Build and styling¶
Build system¶
The Website builds in two parts: Vite (with the Vike plugin) produces the SSR bundle and hashed client assets, and esbuild produces the Worker bundle.
The build pipeline¶
npm run build runs these steps in order:
NODE_ENV=production tsx scripts/build-static.ts \
&& tsc -b \
&& NODE_ENV=production vike build \
&& tsx scripts/patch-server-entry.ts \
&& tsx scripts/copy-static.ts \
&& tsx scripts/build-worker.ts
| Step | Script | What it does |
|---|---|---|
| 1 | build-static.ts |
Generates static inputs; loads .env if present |
| 2 | tsc -b |
TypeScript project build |
| 3 | vike build |
Builds the Vike SSR bundle + hashed client assets |
| 4 | patch-server-entry.ts |
Patches the generated Vike server entry |
| 5 | copy-static.ts |
Copies static files into dist |
| 6 | build-worker.ts |
Bundles src/worker.ts → dist/worker.js (esbuild) |
The output is dist/client/ (assets served via the ASSETS binding) and
dist/worker.js (the Worker, main in wrangler.toml).
Vite configuration¶
Key options in vite.config.ts:
- JSX runtime — always the production automatic runtime (
jsxDev: false) to avoid dev-runtime issues in the Workers environment. define— bakes__BASE_URL__,__API_URL__,__GTM_ID__,__GTAG_ID__,__NODE_ENV__,__SUBSCRIPTIONS_API_URL__,__RECAPTCHA_SITE_KEY__,__CHAT_API_KEY__,__SENTRY_DSN__into the bundle (see Environment setup).manualChunks— React + scheduler go toreact-vendor, othernode_modulestovendor; chunk filenames are content-hashed (assets/js/[name]-[hash].js).cssCodeSplit: trueand CSS Modules with camelCase locals and scoped class names.assetsInlineLimit: 8192and source maps only outside production..dev.varsis loaded intoprocess.envwhen present, so local builds bake in local-only build-time secrets.
esbuild Worker bundle¶
scripts/build-worker.ts bundles the Worker:
await build({
entryPoints: ["src/worker.ts"],
bundle: true,
outfile: "dist/worker.js",
format: "esm",
target: "es2022",
platform: "neutral",
conditions: ["worker", "browser"],
minify: true,
define: { "process.env.NODE_ENV": '"production"' },
external: ["mermaid", "lodash-es", "dagre-d3-es", /* … */],
});
It also copies Vike's generated server entry (dist/server/entry.mjs) to
dist/server-entry.js.
Dev and watch scripts¶
| Command | Script | Purpose |
|---|---|---|
npm run dev |
wrangler dev --env dev |
Dev server on port 3000 |
npm run watch |
scripts/watch.ts |
Rebuild on change (no server) |
npm run watch:dev |
scripts/watch-dev.ts |
Rebuild + dev server + browser reload |
npm run build:worker |
scripts/build-worker.ts |
Rebuild only the Worker |
npm run optimize:images |
scripts/optimize-images.mjs |
Convert PNG/JPG to WebP (Sharp) |
Styling¶
The project uses SCSS with the BEM (Block-Element-Modifier) naming convention. There is no utility-CSS framework; styling is hand-authored SCSS plus a small set of inlined critical styles.
BEM¶
.header { } // Block
.header__logo { } // Element
.header--sticky { } // Modifier
File organization (src/styles/)¶
| Directory / file | Purpose |
|---|---|
abstracts/ |
Variables, mixins, functions (_variables.scss, _mixins.scss, _functions.scss) |
base/ |
Base HTML element styles |
components/ |
Component-specific styles (one file per component) |
layout/ |
Layout-level styles |
pages/ |
Page-specific styles (page-name.page.scss) |
global.scss |
Global styles and imports |
main.scss |
Main SCSS entry point |
Conventions¶
- Import styles via the
@/styles/alias. - Use variables from
abstracts/for colors, spacing, and breakpoints — no magic values. - Component styles live in
styles/components/matching the component name; page styles instyles/pages/using thepage-name.page.scsspattern. - No inline styles — use BEM SCSS classes. The one deliberate exception is the
critical CSS inlined into the SSR
<head>(pages/+onRenderHtml.tsx) to avoid FOUC for above-the-fold header/nav/container. - SCSS is compiled with
sass; Vite'sadditionalDataprepends@charset "UTF-8";.
Note
The platform's shared swapps-design system informs the visual language
(typography, colors, components). The internal reference lives in the
pages/style-guide/ route, which documents typography, colors, logo, icons,
illustrations, and component patterns.
Quality gates¶
| Command | Purpose |
|---|---|
npm run lint / lint:fix |
ESLint (flat config) |
npm run format / format:check |
Prettier |
npm run type-check |
tsc --noEmit |
npm run test |
Vitest |
lint-staged runs ESLint + Prettier on staged files via a Husky pre-commit hook;
CI re-runs lint, format check, type check, build, and route tests (see
Deployment).