6.2 KiB
6.2 KiB
Build Instructions
Development
Setup
# Install dependencies
pnpm install
# Copy environment file
cp .env.example .env
# Edit .env as needed
# For local development with parent backend:
# PUBLIC_API_URL=http://localhost:3000
# PUBLIC_SEASON=s1
# PUBLIC_ENABLE_TURNSTILE=false
Run Dev Server
pnpm dev
App runs on http://localhost:5173
Note: Dev server proxies /api/* to http://localhost:3000 (see vite.config.ts)
Production Build
Build for Parent Backend
The build is configured to output directly to the parent backend's frontend/ folder:
pnpm build
Output location: ../frontend/ (replaces existing compiled frontend)
What Gets Built
../frontend/
├── _app/ # SvelteKit app chunks
│ ├── immutable/
│ │ ├── assets/ # CSS files
│ │ ├── chunks/ # JS chunks
│ │ ├── nodes/ # Route components
│ │ └── entry/ # App entry points
│ └── version.json
├── index.html # Main page
├── 404.html # 404 fallback
├── admin/
│ └── index.html
├── moderation/
│ └── index.html
├── join/
│ └── index.html
└── ... (other static files)
Backend Integration
The parent backend (in ../src/index.ts) serves the built frontend:
// Serve frontend static files
app.use('/', sirv('./frontend', {
maxAge: 31536000, // 1 year for immutable files
immutable: true
}));
// SPA fallback - serve 404.html for unmatched routes
app.use((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.sendFile(path.join(__dirname, '../frontend/404.html'));
});
All API routes (/me, /auth/*, /alliance/*, etc.) are handled by the backend first, then unmatched routes serve the frontend.
Environment Variables
Build Time (PUBLIC_*)
These are embedded into the built JavaScript:
PUBLIC_API_URL- API base URL (default:''= same origin)PUBLIC_SEASON- Current season (default:'s1')PUBLIC_ENABLE_TURNSTILE- Enable Cloudflare Turnstile (default:'false')PUBLIC_TURNSTILE_SITE_KEY- Turnstile site key
Development vs Production
Development (.env):
PUBLIC_API_URL=http://localhost:3000
PUBLIC_SEASON=s1
PUBLIC_ENABLE_TURNSTILE=false
Production (backend serves frontend from same origin):
PUBLIC_API_URL=
PUBLIC_SEASON=s1
PUBLIC_ENABLE_TURNSTILE=true
PUBLIC_TURNSTILE_SITE_KEY=0x4AAAAAABpqJe8FO0N84q0F
Turnstile Configuration
Disable Turnstile (Development)
PUBLIC_ENABLE_TURNSTILE=false
- No Turnstile widget rendered
- Login buttons work immediately
- OAuth URLs don't include
tokenparameter - Backend should handle auth without Turnstile
Enable Turnstile (Production)
PUBLIC_ENABLE_TURNSTILE=true
PUBLIC_TURNSTILE_SITE_KEY=your_site_key_here
- Turnstile widget loads on login page
- Login buttons disabled until captcha completes
- OAuth URLs include
?token=...parameter - Backend validates Turnstile token
Build Process
Clean Build
# Remove old build
rm -rf ../frontend/_app ../frontend/index.html
# Fresh build
pnpm build
Verify Build
After building, check the parent backend:
cd ..
pnpm start
# Open browser to http://localhost:3000
# Should see the new frontend
Backend Requirements
The parent backend must:
- Serve static files from
./frontenddirectory - Handle API routes first (before static file serving)
- Serve 404.html for SPA fallback on unmatched routes
- Set appropriate headers (CORS, CSP, etc.)
Example setup in ../src/index.ts:
import sirv from 'sirv';
import path from 'path';
// API routes first
app.get('/me', authMiddleware, ...);
app.post('/auth/logout', ...);
// ... all other API routes
// Serve frontend static files
app.use('/', sirv('./frontend', {
maxAge: 31536000,
immutable: true
}));
// SPA fallback
app.use((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.sendFile(path.join(__dirname, '../frontend/404.html'));
});
Troubleshooting
Build fails with "Cannot find module"
rm -rf node_modules
pnpm install
Changes not appearing
# Clear browser cache
# Or use incognito mode
API calls return 404
- Check
PUBLIC_API_URLin.env - For production, set to empty string (same origin)
- Backend API routes must be registered before static file serving
Turnstile not working
- Check
PUBLIC_ENABLE_TURNSTILEis'true'(string, not boolean) - Verify
PUBLIC_TURNSTILE_SITE_KEYis correct - Check browser console for errors
CI/CD Integration
Example GitHub Actions
name: Build Frontend
on:
push:
branches: [main]
paths:
- 'frontend-src/**'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 10
- uses: actions/setup-node@v3
with:
node-version: 24
cache: 'pnpm'
cache-dependency-path: frontend-src/pnpm-lock.yaml
- name: Install dependencies
run: cd frontend-src && pnpm install
- name: Build
run: cd frontend-src && pnpm build
env:
PUBLIC_API_URL: ''
PUBLIC_SEASON: 's1'
PUBLIC_ENABLE_TURNSTILE: 'true'
PUBLIC_TURNSTILE_SITE_KEY: ${{ secrets.TURNSTILE_SITE_KEY }}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: frontend-build
path: frontend/
File Structure Reference
FurryPlace/
├── frontend/ # ← Build output (served by backend)
│ ├── _app/
│ ├── index.html
│ └── ...
├── frontend-src/ # ← Source code (this directory)
│ ├── src/
│ ├── static/
│ ├── package.json
│ ├── svelte.config.js # Output to ../frontend
│ └── BUILD.md # This file
└── src/ # Backend source
└── index.ts # Serves ./frontend