SPA Integration
Serve a Vue, React, Svelte, or Angular build alongside your KickJS API. API routes are handled by controllers; all other GET requests fall back to index.html for client-side routing.
Setup
ts
import { bootstrap } from '@forinda/kickjs-http'
import { SpaAdapter } from '@forinda/kickjs-http/spa'
bootstrap({
modules: [...],
adapters: [
new SpaAdapter({
clientDir: 'dist/client',
apiPrefix: '/api',
}),
],
})How It Works
- Static files in
clientDirare served with long-lived cache headers index.htmlis served withno-cache(so deploys are picked up immediately)- API routes (matching
apiPrefix) pass through to your controllers - Everything else serves
index.html— your SPA router handles client-side navigation
Options
| Option | Default | Description |
|---|---|---|
clientDir | 'dist/client' | Directory with the built SPA files |
apiPrefix | '/api' | URL prefix for API routes (string or array) |
exclude | [] | Additional paths to exclude from fallback |
cacheControl | 'public, max-age=31536000, immutable' | Cache header for static assets |
indexCacheControl | 'no-cache' | Cache header for index.html |
Project Structure
my-app/
src/
index.ts ← KickJS server
modules/ ← API modules
client/ ← Frontend source (Vue/React/Svelte)
dist/
client/ ← Frontend build output
index.html
assets/
server/ ← Server build outputFramework Examples
Vue (Vite)
bash
# Build frontend
cd client && npx vite build --outDir ../dist/clientts
new SpaAdapter({ clientDir: 'dist/client' })React (Vite)
bash
cd client && npx vite build --outDir ../dist/clientts
new SpaAdapter({ clientDir: 'dist/client' })Angular
bash
cd client && npx ng build --output-path ../dist/clientts
new SpaAdapter({ clientDir: 'dist/client' })Svelte (SvelteKit static)
bash
cd client && npx vite build --outDir ../dist/clientts
new SpaAdapter({ clientDir: 'dist/client' })Multiple API Prefixes
ts
new SpaAdapter({
clientDir: 'dist/client',
apiPrefix: ['/api', '/graphql', '/_debug'],
exclude: ['/health', '/ws'],
})Disable Asset Caching
ts
new SpaAdapter({
clientDir: 'dist/client',
cacheControl: false, // no cache headers on assets
})