Cleanup: Remove old modes, add Svelte 5 reference library, update orchestrator
- Delete Mode1Test, Mode2Test, Mode3Test, Mode5Test (keep only Mode6Test) - Delete old documentation, Docker files, and k8s configs - Add comprehensive Svelte 5 reference library (svelte-reference/) - Update ModeSwitch orchestrator: - Fix port to 3005 (never use 3000/3001) - Add API endpoints for mode switching - Add bun-types and proper tsconfig - Clean up mode folder mappings
This commit is contained in:
@@ -0,0 +1,656 @@
|
||||
# SvelteKit Deployment Guide
|
||||
|
||||
## Overview
|
||||
|
||||
SvelteKit supports multiple deployment targets through adapters. Choose the right adapter for your infrastructure and requirements.
|
||||
|
||||
---
|
||||
|
||||
## 🔌 Available Adapters
|
||||
|
||||
### Adapter Comparison
|
||||
|
||||
| Adapter | Platform | SSR | SSG | Edge | Serverless |
|
||||
|---------|----------|-----|-----|------|------------|
|
||||
| `adapter-node` | Node.js | ✅ | ✅ | ❌ | ❌ |
|
||||
| `adapter-auto` | Auto-detect | ✅ | ✅ | Varies | Varies |
|
||||
| `adapter-vercel` | Vercel | ✅ | ✅ | ✅ | ✅ |
|
||||
| `adapter-netlify` | Netlify | ✅ | ✅ | ✅ | ✅ |
|
||||
| `adapter-cloudflare` | Cloudflare | ✅ | ✅ | ✅ | ✅ |
|
||||
| `adapter-static` | Static hosts | ❌ | ✅ | ❌ | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Node.js Deployment (adapter-node)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
npm install -D @sveltejs/adapter-node
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```javascript
|
||||
// svelte.config.js
|
||||
import adapter from '@sveltejs/adapter-node';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
preprocess: vitePreprocess(),
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
// Output directory
|
||||
out: 'build',
|
||||
|
||||
// Precompress static assets with gzip/brotli
|
||||
precompress: true,
|
||||
|
||||
// Environment variable configuration
|
||||
envPrefix: 'APP_'
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
### Build & Run
|
||||
|
||||
```bash
|
||||
# Build
|
||||
npm run build
|
||||
|
||||
# Run with Node
|
||||
node build/index.js
|
||||
|
||||
# Or with environment variables
|
||||
PORT=3000 HOST=0.0.0.0 node build/index.js
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Server configuration
|
||||
PORT=3000 # Default: 3000
|
||||
HOST=0.0.0.0 # Default: 0.0.0.0
|
||||
ORIGIN=https://example.com # Required for form actions
|
||||
BODY_SIZE_LIMIT=512K # Request body limit
|
||||
```
|
||||
|
||||
### Production Process Manager (PM2)
|
||||
|
||||
```javascript
|
||||
// ecosystem.config.cjs
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: 'sveltekit-app',
|
||||
script: './build/index.js',
|
||||
instances: 'max',
|
||||
exec_mode: 'cluster',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 3000,
|
||||
ORIGIN: 'https://example.com'
|
||||
},
|
||||
error_file: './logs/error.log',
|
||||
out_file: './logs/output.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
|
||||
}]
|
||||
};
|
||||
```
|
||||
|
||||
```bash
|
||||
# Start with PM2
|
||||
pm2 start ecosystem.config.cjs
|
||||
|
||||
# Save process list
|
||||
pm2 save
|
||||
|
||||
# Setup startup script
|
||||
pm2 startup
|
||||
```
|
||||
|
||||
### Systemd Service
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/sveltekit-app.service
|
||||
[Unit]
|
||||
Description=SvelteKit Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
WorkingDirectory=/var/www/app
|
||||
ExecStart=/usr/bin/node build/index.js
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=3000
|
||||
Environment=ORIGIN=https://example.com
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl enable sveltekit-app
|
||||
sudo systemctl start sveltekit-app
|
||||
```
|
||||
|
||||
### Nginx Reverse Proxy
|
||||
|
||||
```nginx
|
||||
# /etc/nginx/sites-available/sveltekit-app
|
||||
upstream sveltekit {
|
||||
server 127.0.0.1:3000;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
# Redirect to HTTPS
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name example.com;
|
||||
|
||||
# SSL certificates
|
||||
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
|
||||
|
||||
# SSL settings
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Gzip
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript;
|
||||
|
||||
# Static files with immutable cache
|
||||
location /_app/immutable {
|
||||
proxy_pass http://sveltekit;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
}
|
||||
|
||||
# Other static files
|
||||
location /static {
|
||||
proxy_pass http://sveltekit;
|
||||
add_header Cache-Control "public, max-age=86400";
|
||||
}
|
||||
|
||||
# Proxy to SvelteKit
|
||||
location / {
|
||||
proxy_pass http://sveltekit;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Docker Deployment
|
||||
|
||||
### Dockerfile
|
||||
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Build application
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/build ./build
|
||||
COPY --from=builder /app/package*.json ./
|
||||
|
||||
# Install production dependencies only
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
# Set environment
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
|
||||
|
||||
# Run
|
||||
CMD ["node", "build/index.js"]
|
||||
```
|
||||
|
||||
### docker-compose.yml
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- ORIGIN=https://example.com
|
||||
- DATABASE_URL=postgresql://user:pass@db:5432/app
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "http://localhost:3000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: user
|
||||
POSTGRES_PASSWORD: pass
|
||||
POSTGRES_DB: app
|
||||
restart: unless-stopped
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
restart: unless-stopped
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
depends_on:
|
||||
- app
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Static Site Generation (adapter-static)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
npm install -D @sveltejs/adapter-static
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```javascript
|
||||
// svelte.config.js
|
||||
import adapter from '@sveltejs/adapter-static';
|
||||
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
pages: 'build',
|
||||
assets: 'build',
|
||||
fallback: '404.html', // or 'index.html' for SPA
|
||||
precompress: true,
|
||||
strict: true
|
||||
}),
|
||||
prerender: {
|
||||
entries: ['*'], // Prerender all pages
|
||||
handleHttpError: 'warn'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
### Page Configuration for SSG
|
||||
|
||||
```typescript
|
||||
// src/routes/+layout.ts
|
||||
export const prerender = true; // Prerender all pages
|
||||
export const ssr = true; // Enable SSR during build
|
||||
|
||||
// src/routes/+page.ts
|
||||
export const prerender = true; // Prerender this specific page
|
||||
|
||||
// For dynamic routes, export entries
|
||||
export function entries() {
|
||||
return [
|
||||
{ slug: 'post-1' },
|
||||
{ slug: 'post-2' },
|
||||
{ slug: 'post-3' }
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### Deploy to GitHub Pages
|
||||
|
||||
```yaml
|
||||
# .github/workflows/deploy.yml
|
||||
name: Deploy to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
env:
|
||||
BASE_PATH: '/${{ github.event.repository.name }}'
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ☁️ Vercel Deployment
|
||||
|
||||
### Configuration
|
||||
|
||||
```javascript
|
||||
// svelte.config.js
|
||||
import adapter from '@sveltejs/adapter-vercel';
|
||||
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
runtime: 'nodejs20.x', // or 'edge'
|
||||
regions: ['iad1'], // Deploy regions
|
||||
split: true // Split into multiple functions
|
||||
})
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Per-Route Configuration
|
||||
|
||||
```typescript
|
||||
// src/routes/api/slow-endpoint/+server.ts
|
||||
export const config = {
|
||||
runtime: 'nodejs20.x',
|
||||
maxDuration: 30 // Extend timeout
|
||||
};
|
||||
|
||||
// src/routes/api/fast-endpoint/+server.ts
|
||||
export const config = {
|
||||
runtime: 'edge',
|
||||
regions: ['iad1', 'sfo1', 'cdg1'] // Multi-region
|
||||
};
|
||||
```
|
||||
|
||||
### vercel.json
|
||||
|
||||
```json
|
||||
{
|
||||
"framework": "sveltekit",
|
||||
"buildCommand": "npm run build",
|
||||
"installCommand": "npm ci",
|
||||
"headers": [
|
||||
{
|
||||
"source": "/_app/immutable/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=31536000, immutable"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Cloudflare Pages
|
||||
|
||||
### Configuration
|
||||
|
||||
```javascript
|
||||
// svelte.config.js
|
||||
import adapter from '@sveltejs/adapter-cloudflare';
|
||||
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
routes: {
|
||||
include: ['/*'],
|
||||
exclude: ['<all>']
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Platform Bindings
|
||||
|
||||
```typescript
|
||||
// src/app.d.ts
|
||||
declare global {
|
||||
namespace App {
|
||||
interface Platform {
|
||||
env: {
|
||||
KV_NAMESPACE: KVNamespace;
|
||||
D1_DATABASE: D1Database;
|
||||
R2_BUCKET: R2Bucket;
|
||||
};
|
||||
context: {
|
||||
waitUntil(promise: Promise<unknown>): void;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// src/routes/+page.server.ts
|
||||
export async function load({ platform }) {
|
||||
const value = await platform?.env.KV_NAMESPACE.get('key');
|
||||
return { value };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Security Considerations
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```typescript
|
||||
// src/lib/server/env.ts
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { building } from '$app/environment';
|
||||
|
||||
if (!building) {
|
||||
// Validate required env vars at startup
|
||||
const required = ['DATABASE_URL', 'SECRET_KEY'];
|
||||
|
||||
for (const key of required) {
|
||||
if (!env[key]) {
|
||||
throw new Error(`Missing required environment variable: ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const config = {
|
||||
databaseUrl: env.DATABASE_URL,
|
||||
secretKey: env.SECRET_KEY,
|
||||
isProduction: env.NODE_ENV === 'production'
|
||||
};
|
||||
```
|
||||
|
||||
### Security Headers
|
||||
|
||||
```typescript
|
||||
// src/hooks.server.ts
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
|
||||
export const handle: Handle = async ({ event, resolve }) => {
|
||||
const response = await resolve(event);
|
||||
|
||||
// Security headers
|
||||
response.headers.set('X-Frame-Options', 'SAMEORIGIN');
|
||||
response.headers.set('X-Content-Type-Options', 'nosniff');
|
||||
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||
response.headers.set(
|
||||
'Content-Security-Policy',
|
||||
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
|
||||
);
|
||||
response.headers.set(
|
||||
'Permissions-Policy',
|
||||
'camera=(), microphone=(), geolocation=()'
|
||||
);
|
||||
|
||||
return response;
|
||||
};
|
||||
```
|
||||
|
||||
### CORS Configuration
|
||||
|
||||
```typescript
|
||||
// src/routes/api/[...path]/+server.ts
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
const allowedOrigins = ['https://example.com', 'https://app.example.com'];
|
||||
|
||||
export const OPTIONS: RequestHandler = async ({ request }) => {
|
||||
const origin = request.headers.get('origin');
|
||||
|
||||
if (origin && allowedOrigins.includes(origin)) {
|
||||
return new Response(null, {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': origin,
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
'Access-Control-Max-Age': '86400'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new Response(null, { status: 403 });
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Health Checks & Monitoring
|
||||
|
||||
### Health Endpoint
|
||||
|
||||
```typescript
|
||||
// src/routes/health/+server.ts
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
const health = {
|
||||
status: 'healthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime(),
|
||||
memory: process.memoryUsage(),
|
||||
version: process.env.npm_package_version
|
||||
};
|
||||
|
||||
// Add database check
|
||||
try {
|
||||
// await db.query('SELECT 1');
|
||||
health.database = 'connected';
|
||||
} catch {
|
||||
health.database = 'disconnected';
|
||||
health.status = 'degraded';
|
||||
}
|
||||
|
||||
const statusCode = health.status === 'healthy' ? 200 : 503;
|
||||
|
||||
return json(health, { status: statusCode });
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Deployment Checklist
|
||||
|
||||
### Pre-Deployment
|
||||
- [ ] All tests passing
|
||||
- [ ] Environment variables documented
|
||||
- [ ] Build succeeds locally
|
||||
- [ ] Security headers configured
|
||||
- [ ] Error pages customized
|
||||
- [ ] Logging configured
|
||||
|
||||
### Production
|
||||
- [ ] SSL/TLS enabled
|
||||
- [ ] CDN configured
|
||||
- [ ] Database backups scheduled
|
||||
- [ ] Monitoring/alerting setup
|
||||
- [ ] Rate limiting enabled
|
||||
- [ ] Health checks configured
|
||||
|
||||
### Post-Deployment
|
||||
- [ ] Smoke tests passing
|
||||
- [ ] Performance metrics acceptable
|
||||
- [ ] Error tracking working
|
||||
- [ ] Rollback plan documented
|
||||
Reference in New Issue
Block a user