Chapter 36
Deployment & CDN
Learning Objectives
- Understand deployment process
- Learn about CDNs
- Configure Cloudflare Pages
- Monitor and maintain
Deployment Process
// Steps to deploy MixMind:
// 1. Prepare files
const files = [
'index.html',
'styles.css',
'app.js',
'audio-engine.js',
'analysis-engine.js',
'separation-engine.js',
'transition-engine.js',
'export-engine.js',
'models/spleeter.onnx',
'wasm/ort-wasm-simd.wasm'
];
// 2. Verify integrity
async function verifyFiles(files) {
for (const file of files) {
const content = await fetch(file).then(r => r.arrayBuffer());
const hash = await calculateHash(content);
console.log(`${file}: ${hash}`);
}
}
// 3. Deploy to CDN
// (Using Cloudflare Pages in our case)
// Upload files via dashboard or CLI
Content Delivery Network (CDN)
A CDN distributes your files across servers worldwide for fast loading:
- Edge servers: Servers in many locations
- Caching: Files stored close to users
- Low latency: Fast load times everywhere
MixMind uses Cloudflare Pages:
- Free tier: Unlimited bandwidth
- Automatic HTTPS
- Global CDN
- Deploy from Git
Cloudflare Pages Setup
// Deployment workflow:
// 1. Push code to Git
git add .
git commit -m "Update MixMind"
git push origin main
// 2. Cloudflare auto-deploys
// - Detects changes
// - Builds project
// - Deploys to CDN
// - Provides URL: mixmind.pages.dev
// 3. Manual deployment (if needed)
// Using Wrangler CLI:
npx wrangler pages deploy ./dist --project-name=mixmind
// Configuration: wrangler.toml
[site]
bucket = "./dist"
// Environment variables
[env.production]
NODE_ENV = "production"
Monitoring & Analytics
// Track usage and errors
class Analytics {
constructor() {
this.events = [];
}
track(event, data = {}) {
this.events.push({
event: event,
data: data,
timestamp: Date.now()
});
// Send to analytics service
this.send(event, data);
}
send(event, data) {
// Using a simple beacon
navigator.sendBeacon('/analytics', JSON.stringify({
event: event,
data: data,
timestamp: Date.now(),
userAgent: navigator.userAgent,
url: window.location.href
}));
}
}
// Track key events
analytics.track('page_view');
analytics.track('track_upload', { format: 'mp3', size: 5000000 });
analytics.track('separation_start', { duration: 180 });
analytics.track('separation_complete', { duration: 180, time: 12.5 });
analytics.track('export', { format: 'wav' });
analytics.track('error', { message: 'Model load failed' });
// Error tracking
window.addEventListener('error', (event) => {
analytics.track('javascript_error', {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno
});
});
window.addEventListener('unhandledrejection', (event) => {
analytics.track('promise_error', {
message: event.reason.message,
stack: event.reason.stack
});
});
Updates & Maintenance
// Version management
const VERSION = '1.0.0';
// Check for updates
async function checkForUpdates() {
const response = await fetch('/version.json');
const data = await response.json();
if (data.version !== VERSION) {
showUpdateNotification(data.version);
}
}
// Cache busting
// index.html
// Service worker update
self.addEventListener('install', (event) => {
self.skipWaiting(); // Activate immediately
});
self.addEventListener('activate', (event) => {
event.waitUntil(clients.claim()); // Take control
});
// Deployment checklist:
// ✅ Test locally
// ✅ Run test suite
// ✅ Check file sizes
// ✅ Verify integrity hashes
// ✅ Test on mobile
// ✅ Check performance
// ✅ Deploy to staging
// ✅ Test staging
// ✅ Deploy to production
// ✅ Monitor for errors
🎵 MixMind Connection
How MixMind is Deployed
// MixMind's deployment setup
// File structure on CDN:
// mixmind.pages.dev/
// ├── index.html
// ├── styles.css
// ├── app.js
// ├── audio-engine.js
// ├── analysis-engine.js
// ├── separation-engine.js
// ├── transition-engine.js
// ├── export-engine.js
// ├── models/
// │ └── spleeter.onnx (120 MB)
// ├── wasm/
// │ └── ort-wasm-simd.wasm (20 MB)
// └── sw.js
// Integrity verification
const manifest = {
'index.html': 'sha256-abc123...',
'app.js': 'sha256-def456...',
'models/spleeter.onnx': 'sha256-ghi789...'
};
// Check integrity on load
async function verifyIntegrity() {
for (const [file, expectedHash] of Object.entries(manifest)) {
const content = await fetch(file).then(r => r.arrayBuffer());
const actualHash = await calculateHash(content);
if (actualHash !== expectedHash) {
throw new Error(`Integrity check failed: ${file}`);
}
}
}
// Performance monitoring
class PerformanceMonitor {
constructor() {
this.metrics = {};
}
record(metric, value) {
if (!this.metrics[metric]) {
this.metrics[metric] = [];
}
this.metrics[metric].push(value);
}
report() {
const report = {};
for (const [metric, values] of Object.entries(this.metrics)) {
const avg = values.reduce((a, b) => a + b) / values.length;
const max = Math.max(...values);
const min = Math.min(...values);
report[metric] = { avg, max, min };
}
console.log('Performance Report:', report);
return report;
}
}
// Track key metrics
const perfMonitor = new PerformanceMonitor();
// Track load times
performance.mark('app-start');
// ... app loads ...
performance.mark('app-ready');
performance.measure('app-load', 'app-start', 'app-ready');
const loadTime = performance.getEntriesByName('app-load')[0].duration;
perfMonitor.record('app_load_time', loadTime);
// Track separation times
const startTime = performance.now();
await separationEngine.separate(audio);
const duration = performance.now() - startTime;
perfMonitor.record('separation_time', duration);
// Deployment complete! 🎉
console.log('✅ MixMind is live at https://mixmind.pages.dev');
Exercise 36.1: Practice
Goal: Apply what you've learned in this chapter
Try the concepts from this chapter in your browser's console or a simple HTML file. Experiment with the code examples and modify them to see what happens.
📝 Quick Reference:
Review the key concepts from this chapter and make sure you understand each one before moving to the next chapter.