Skip to content

Commit 30ee844

Browse files
authored
updated styles in docs (#26)
* frontend build doc style update * svelte6 migration doc fix
1 parent 01330a8 commit 30ee844

File tree

2 files changed

+85
-663
lines changed

2 files changed

+85
-663
lines changed
Lines changed: 33 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
# Frontend build system
22

3-
This document explains how the frontend codebase is built, what libraries are involved, and how different parts connect at compile time and runtime. It's written for developers who need to modify the build pipeline or understand how the frontend works.
4-
5-
## Overview
6-
7-
The frontend is a Svelte 5 single-page application bundled with Rollup. It uses TypeScript for type safety, Tailwind CSS v4 for styling, and a generated SDK for type-safe API calls. The build outputs static files to `public/build/` which are served by nginx in production or by a custom HTTPS dev server during development.
8-
9-
For details on the Svelte 5 runes API and migration patterns, see [Svelte 5 Migration](svelte5-migration.md).
3+
The frontend is a Svelte 5 single-page application bundled with Rollup. It uses TypeScript for type safety, Tailwind CSS v4 for styling, and a generated SDK for type-safe API calls. The build outputs static files to `public/build/` which are served by nginx in production or by a custom HTTPS dev server during development. For details on the Svelte 5 runes API and migration patterns, see [Svelte 5 Migration](svelte5-migration.md).
104

115
```mermaid
126
graph LR
@@ -44,11 +38,7 @@ graph LR
4438

4539
## Rollup configuration
4640

47-
The `rollup.config.js` file configures the entire build pipeline. It produces ES modules with code splitting, enabling parallel loading of vendor code and application code.
48-
49-
### Entry point
50-
51-
The build starts from `src/main.ts`, which imports the API client setup, mounts the Svelte `App` component using Svelte 5's `mount()` function, and imports global CSS:
41+
The `rollup.config.js` file configures the entire build pipeline, producing ES modules with code splitting for parallel loading of vendor and application code. The build starts from `src/main.ts`, which imports the API client setup, mounts the Svelte `App` component using Svelte 5's `mount()` function, and imports global CSS:
5242

5343
```typescript
5444
import { mount } from 'svelte';
@@ -61,57 +51,20 @@ const app = mount(App, {
6151
});
6252
```
6353

64-
### Code splitting
65-
66-
Rollup splits the bundle into chunks to improve load performance. The `manualChunks` configuration separates large dependencies:
67-
68-
| Chunk | Contents |
69-
|-------|----------|
70-
| `vendor` | Svelte, @mateothegreat/svelte5-router |
71-
| `codemirror` | All CodeMirror packages for the editor |
72-
| Application chunks | Route components and shared code |
73-
74-
This means users don't re-download vendor code when application code changes, and the editor chunk only loads when needed.
75-
76-
### Plugins
77-
78-
The plugin pipeline processes files in order:
54+
Rollup splits the bundle into chunks to improve load performance. The `manualChunks` configuration separates large dependencies into a `vendor` chunk (Svelte, svelte5-router), a `codemirror` chunk (all CodeMirror packages), and application chunks for routes and shared code. This means users don't re-download vendor code when application code changes, and the editor chunk only loads when needed.
7955

80-
1. **replace** — Substitutes `process.env.VITE_BACKEND_URL` with an empty string, allowing relative API paths
81-
2. **svelte** — Compiles `.svelte` files with TypeScript preprocessing via `svelte-preprocess`, with `runes: true` enabled for Svelte 5
82-
3. **postcss** — Processes CSS through PostCSS, extracting styles to `bundle.css`
83-
4. **typescript** — Compiles TypeScript files with source maps
84-
5. **json** — Allows importing JSON files
85-
6. **resolve** — Resolves `node_modules` imports for browser usage, preferring ES modules
86-
7. **commonjs** — Converts CommonJS modules to ES modules
87-
8. **terser** (production only) — Minifies JavaScript, removes console logs, runs two compression passes
56+
The plugin pipeline processes files in order: **replace** substitutes `process.env.VITE_BACKEND_URL` with an empty string for relative API paths; **svelte** compiles `.svelte` files with TypeScript preprocessing and `runes: true` for Svelte 5; **postcss** processes CSS and extracts styles to `bundle.css`; **typescript** compiles TypeScript with source maps; **json** allows importing JSON files; **resolve** handles `node_modules` imports preferring ES modules; **commonjs** converts CommonJS to ES modules; and **terser** (production only) minifies JavaScript, removes console logs, and runs two compression passes.
8857

89-
### Development server
90-
91-
In development mode (`npm run dev`), Rollup watches for changes and a custom HTTPS server starts automatically. The server handles two responsibilities:
92-
93-
1. **Static file serving** — Serves files from `public/`, falling back to `index.html` for SPA routing
94-
2. **API proxying** — Forwards `/api/*` requests to the backend container over HTTPS
95-
96-
The proxy uses a custom `https.Agent` that trusts the local CA certificate at `/shared_ca/mkcert-ca.pem`, allowing secure communication with the backend during development. The server listens on port 5001.
58+
In development mode (`npm run dev`), Rollup watches for changes and a custom HTTPS server starts automatically. The server serves files from `public/` with SPA fallback to `index.html`, and proxies `/api/*` requests to the backend container over HTTPS. The proxy uses a custom `https.Agent` that trusts the local CA certificate at `/shared_ca/mkcert-ca.pem`, allowing secure communication with the backend during development on port 5001.
9759

9860
## TypeScript configuration
9961

100-
The `tsconfig.json` configures TypeScript compilation:
101-
102-
- Target: ES2020 with ESNext modules
103-
- Strict mode enabled
104-
- Module resolution set to bundler mode for Rollup compatibility
105-
- Svelte component types enabled via `svelte-preprocess`
106-
107-
TypeScript catches type errors during development and the build fails if any exist, preventing broken code from reaching production.
62+
The `tsconfig.json` targets ES2020 with ESNext modules, enables strict mode, sets module resolution to bundler mode for Rollup compatibility, and enables Svelte component types via `svelte-preprocess`. TypeScript catches type errors during development and the build fails if any exist, preventing broken code from reaching production.
10863

10964
## API SDK generation
11065

11166
The frontend uses a generated SDK for type-safe API calls instead of manual fetch requests. This SDK is created from the backend's OpenAPI specification using `@hey-api/openapi-ts`.
11267

113-
### Generation pipeline
114-
11568
```mermaid
11669
graph LR
11770
OpenAPI["docs/reference/openapi.json"] --> Generator["@hey-api/openapi-ts"]
@@ -120,30 +73,12 @@ graph LR
12073
Generator --> Client["client.gen.ts"]
12174
```
12275

123-
Run `npm run generate:api` to regenerate the SDK. The configuration in `openapi-ts.config.ts` specifies:
124-
125-
- Input: `../docs/reference/openapi.json` (the backend's OpenAPI spec)
126-
- Output: `src/lib/api/` with Prettier formatting
127-
- Plugins: TypeScript types, SDK functions, and fetch client
128-
129-
### Generated files
130-
131-
| File | Purpose |
132-
|------|---------|
133-
| `types.gen.ts` | TypeScript interfaces for all request/response models |
134-
| `sdk.gen.ts` | Function for each API endpoint, fully typed |
135-
| `client.gen.ts` | HTTP client with interceptor support |
136-
| `index.ts` | Re-exports types and SDK functions |
137-
| `setup.ts` | Manual file that configures the client (not generated) |
138-
139-
### Client configuration
140-
141-
The `setup.ts` file configures the generated client:
76+
Run `npm run generate:api` to regenerate the SDK. The configuration in `openapi-ts.config.ts` specifies the input as `../docs/reference/openapi.json`, outputs to `src/lib/api/` with Prettier formatting, and generates TypeScript types, SDK functions, and a fetch client. The generated files include `types.gen.ts` (TypeScript interfaces for all request/response models), `sdk.gen.ts` (functions for each API endpoint, fully typed), `client.gen.ts` (HTTP client with interceptor support), and `index.ts` (re-exports for convenient imports). There's also a manual `setup.ts` file that configures the client with relative URLs and cookie credentials, and adds an interceptor that automatically attaches CSRF tokens to mutating requests:
14277

14378
```typescript
14479
client.setConfig({
145-
baseUrl: '', // Relative URLs, proxied in dev
146-
credentials: 'include', // Send cookies for auth
80+
baseUrl: '',
81+
credentials: 'include',
14782
});
14883

14984
client.interceptors.request.use((request) => {
@@ -155,121 +90,50 @@ client.interceptors.request.use((request) => {
15590
});
15691
```
15792

158-
The interceptor automatically adds CSRF tokens to mutating requests, pulling the token from the auth store. This happens transparently for all SDK calls.
159-
160-
### Usage pattern
161-
162-
Components import SDK functions and types directly:
93+
Components import SDK functions and types directly. The SDK returns `{ data, error }` tuples, making error handling explicit without try/catch boilerplate:
16394

16495
```typescript
165-
import {
166-
getNotificationsApiV1NotificationsGet,
167-
type NotificationResponse,
168-
} from '../lib/api';
96+
import { getNotificationsApiV1NotificationsGet, type NotificationResponse } from '../lib/api';
16997

170-
const { data, error } = await getNotificationsApiV1NotificationsGet({
171-
query: { limit: 20 }
172-
});
98+
const { data, error } = await getNotificationsApiV1NotificationsGet({ query: { limit: 20 } });
17399
```
174100

175-
The SDK returns `{ data, error }` tuples, making error handling explicit without try/catch boilerplate.
176-
177101
## Tailwind CSS v4
178102

179-
The frontend uses Tailwind CSS v4 with the new CSS-first configuration. Unlike v3, there's no `tailwind.config.js` — all configuration lives in CSS.
180-
181-
### PostCSS integration
182-
183-
PostCSS processes CSS through `@tailwindcss/postcss`:
184-
185-
```javascript
186-
// postcss.config.cjs
187-
module.exports = {
188-
plugins: {
189-
"@tailwindcss/postcss": {},
190-
},
191-
}
192-
```
193-
194-
### CSS configuration
195-
196-
The `src/app.css` file contains all Tailwind configuration using v4's new at-rules:
103+
The frontend uses Tailwind CSS v4 with the new CSS-first configuration. Unlike v3, there's no `tailwind.config.js` — all configuration lives in CSS. PostCSS processes CSS through `@tailwindcss/postcss`, and the `src/app.css` file contains all Tailwind configuration using v4's new at-rules:
197104

198105
```css
199-
/* Import Tailwind */
200106
@import "tailwindcss";
201107

202-
/* Forms plugin */
203-
@plugin "@tailwindcss/forms" {
204-
strategy: class;
205-
}
206-
207-
/* Class-based dark mode */
108+
@plugin "@tailwindcss/forms" { strategy: class; }
208109
@variant dark (&:where(.dark, .dark *));
209110

210-
/* Custom theme tokens */
211111
@theme {
212112
--color-primary: #3b82f6;
213113
--color-bg-default: #f8fafc;
214114
--font-sans: 'Inter', ui-sans-serif, system-ui;
215-
/* ... */
216115
}
217116

218-
/* Custom utilities */
219117
@utility animate-fadeIn {
220-
animation: fadeIn 0.3s ease-in-out;
118+
animation: var(--animate-fadeIn);
221119
}
222120
```
223121

224-
### Theme structure
225-
226-
The theme defines semantic color tokens for both light and dark modes:
227-
228-
| Token | Light | Dark |
229-
|-------|-------|------|
230-
| `bg-default` | `#f8fafc` | `#0f172a` |
231-
| `fg-default` | `#1e293b` | `#e2e8f0` |
232-
| `border-default` | `#e2e8f0` | `#334155` |
233-
234-
Components use these tokens (e.g., `bg-bg-default dark:bg-dark-bg-default`) for consistent theming. The `@variant dark` rule enables the `.dark` class on `<html>` to trigger dark mode.
122+
The theme defines semantic color tokens for both light and dark modes (`bg-default`, `fg-default`, `border-default`, etc.) which components use for consistent theming. The `@variant dark` rule enables the `.dark` class on `<html>` to trigger dark mode. Styles are organized into Tailwind layers: **base** for element defaults, form styles, scrollbars, and CodeMirror overrides; **components** for reusable patterns like `.btn`, `.card`, and `.form-input-standard`.
235123

236-
### Layer organization
124+
## Svelte stores and state
237125

238-
Styles are organized into Tailwind layers:
126+
The frontend uses a hybrid approach to state management. Svelte stores in `src/stores/` handle global, shared state: `auth.ts` manages authentication state, login/logout, and CSRF tokens; `theme.ts` handles theme preference with localStorage persistence; `toastStore.ts` manages the toast notification queue; and `notificationStore.ts` handles server notifications with pagination. Stores use the generated SDK for API calls and persist state to localStorage where appropriate. The auth store exposes a `csrfToken` store that the API client interceptor reads for request signing.
239127

240-
- **base** — Element defaults, form styles, scrollbars, CodeMirror overrides
241-
- **components** — Reusable patterns like `.btn`, `.card`, `.form-input-standard`
242-
243-
## Svelte stores and runes
244-
245-
The frontend uses a hybrid approach to state management:
246-
247-
**Svelte stores** (`src/stores/`) handle global, shared state:
248-
249-
| Store | Purpose |
250-
|-------|---------|
251-
| `auth.ts` | Authentication state, login/logout, CSRF token |
252-
| `theme.ts` | Theme preference (light/dark/auto) with localStorage persistence |
253-
| `toastStore.ts` | Toast notifications queue |
254-
| `notificationStore.ts` | Server notifications with pagination |
255-
256-
Stores use the generated SDK for API calls and persist state to localStorage where appropriate. The auth store exposes a `csrfToken` store that the API client interceptor reads for request signing.
257-
258-
**Svelte 5 runes** (`$state`, `$derived`, `$effect`) handle component-local state:
128+
Svelte 5 runes (`$state`, `$derived`, `$effect`) handle component-local state. Store subscriptions remain unchanged from Svelte 4 — the `$storeName` syntax auto-subscribes to any store:
259129

260130
```svelte
261131
<script lang="ts">
262132
import { isAuthenticated } from '../stores/auth';
263133

264-
// Component-local reactive state
265134
let loading = $state(false);
266135
let items = $state<Item[]>([]);
267-
268-
// Derived values
269136
let itemCount = $derived(items.length);
270-
271-
// Store subscription (unchanged from Svelte 4)
272-
// $isAuthenticated auto-subscribes to the store
273137
</script>
274138

275139
{#if $isAuthenticated}
@@ -279,14 +143,6 @@ Stores use the generated SDK for API calls and persist state to localStorage whe
279143

280144
For detailed patterns and migration guidance, see [Svelte 5 Migration](svelte5-migration.md).
281145

282-
## Build commands
283-
284-
| Command | Purpose |
285-
|---------|---------|
286-
| `npm run dev` | Start Rollup in watch mode with HTTPS dev server |
287-
| `npm run build` | Production build with minification |
288-
| `npm run generate:api` | Regenerate SDK from OpenAPI spec |
289-
290146
## File structure
291147

292148
```
@@ -313,64 +169,30 @@ frontend/
313169
└── openapi-ts.config.ts # SDK generator config
314170
```
315171

316-
## Local development
317-
318-
Start the development stack:
319-
320-
```bash
321-
# From project root
322-
docker compose up -d
323-
324-
# In frontend directory
325-
npm install
326-
npm run dev
327-
```
328-
329-
The dev server runs at `https://localhost:5001`. API requests proxy to the backend container. Changes to `.svelte`, `.ts`, and `.css` files trigger automatic rebuilds.
330-
331-
### Regenerating the API client
172+
## Build commands
332173

333-
When backend endpoints change:
174+
| Command | Purpose |
175+
|---------|---------|
176+
| `npm run dev` | Start Rollup in watch mode with HTTPS dev server |
177+
| `npm run build` | Production build with minification |
178+
| `npm run generate:api` | Regenerate SDK from OpenAPI spec |
334179

335-
1. Update the backend and restart it
336-
2. Fetch the new OpenAPI spec (the docs workflow does this automatically)
337-
3. Run `npm run generate:api`
338-
4. Fix any TypeScript errors from changed types
180+
## Local development
339181

340-
### Adding new routes
182+
Start the development stack from the project root with `docker compose up -d`, then in the frontend directory run `npm install && npm run dev`. The dev server runs at `https://localhost:5001` with API requests proxying to the backend container. Changes to `.svelte`, `.ts`, and `.css` files trigger automatic rebuilds.
341183

342-
1. Create a component in `src/routes/`
343-
2. Add a `<Route>` entry in `App.svelte`
344-
3. Use SDK functions for API calls
345-
4. Use semantic color tokens for styling
184+
When backend endpoints change, update the backend and restart it, fetch the new OpenAPI spec (the docs workflow does this automatically), run `npm run generate:api`, and fix any TypeScript errors from changed types. To add new routes, create a component in `src/routes/`, add a `<Route>` entry in `App.svelte`, use SDK functions for API calls, and use semantic color tokens for styling.
346185

347186
## Production build
348187

349-
The production build runs `npm run build`, which:
350-
351-
1. Compiles TypeScript with source maps
352-
2. Processes Svelte components in production mode (no dev warnings)
353-
3. Extracts and minifies CSS
354-
4. Splits code into chunks
355-
5. Minifies JavaScript with Terser (removes console.log)
356-
6. Outputs to `public/build/`
357-
358-
The Docker build copies `public/` to nginx, which serves static files and proxies `/api/` to the backend.
188+
The production build runs `npm run build`, which compiles TypeScript with source maps, processes Svelte components in production mode without dev warnings, extracts and minifies CSS, splits code into chunks, minifies JavaScript with Terser removing console.log calls, and outputs everything to `public/build/`. The Docker build copies `public/` to nginx, which serves static files and proxies `/api/` to the backend.
359189

360190
## Troubleshooting
361191

362-
### TypeScript errors after SDK regeneration
363-
364-
If the backend changed response types, update components to match. The SDK provides exact types — check `types.gen.ts` for the new structure.
365-
366-
### Styles not applying
367-
368-
Ensure the class exists in Tailwind's default utilities or is defined in `app.css`. Check for typos in semantic token names (e.g., `bg-default` vs `bg-bg-default`).
369-
370-
### Dev server certificate errors
192+
If you see TypeScript errors after SDK regeneration, check `types.gen.ts` for the new structure and update components to match the changed response types.
371193

372-
The dev server requires certificates at `./certs/server.key` and `./certs/server.crt`, and the CA at `/shared_ca/mkcert-ca.pem`. Run the cert-generator container first via Docker Compose.
194+
For styles not applying, ensure the class exists in Tailwind's default utilities or is defined in `app.css`, and check for typos in semantic token names (e.g., `bg-default` vs `bg-bg-default`).
373195

374-
### API calls failing in development
196+
Dev server certificate errors mean the certificates at `./certs/server.key` and `./certs/server.crt` are missing, or the CA at `/shared_ca/mkcert-ca.pem` isn't available — run the cert-generator container first via Docker Compose.
375197

376-
Verify the backend is running and healthy. The dev server proxies to `https://backend:443` check Docker networking if the container can't resolve the hostname.
198+
If API calls fail in development, verify the backend is running and healthy; the dev server proxies to `https://backend:443`, so check Docker networking if the container can't resolve the hostname.

0 commit comments

Comments
 (0)