Full stack swap to enable future extension (more pages / load functions /
backend) while keeping JSDoc-only code style.
Stack:
- SvelteKit 2 + adapter-static
- Svelte 5 runes ($state, $derived, $effect, $props)
- Vite 7 + @sveltejs/vite-plugin-svelte 6
- Tailwind 4 (Vite plugin)
- ESLint 9 (flat) + eslint-plugin-svelte
- Pure JS + JSDoc, no TypeScript
Source moves:
- app/page.jsx → src/routes/+page.svelte
- app/master/page.jsx → src/routes/master/+page.svelte
- app/layout.jsx → src/routes/+layout.svelte (+ +layout.js)
- components/player-board.jsx → src/lib/PlayerBoard.svelte
- lib/game-logic.js → src/lib/game-logic.js (verbatim)
- next.config.mjs → svelte.config.js + vite.config.js
- app/globals.css → src/app.css
- (new) → src/app.html
Behavior preserved: PlayerBoard with bingo "Kinh!" popup + waiting "Chờ X"
toast, master 9x10 tracking board with shuffled draw, host's own player
card via storagePrefix="loto_master_card", localStorage prefix model
(loto_*, loto_master, loto_master_card_*), basePath dual mode (CF default
empty, BUILD_PROFILE=gh → /loto, codeserver dev → /absproxy/{port}).
A11y kept from prior hardening: role-correct buttons, aria-pressed on
cells, role=dialog modal with Escape, role=status toast.
Plans: ts-to-jsdoc plan marked completed; sveltekit-refactor plan tracks
the work above. Docs under ./docs/ rewritten by docs-manager subagent to
match the SvelteKit terminology.
5.1 KiB
Deployment Guide
Build Profiles
| Script | basePath | Target |
|---|---|---|
npm run build |
"" (root) |
Cloudflare Pages → https://loto.miti99.com |
npm run build:gh |
/loto |
GitHub Pages → https://tiennm99.github.io/loto (manual fallback) |
Implementation: svelte.config.js reads BUILD_PROFILE env. Default is empty
basePath; BUILD_PROFILE=gh npm run build switches to /loto.
Internal links use import { base } from '$app/paths' so they survive
either profile without code changes.
Production Deployment — Cloudflare Pages
Primary deploy. Set up via the Cloudflare dashboard once; subsequent
pushes to master trigger automatic builds + deploys.
- dash.cloudflare.com → Workers & Pages → Create → Pages → Connect to Git → pick the repo
- Build settings:
- Framework preset: SvelteKit
- Build command:
npm run build - Build output directory:
build - Production branch:
master
- After first deploy, add the custom domain:
Project → Custom domains →
loto.miti99.com. Cloudflare gives DNS records to add at your registrar (or auto-configures ifmiti99.comis on Cloudflare DNS).
No GitHub Actions involved; no repo secrets needed.
Manual GH Pages Deploy (optional)
If you ever want to push a build to GitHub Pages by hand:
npm run build:gh
# upload build/ to the GH Pages target
The repo no longer auto-deploys to GH Pages — there's no GitHub Actions workflow. CF Pages is the only auto-deploy target.
Development Environment
Local Dev
npm install
npm run dev
Access at http://localhost:3000 (no basePath).
HMR works automatically.
Code-Server Dev
For browser-based development (VS Code in browser):
1. Start code-server with Node.js environment:
code-server --no-auth
2. Create .env.local in project root:
VITE_DEV_PROFILE=codeserver
CODESERVER_HOST=your-machine.example.com
CODESERVER_PORT=3000
Replace your-machine.example.com with your actual hostname/IP (must match the proxy URL you'll access).
3. Run dev server:
npm run dev:codeserver
This reads vite.config.js codeserver config (basePath /absproxy/{PORT}, HMR proxy).
4. Access via browser: Navigate to:
https://your-codeserver-host/absproxy/3000/
Key Points:
/absproxy/{port}(NOT/proxy/{port}) preserves basePath through the proxy.- HMR socket connects to
CODESERVER_HOSTfor live reload. - If HMR fails, manually refresh the page (Vite HMR still compiles server-side).
Manual Refresh Workaround
If HMR over proxy is unreliable:
- Make code changes
- Manually refresh browser (F5)
- Dev server has already compiled the changes
This is normal in proxy environments.
Build & Output
Build Command
npm run build
Generates:
build/— Complete static HTML + JS export.svelte-kit/— Build cache (not needed for deployment)
Export Settings
adapter-staticinsvelte.config.js- No server-side rendering (SSR disabled via
ssr: false) - All pages pre-rendered to HTML + JS bundles
Asset Hosting
basepath matches deployment target (prod:"", GH:/loto, codeserver:/absproxy/{port})- CSS, JS, fonts all prefixed correctly
- GitHub Pages serves from repository root, so
/lotopaths resolve correctly
Environment Variables
Development (code-server only)
VITE_DEV_PROFILE— set to "codeserver" to enable proxy modeCODESERVER_HOST— hostname for HMR proxyCODESERVER_PORT— port (default 3000)
Build-Time
BUILD_PROFILE— set to "gh" for GitHub Pages build (basePath/loto). Default empty (Cloudflare).
Not Used at Runtime
- No database URL, API keys, or secrets (all client-side, localStorage)
.env.localis.gitignored and safe for local config
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| 404 on subpages after deploy | basePath mismatch | Verify BUILD_PROFILE=gh for GitHub Pages; default for Cloudflare |
| HMR not connecting (code-server) | CODESERVER_HOST not set | Add CODESERVER_HOST=... to .env.local |
| Assets 404 (code-server) | Wrong proxy URL | Use /absproxy/{port}, not /proxy/{port} |
| Page blank after refresh | State not persisted | Check browser localStorage is enabled |
| Stale CSS (code-server) | HMR failed | Manually refresh page (F5) |
CI/CD Pipeline
Cloudflare Pages handles CI/CD automatically:
- GitHub Pages deployment removed (Cloudflare is primary).
- Manual fallback:
npm run build:gh && git push(if needed). - No GitHub Actions workflow for automatic GH Pages deploy.
Performance Checklist
- Static export via adapter-static (no server overhead)
- Tailwind 4 purged for production size
- localStorage reduces bundle—no API calls
- Images minimal (mostly CSS gradients + emojis)
- Fonts: Geist via Google Fonts CDN
Bundle analysis: Run npm run build && ls -lh build/ to inspect file sizes.
Security Considerations
- No sensitive data in code (no API keys, secrets)
.env.localis local-only, not committed- localStorage scoped to origin
- No external API calls (offline-capable)
- GitHub Pages HTTPS by default
Last reviewed: 2026-04-26