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.