Skip to content

浏览器端代码沙箱原理 #35

@leno23

Description

@leno23
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>浏览器端代码沙箱原理 - CodePen & CodeSandbox</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
            line-height: 1.6;
            color: #333;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            padding: 20px;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
            background: white;
            border-radius: 12px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            padding: 40px;
        }

        h1 {
            color: #667eea;
            font-size: 2.5em;
            margin-bottom: 10px;
            text-align: center;
        }

        .subtitle {
            text-align: center;
            color: #666;
            margin-bottom: 40px;
            font-size: 1.1em;
        }

        h2 {
            color: #764ba2;
            font-size: 1.8em;
            margin-top: 40px;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 3px solid #667eea;
        }

        h3 {
            color: #555;
            font-size: 1.3em;
            margin-top: 30px;
            margin-bottom: 15px;
        }

        h4 {
            color: #666;
            font-size: 1.1em;
            margin-top: 20px;
            margin-bottom: 10px;
        }

        .intro {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 8px;
            border-left: 4px solid #667eea;
            margin-bottom: 30px;
        }

        .platform-comparison {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin: 30px 0;
        }

        .codepen, .codesandbox {
            padding: 20px;
            border-radius: 8px;
            border: 2px solid #ddd;
        }

        .codepen {
            background: #fff5f5;
            border-color: #fc8181;
        }

        .codepen h3 {
            color: #c53030;
        }

        .codesandbox {
            background: #f0fff4;
            border-color: #68d391;
        }

        .codesandbox h3 {
            color: #22543d;
        }

        pre {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 20px;
            border-radius: 8px;
            overflow-x: auto;
            margin: 15px 0;
            font-size: 14px;
            line-height: 1.5;
        }

        code {
            font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
        }

        .code-block {
            margin: 15px 0;
        }

        .architecture-diagram {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 8px;
            margin: 20px 0;
            border: 2px dashed #667eea;
        }

        .architecture-diagram pre {
            background: #2d2d2d;
            margin: 10px 0;
        }

        .step {
            background: #e6f3ff;
            padding: 15px;
            border-radius: 8px;
            margin: 15px 0;
            border-left: 4px solid #667eea;
        }

        .step-number {
            display: inline-block;
            background: #667eea;
            color: white;
            width: 30px;
            height: 30px;
            border-radius: 50%;
            text-align: center;
            line-height: 30px;
            font-weight: bold;
            margin-right: 10px;
        }

        .tech-stack {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .tech-item {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 8px;
            border: 2px solid #ddd;
            text-align: center;
        }

        .tech-item strong {
            color: #667eea;
            display: block;
            margin-bottom: 5px;
        }

        .warning {
            background: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 15px;
            margin: 20px 0;
            border-radius: 4px;
        }

        .info {
            background: #d1ecf1;
            border-left: 4px solid #0c5460;
            padding: 15px;
            margin: 20px 0;
            border-radius: 4px;
        }

        .success {
            background: #d4edda;
            border-left: 4px solid #28a745;
            padding: 15px;
            margin: 20px 0;
            border-radius: 4px;
        }

        .flow-diagram {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 8px;
            margin: 20px 0;
        }

        .flow-step {
            background: white;
            padding: 15px;
            margin: 10px 0;
            border-radius: 8px;
            border-left: 4px solid #667eea;
            position: relative;
            padding-left: 50px;
        }

        .flow-step::before {
            content: "→";
            position: absolute;
            left: 15px;
            color: #667eea;
            font-size: 20px;
            font-weight: bold;
        }

        .comparison-table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }

        .comparison-table th,
        .comparison-table td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }

        .comparison-table th {
            background: #667eea;
            color: white;
        }

        .comparison-table tr:hover {
            background: #f5f5f5;
        }

        @media (max-width: 768px) {
            .platform-comparison {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🌐 浏览器端代码沙箱原理</h1>
        <p class="subtitle">CodePen.io 与 CodeSandbox 技术深度解析</p>

        <div class="intro">
            <h3>什么是浏览器端代码沙箱?</h3>
            <p>
                浏览器端代码沙箱是一种在浏览器中安全执行用户代码的技术。它允许用户在网页中编写、编辑和运行代码(HTML、CSS、JavaScript),
                而无需安装任何开发环境。CodePen 和 CodeSandbox 是两个最流行的在线代码编辑器平台。
            </p>
        </div>

        <h2>📋 平台概览</h2>

        <div class="platform-comparison">
            <div class="codepen">
                <h3>CodePen.io</h3>
                <p><strong>定位:</strong>前端代码片段展示和实验平台</p>
                <p><strong>特点:</strong></p>
                <ul style="margin-left: 20px; margin-top: 10px;">
                    <li>专注于 HTML/CSS/JS 片段</li>
                    <li>实时预览</li>
                    <li>社区分享</li>
                    <li>简单易用</li>
                </ul>
            </div>

            <div class="codesandbox">
                <h3>CodeSandbox</h3>
                <p><strong>定位:</strong>完整的 Web 应用开发环境</p>
                <p><strong>特点:</strong></p>
                <ul style="margin-left: 20px; margin-top: 10px;">
                    <li>支持完整的项目结构</li>
                    <li>支持 npm 包管理</li>
                    <li>支持 React、Vue、Angular 等框架</li>
                    <li>支持 TypeScript、构建工具等</li>
                </ul>
            </div>
        </div>

        <h2>🔧 核心技术原理</h2>

        <h3>1. iframe 隔离机制</h3>
        <div class="info">
            <p><strong>核心思想:</strong>使用 iframe 创建独立的执行环境,实现代码隔离和安全控制。</p>
        </div>

        <div class="architecture-diagram">
            <h4>CodePen 架构图:</h4>
            <pre><code>┌─────────────────────────────────────┐
│  主页面 (Parent Window)              │
│  ┌──────────┐  ┌──────────┐        │
│  │ HTML编辑器│  │ CSS编辑器 │        │
│  └──────────┘  └──────────┘        │
│  ┌──────────┐                       │
│  │ JS编辑器 │                       │
│  └──────────┘                       │
│                                     │
│  ┌─────────────────────────────┐   │
│  │  预览区域 (iframe)           │   │
│  │  ┌───────────────────────┐  │   │
│  │  │ 用户代码执行环境       │  │   │
│  │  │ - HTML 渲染           │  │   │
│  │  │ - CSS 应用            │  │   │
│  │  │ - JavaScript 执行      │  │   │
│  │  └───────────────────────┘  │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘</code></pre>
        </div>

        <div class="step">
            <span class="step-number">1</span>
            <strong>创建隔离的 iframe</strong>
            <pre><code>// 主页面创建 iframe
const iframe = document.createElement('iframe');
iframe.src = 'about:blank';  // 空白页面
iframe.sandbox = 'allow-scripts allow-same-origin';
document.body.appendChild(iframe);

// 获取 iframe 的 document
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;</code></pre>
        </div>

        <div class="step">
            <span class="step-number">2</span>
            <strong>注入用户代码</strong>
            <pre><code>// 组合 HTML、CSS、JS
const html = userHTML;
const css = userCSS;
const js = userJS;

// 构建完整的 HTML 文档
const fullHTML = `
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;style&gt;${css}&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  ${html}
  &lt;script&gt;${js}&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
`;

// 写入 iframe
iframeDoc.open();
iframeDoc.write(fullHTML);
iframeDoc.close();</code></pre>
        </div>

        <h3>2. 安全沙箱属性 (sandbox)</h3>
        <div class="warning">
            <p><strong>安全考虑:</strong>iframe 的 sandbox 属性限制了 iframe 内的代码可以执行的操作。</p>
        </div>

        <pre><code>// sandbox 属性的常用值
iframe.sandbox = 'allow-scripts allow-same-origin allow-forms';

// 各属性说明:
// - allow-scripts: 允许执行 JavaScript
// - allow-same-origin: 允许访问同源资源(但会降低安全性)
// - allow-forms: 允许提交表单
// - allow-popups: 允许打开弹窗
// - allow-modals: 允许 alert/confirm 等模态框

// 注意:allow-same-origin 会降低安全性,因为代码可以访问父页面
// CodePen 通常不使用 allow-same-origin,完全隔离</code></pre>

        <h3>3. CodePen 完整实现流程</h3>
        <div class="flow-diagram">
            <div class="flow-step">
                <strong>步骤 1:用户输入代码</strong>
                <p>用户在编辑器中输入 HTML、CSS、JavaScript 代码</p>
            </div>
            <div class="flow-step">
                <strong>步骤 2:代码组合</strong>
                <p>将三个编辑器的内容组合成一个完整的 HTML 文档</p>
            </div>
            <div class="flow-step">
                <strong>步骤 3:创建/更新 iframe</strong>
                <p>创建新的 iframe 或清空现有 iframe 内容</p>
            </div>
            <div class="flow-step">
                <strong>步骤 4:写入代码</strong>
                <p>使用 document.write() 或 srcdoc 属性将代码写入 iframe</p>
            </div>
            <div class="flow-step">
                <strong>步骤 5:执行和渲染</strong>
                <p>浏览器解析 HTML、应用 CSS、执行 JavaScript</p>
            </div>
        </div>

        <div class="code-block">
            <h4>CodePen 核心代码示例:</h4>
            <pre><code>class CodePenEditor {
  constructor() {
    this.html = '';
    this.css = '';
    this.js = '';
    this.iframe = null;
  }

  // 创建预览 iframe
  createPreviewFrame() {
    this.iframe = document.createElement('iframe');
    this.iframe.id = 'preview-frame';
    this.iframe.sandbox = 'allow-scripts allow-forms allow-modals';
    this.iframe.style.width = '100%';
    this.iframe.style.height = '500px';
    this.iframe.style.border = 'none';
    document.getElementById('preview').appendChild(this.iframe);
  }

  // 更新预览
  updatePreview() {
    if (!this.iframe) {
      this.createPreviewFrame();
    }

    const htmlContent = `
      &lt;!DOCTYPE html&gt;
      &lt;html&gt;
      &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;style&gt;
          ${this.css}
        &lt;/style&gt;
      &lt;/head&gt;
      &lt;body&gt;
        ${this.html}
        &lt;script&gt;
          ${this.js}
        &lt;/script&gt;
      &lt;/body&gt;
      &lt;/html&gt;
    `;

    // 方法 1: 使用 srcdoc (推荐)
    this.iframe.srcdoc = htmlContent;

    // 方法 2: 使用 document.write
    // const iframeDoc = this.iframe.contentDocument;
    // iframeDoc.open();
    // iframeDoc.write(htmlContent);
    // iframeDoc.close();
  }

  // 监听编辑器变化
  setupEditors() {
    const htmlEditor = document.getElementById('html-editor');
    const cssEditor = document.getElementById('css-editor');
    const jsEditor = document.getElementById('js-editor');

    [htmlEditor, cssEditor, jsEditor].forEach(editor => {
      editor.addEventListener('input', () => {
        this.html = htmlEditor.value;
        this.css = cssEditor.value;
        this.js = jsEditor.value;
        this.updatePreview();
      });
    });
  }
}</code></pre>
        </div>

        <h2>🚀 CodeSandbox 的高级架构</h2>

        <div class="success">
            <p><strong>CodeSandbox 的复杂性:</strong>CodeSandbox 不仅是一个代码编辑器,更是一个完整的开发环境,需要处理模块系统、包管理、构建工具等。现代版本还使用了 WebContainer 和 Serverless 技术。</p>
        </div>

        <h3>1. 模块系统实现</h3>
        <div class="architecture-diagram">
            <h4>CodeSandbox 架构:</h4>
            <pre><code>┌─────────────────────────────────────────┐
│  主应用 (React/Vue)                      │
│  ┌───────────────────────────────────┐  │
│  │  文件管理器                        │  │
│  │  - package.json                   │  │
│  │  - src/index.js                   │  │
│  │  - src/App.jsx                    │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  代码编辑器 (Monaco Editor)        │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  预览区域                           │  │
│  │  ┌─────────────────────────────┐  │  │
│  │  │  iframe (应用运行环境)       │  │  │
│  │  │  ┌───────────────────────┐ │  │  │
│  │  │  │ 模块加载器             │ │  │  │
│  │  │  │ - 解析 import/require  │ │  │  │
│  │  │  │ - 加载 npm 包          │ │  │  │
│  │  │  │ - 代码转换 (Babel)      │ │  │  │
│  │  │  └───────────────────────┘ │  │  │
│  │  └─────────────────────────────┘  │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘</code></pre>
        </div>

        <h3>2. 模块加载器实现</h3>
        <div class="code-block">
            <pre><code>// CodeSandbox 使用自定义的模块加载器
// 在浏览器中模拟 Node.js 的模块系统

class ModuleLoader {
  constructor() {
    this.modules = new Map();
    this.cache = new Map();
  }

  // 注册模块
  registerModule(path, code) {
    this.modules.set(path, code);
  }

  // 解析模块路径
  resolveModule(importPath, fromPath) {
    // 处理相对路径
    if (importPath.startsWith('./') || importPath.startsWith('../')) {
      return this.resolveRelativePath(importPath, fromPath);
    }
    
    // 处理 npm 包
    if (!importPath.startsWith('.')) {
      return this.resolveNpmPackage(importPath);
    }
  }

  // 加载模块
  async loadModule(path) {
    if (this.cache.has(path)) {
      return this.cache.get(path);
    }

    const code = this.modules.get(path);
    if (!code) {
      throw new Error(`Module not found: ${path}`);
    }

    // 转换代码 (使用 Babel 或 esbuild)
    const transformedCode = await this.transformCode(code, path);
    
    // 执行模块
    const module = this.executeModule(transformedCode, path);
    this.cache.set(path, module);
    
    return module;
  }

  // 转换代码
  async transformCode(code, path) {
    // 使用 Babel 转换 JSX、TypeScript 等
    // 或使用 esbuild 进行更快的转换
    const result = await babel.transform(code, {
      presets: ['react', 'env'],
      filename: path
    });
    return result.code;
  }

  // 执行模块
  executeModule(code, path) {
    // 创建模块作用域
    const module = { exports: {} };
    const require = (path) => this.loadModule(path);
    
    // 包装代码
    const wrappedCode = `
      (function(module, exports, require) {
        ${code}
      })(module, module.exports, require);
    `;
    
    eval(wrappedCode);
    return module.exports;
  }
}</code></pre>
        </div>

        <h3>3. npm 包管理</h3>
        <div class="info">
            <p><strong>挑战:</strong>在浏览器中运行 npm 包需要将包转换为浏览器可用的格式。</p>
        </div>

        <div class="flow-diagram">
            <div class="flow-step">
                <strong>步骤 1:解析 package.json</strong>
                <p>读取依赖列表,确定需要加载的包</p>
            </div>
            <div class="flow-step">
                <strong>步骤 2:从 CDN 加载包</strong>
                <p>使用 unpkg.com 或 jsDelivr 等 CDN 获取包文件</p>
            </div>
            <div class="flow-step">
                <strong>步骤 3:转换 CommonJS/ESM</strong>
                <p>将包的格式转换为浏览器可用的格式</p>
            </div>
            <div class="flow-step">
                <strong>步骤 4:注册到模块系统</strong>
                <p>将转换后的包注册到模块加载器中</p>
            </div>
        </div>

        <pre><code>// CodeSandbox 的包加载示例
async function loadNpmPackage(packageName, version = 'latest') {
  // 1. 从 CDN 获取包的入口文件
  const packageUrl = `https://unpkg.com/${packageName}@${version}`;
  const packageJsonUrl = `${packageUrl}/package.json`;
  
  // 2. 获取 package.json 确定入口
  const packageJson = await fetch(packageJsonUrl).then(r => r.json());
  const entryFile = packageJson.module || packageJson.main || 'index.js';
  
  // 3. 加载入口文件
  const code = await fetch(`${packageUrl}/${entryFile}`).then(r => r.text());
  
  // 4. 转换代码
  const transformedCode = await transformCode(code);
  
  // 5. 注册到模块系统
  moduleLoader.registerModule(packageName, transformedCode);
  
  return transformedCode;
}</code></pre>

        <h3>4. 实时编译和热更新</h3>
        <div class="code-block">
            <pre><code>// CodeSandbox 使用 Web Worker 进行代码转换
// 避免阻塞主线程

class CompilerWorker {
  constructor() {
    this.worker = new Worker('/compiler-worker.js');
    this.worker.onmessage = this.handleMessage.bind(this);
  }

  // 编译代码
  compile(filePath, code) {
    return new Promise((resolve, reject) => {
      const requestId = Math.random().toString(36);
      
      this.pendingRequests = this.pendingRequests || {};
      this.pendingRequests[requestId] = { resolve, reject };
      
      this.worker.postMessage({
        id: requestId,
        type: 'compile',
        filePath,
        code
      });
    });
  }

  handleMessage(event) {
    const { id, result, error } = event.data;
    const request = this.pendingRequests[id];
    
    if (error) {
      request.reject(new Error(error));
    } else {
      request.resolve(result);
    }
    
    delete this.pendingRequests[id];
  }
}

// 使用
const compiler = new CompilerWorker();

// 监听文件变化
fileWatcher.on('change', async (filePath, newCode) => {
  try {
    const compiled = await compiler.compile(filePath, newCode);
    updatePreview(compiled);
  } catch (error) {
    showError(error);
  }
});</code></pre>
        </div>

        <h2>⚙️ WebAssembly (WASM) 原理深度解析</h2>

        <div class="intro">
            <h3>什么是 WebAssembly?</h3>
            <p>
                <strong>WebAssembly (WASM)</strong> 是一种低级的二进制指令格式,设计用于在 Web 浏览器中高效执行。
                它不是一种编程语言,而是一种编译目标,允许用 C/C++、Rust、Go 等语言编写的代码在浏览器中以接近原生的速度运行。
            </p>
        </div>

        <h3>1. WebAssembly 的核心概念</h3>

        <div class="architecture-diagram">
            <h4>WebAssembly 执行流程:</h4>
            <pre><code>┌─────────────────────────────────────────┐
│  源代码 (C/C++/Rust/Go)                  │
│  int add(int a, int b) {                │
│    return a + b;                         │
│  }                                       │
└─────────────────────────────────────────┘
           │
           ▼ 编译
┌─────────────────────────────────────────┐
│  WebAssembly 二进制 (.wasm)              │
│  或文本格式 (.wat)                        │
│  (module                                 │
│    (func $add (param $a i32) (param $b i32) (result i32)
│      local.get $a
│      local.get $b
│      i32.add
│    )
│  )                                       │
└─────────────────────────────────────────┘
           │
           ▼ 加载和执行
┌─────────────────────────────────────────┐
│  浏览器 WebAssembly 引擎                  │
│  ┌───────────────────────────────────┐  │
│  │  验证器 (Validator)                │  │
│  │  - 检查代码安全性                   │  │
│  │  - 验证类型正确性                   │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  编译器 (Compiler)                │  │
│  │  - 即时编译 (JIT)                  │  │
│  │  - 优化代码                         │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  执行引擎                          │  │
│  │  - 栈式虚拟机                       │  │
│  │  - 线性内存模型                     │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘</code></pre>
        </div>

        <h3>2. WebAssembly 的栈式虚拟机</h3>
        <div class="info">
            <p><strong>关键特性:</strong>WebAssembly 使用栈式虚拟机,所有操作都通过栈进行。</p>
        </div>

        <div class="code-block">
            <pre><code>// 示例:计算 (2 + 3) * 4

// JavaScript 代码
function calculate() {
  return (2 + 3) * 4;
}

// 对应的 WebAssembly 文本格式 (.wat)
(module
  (func $calculate (result i32)
    i32.const 2      // 将 2 压入栈
    i32.const 3      // 将 3 压入栈
    i32.add          // 弹出 3 和 2,计算 2+3=5,将 5 压入栈
    i32.const 4      // 将 4 压入栈
    i32.mul          // 弹出 4 和 5,计算 5*4=20,将 20 压入栈
  )
  (export "calculate" (func $calculate))
)

// 栈的变化过程:
// 初始: []
// i32.const 2: [2]
// i32.const 3: [2, 3]
// i32.add: [5]
// i32.const 4: [5, 4]
// i32.mul: [20]
// 返回: 20</code></pre>
        </div>

        <h3>3. WebAssembly 的线性内存模型</h3>
        <div class="step">
            <span class="step-number">1</span>
            <strong>线性内存</strong>
            <p>WebAssembly 使用一个大的、连续的字节数组作为内存,通过索引访问。</p>
            <pre><code>// WebAssembly 内存是一个字节数组
// 内存布局示例:

// 地址:  0    1    2    3    4    5    6    7
// 值:    [0x41][0x42][0x43][0x00][0x01][0x02][0x03][0x04]
//        'A'  'B'  'C'  null  1     2     3     4

// 在 WebAssembly 中访问内存
(module
  (memory 1)  // 分配 1 页内存 (64KB)
  (func $store (param $value i32) (param $offset i32)
    local.get $offset
    local.get $value
    i32.store  // 将值存储到内存的指定偏移量
  )
  (func $load (param $offset i32) (result i32)
    local.get $offset
    i32.load   // 从内存的指定偏移量加载值
  )
)</code></pre>
        </div>

        <div class="step">
            <span class="step-number">2</span>
            <strong>与 JavaScript 的交互</strong>
            <p>WebAssembly 通过导入/导出函数与 JavaScript 交互,共享内存。</p>
            <pre><code>// JavaScript 端
const wasmModule = await WebAssembly.instantiateStreaming(
  fetch('module.wasm'),
  {
    // 导入对象:向 WASM 提供 JavaScript 函数
    env: {
      console_log: (value) => console.log(value),
      Math_random: () => Math.random()
    }
  }
);

// 调用 WASM 导出的函数
const result = wasmModule.instance.exports.calculate();

// 共享内存
const memory = wasmModule.instance.exports.memory;
const buffer = new Uint8Array(memory.buffer);
buffer[0] = 65; // 写入 'A'</code></pre>
        </div>

        <h3>4. 如何将 Node.js 编译为 WebAssembly</h3>
        <div class="warning">
            <p><strong>挑战:</strong>Node.js 是一个复杂的运行时环境,包含文件系统、网络、进程管理等系统调用,这些在浏览器中不可用。</p>
        </div>

        <div class="architecture-diagram">
            <h4>Node.js 到 WebAssembly 的转换过程:</h4>
            <pre><code>┌─────────────────────────────────────────┐
│  Node.js 源代码                          │
│  - V8 JavaScript 引擎                    │
│  - libuv (事件循环)                       │
│  - 系统调用 (fs, net, process)           │
└─────────────────────────────────────────┘
           │
           ▼ 使用 Emscripten 编译
┌─────────────────────────────────────────┐
│  Emscripten 工具链                       │
│  ┌───────────────────────────────────┐  │
│  │  1. 将 C/C++ 代码编译为 LLVM IR   │  │
│  │  2. LLVM 后端生成 WASM            │  │
│  │  3. 生成 JavaScript 胶水代码      │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘
           │
           ▼
┌─────────────────────────────────────────┐
│  WebAssembly 模块                        │
│  ┌───────────────────────────────────┐  │
│  │  Node.js 核心 (WASM)               │  │
│  │  - JavaScript 引擎                  │  │
│  │  - 事件循环                        │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  JavaScript 胶水代码               │  │
│  │  - 系统调用模拟                    │  │
│  │  - 文件系统绑定                    │  │
│  │  - 网络 API 绑定                   │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘</code></pre>
        </div>

        <h3>5. 系统调用的模拟</h3>
        <div class="code-block">
            <h4>文件系统模拟:</h4>
            <pre><code>// Node.js 的 fs.readFile 在浏览器中的实现

// 1. WebAssembly 端 (C/C++)
// 当 Node.js 调用 fs.readFile 时,会调用系统调用
int sys_read_file(const char* path, char** buffer, size_t* size) {
  // 在浏览器中,我们需要拦截这个调用
  // 通过 JavaScript 胶水代码处理
  return emscripten_async_wget_data(path, buffer, size, NULL);
}

// 2. JavaScript 胶水代码
// Emscripten 生成的胶水代码会处理系统调用
Module['FS'] = {
  // 虚拟文件系统
  filesystems: {},
  
  // 读取文件
  readFile: function(path) {
    // 从 IndexedDB 或 MemoryFS 读取
    if (Module['FS'].filesystems[path]) {
      return Module['FS'].filesystems[path];
    }
    
    // 或者从网络加载
    return fetch(path).then(r => r.arrayBuffer());
  },
  
  // 写入文件
  writeFile: function(path, data) {
    // 写入到 IndexedDB 或 MemoryFS
    Module['FS'].filesystems[path] = data;
    
    // 持久化到 IndexedDB
    saveToIndexedDB(path, data);
  }
};

// 3. 在 WebAssembly 中使用
// Node.js 代码可以正常使用 fs API
const fs = require('fs');
const content = fs.readFileSync('/app/index.js', 'utf8');
// 实际上会调用 JavaScript 胶水代码中的实现</code></pre>
        </div>

        <div class="code-block">
            <h4>网络 API 模拟:</h4>
            <pre><code>// Node.js 的 http 模块在浏览器中的实现

// 1. WebAssembly 中的网络调用
// Node.js 的 socket 操作会被转换为 JavaScript fetch API

// 原始 Node.js 代码
const http = require('http');
const server = http.createServer((req, res) => {
  res.end('Hello');
});
server.listen(3000);

// 2. Emscripten 转换后的实现
// JavaScript 胶水代码拦截网络调用
Module['_socket'] = function(domain, type, protocol) {
  // 创建 WebSocket 或使用 fetch API 模拟 socket
  return createWebSocketConnection();
};

Module['_bind'] = function(socket, addr, len) {
  // 在浏览器中,我们使用 Service Worker 拦截请求
  // 注册路由处理函数
  return registerRoute('/api', handleRequest);
};

Module['_listen'] = function(socket, backlog) {
  // 启动"服务器"(实际上是 Service Worker)
  return startServiceWorker();
};

// 3. Service Worker 处理请求
self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('/api')) {
    event.respondWith(
      handleAPIRequest(event.request)
    );
  }
});</code></pre>
        </div>

        <h3>6. WebContainer 的具体实现</h3>
        <div class="step">
            <span class="step-number">1</span>
            <strong>编译 Node.js 为 WebAssembly</strong>
            <pre><code>// 使用 Emscripten 编译 Node.js 的简化流程

// 1. 配置 Emscripten
emconfigure ./configure \
  --without-snapshot \
  --dest-cpu=wasm32 \
  --without-intl

// 2. 编译
emmake make

// 3. 生成的文件
// - node.wasm: WebAssembly 二进制文件
// - node.js: JavaScript 胶水代码
// - node.data: 预加载的数据文件

// 4. 在浏览器中加载
const Module = {
  // 文件系统配置
  preRun: [],
  postRun: [],
  
  // 虚拟文件系统
  FS: {
    filesystems: {},
    mount: function(type, opts, mountpoint) {
      // 挂载文件系统
    }
  },
  
  // 网络模拟
  ENV: {
    NODE_ENV: 'development'
  }
};

// 加载 WASM 模块
const wasmModule = await WebAssembly.instantiateStreaming(
  fetch('node.wasm'),
  Module
);</code></pre>
        </div>

        <div class="step">
            <span class="step-number">2</span>
            <strong>虚拟文件系统实现</strong>
            <pre><code>// WebContainer 使用 Emscripten 的虚拟文件系统

class WebContainerFileSystem {
  constructor() {
    // 使用 Emscripten 的 FS API
    this.FS = Module.FS;
    this.mountIndexedDB();
  }

  // 挂载 IndexedDB 作为持久化存储
  mountIndexedDB() {
    // Emscripten 支持多种文件系统后端
    this.FS.mkdir('/workspace');
    this.FS.mount(
      this.FS.filesystems.IDBFS,  // IndexedDB 文件系统
      {},
      '/workspace'
    );
    
    // 同步到 IndexedDB
    this.FS.syncfs(true, (err) => {
      if (err) throw err;
      console.log('文件系统已加载');
    });
  }

  // 写入文件
  writeFile(path, content) {
    // 确保目录存在
    const dir = path.substring(0, path.lastIndexOf('/'));
    this.FS.mkdirTree(dir);
    
    // 写入文件
    this.FS.writeFile(path, content, { encoding: 'utf8' });
    
    // 同步到 IndexedDB
    this.FS.syncfs(false, () => {});
  }

  // 读取文件
  readFile(path) {
    return this.FS.readFile(path, { encoding: 'utf8' });
  }

  // 执行命令
  async exec(command, args) {
    // 在 WebAssembly 环境中执行命令
    // 这实际上是在 WASM 版本的 Node.js 中运行
    return new Promise((resolve, reject) => {
      Module.callMain([command, ...args]);
      resolve();
    });
  }
}

// 使用示例
const fs = new WebContainerFileSystem();
fs.writeFile('/workspace/package.json', JSON.stringify({
  name: 'my-app',
  dependencies: { 'react': '^18.0.0' }
}));

// 在 WASM Node.js 中执行 npm install
await fs.exec('npm', ['install']);</code></pre>
        </div>

        <div class="step">
            <span class="step-number">3</span>
            <strong>进程管理模拟</strong>
            <pre><code>// 在浏览器中模拟 Node.js 的进程

class ProcessManager {
  constructor(wasmModule) {
    this.wasmModule = wasmModule;
    this.processes = new Map();
  }

  // 创建子进程
  spawn(command, args, options) {
    return new Promise((resolve, reject) => {
      // 在 Web Worker 中运行进程
      const worker = new Worker('/process-worker.js');
      const processId = Math.random().toString(36);
      
      const process = {
        id: processId,
        worker,
        stdout: new ReadableStream(),
        stderr: new ReadableStream(),
        on: (event, callback) => {
          if (event === 'exit') {
            worker.addEventListener('message', (e) => {
              if (e.data.type === 'exit') {
                callback(e.data.code);
              }
            });
          }
        }
      };
      
      this.processes.set(processId, process);
      
      // 发送命令到 Worker
      worker.postMessage({
        type: 'spawn',
        command,
        args,
        wasmModule: this.wasmModule  // 传递 WASM 模块引用
      });
      
      // 监听 Worker 消息
      worker.addEventListener('message', (e) => {
        const { type, data } = e.data;
        
        if (type === 'stdout') {
          process.stdout.enqueue(new TextEncoder().encode(data));
        } else if (type === 'stderr') {
          process.stderr.enqueue(new TextEncoder().encode(data));
        } else if (type === 'exit') {
          resolve(process);
        }
      });
      
      resolve(process);
    });
  }
}

// Process Worker 实现
// process-worker.js
self.addEventListener('message', async (e) => {
  const { type, command, args, wasmModule } = e.data;
  
  if (type === 'spawn') {
    // 在 Worker 中执行 WASM 代码
    // 这实际上是在 WASM Node.js 环境中运行命令
    const result = await wasmModule.instance.exports.exec(
      command,
      args
    );
    
    // 发送输出
    self.postMessage({ type: 'stdout', data: result.stdout });
    self.postMessage({ type: 'stderr', data: result.stderr });
    self.postMessage({ type: 'exit', code: result.code });
  }
});</code></pre>
        </div>

        <h3>7. 性能优化</h3>
        <div class="info">
            <h4>WebAssembly 的性能优势:</h4>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li><strong>接近原生速度</strong>:WASM 代码编译为机器码,执行速度快</li>
                <li><strong>类型安全</strong>:静态类型检查,减少运行时错误</li>
                <li><strong>并行执行</strong>:可以在 Web Worker 中运行,不阻塞主线程</li>
                <li><strong>内存效率</strong>:线性内存模型,内存使用更高效</li>
            </ul>
        </div>

        <div class="code-block">
            <pre><code>// 性能对比示例

// JavaScript 版本(慢)
function fibonacciJS(n) {
  if (n <= 1) return n;
  return fibonacciJS(n - 1) + fibonacciJS(n - 2);
}
// 执行时间: ~500ms (n=40)

// WebAssembly 版本(快)
// C 代码编译为 WASM
int fibonacciWASM(int n) {
  if (n <= 1) return n;
  return fibonacciWASM(n - 1) + fibonacciWASM(n - 2);
}
// 执行时间: ~50ms (n=40) - 快 10 倍!

// 在浏览器中使用
const wasmModule = await WebAssembly.instantiateStreaming(
  fetch('fibonacci.wasm')
);
const result = wasmModule.instance.exports.fibonacci(40);</code></pre>
        </div>

        <h3>8. 实际应用:WebContainer 完整流程</h3>
        <div class="flow-diagram">
            <div class="flow-step">
                <strong>步骤 1:加载 WebAssembly 模块</strong>
                <p>从 CDN 或本地加载编译好的 Node.js WASM 文件</p>
            </div>
            <div class="flow-step">
                <strong>步骤 2:初始化虚拟文件系统</strong>
                <p>挂载 IndexedDB 或 MemoryFS 作为文件系统后端</p>
            </div>
            <div class="flow-step">
                <strong>步骤 3:启动 Node.js 运行时</strong>
                <p>在 WASM 环境中启动 Node.js,初始化事件循环</p>
            </div>
            <div class="flow-step">
                <strong>步骤 4:执行用户代码</strong>
                <p>在 WASM Node.js 中执行 npm install、构建命令等</p>
            </div>
            <div class="flow-step">
                <strong>步骤 5:处理系统调用</strong>
                <p>通过 JavaScript 胶水代码处理文件系统、网络等操作</p>
            </div>
        </div>

        <div class="code-block">
            <h4>完整的 WebContainer 初始化代码:</h4>
            <pre><code>// WebContainer 的完整初始化流程

class WebContainer {
  static async boot() {
    // 1. 加载 WASM 模块
    const wasmModule = await WebAssembly.instantiateStreaming(
      fetch('https://cdn.jsdelivr.net/npm/@webcontainer/node.wasm'),
      {
        // 导入对象:提供 JavaScript API 给 WASM
        env: {
          // 文件系统操作
          fs_read_file: (path, buffer, size) => {
            const content = readFromIndexedDB(path);
            const encoder = new TextEncoder();
            const bytes = encoder.encode(content);
            new Uint8Array(wasmModule.instance.exports.memory.buffer, buffer, size)
              .set(bytes);
            return bytes.length;
          },
          
          fs_write_file: (path, buffer, size) => {
            const decoder = new TextDecoder();
            const content = decoder.decode(
              new Uint8Array(wasmModule.instance.exports.memory.buffer, buffer, size)
            );
            saveToIndexedDB(path, content);
            return 0;
          },
          
          // 网络操作
          net_create_server: (port) => {
            return registerServiceWorkerRoute(port);
          },
          
          // 控制台输出
          console_log: (ptr, len) => {
            const decoder = new TextDecoder();
            const message = decoder.decode(
              new Uint8Array(wasmModule.instance.exports.memory.buffer, ptr, len)
            );
            console.log(message);
          }
        }
      }
    );
    
    // 2. 初始化文件系统
    const fs = new VirtualFileSystem(wasmModule);
    await fs.mountIndexedDB('/workspace');
    
    // 3. 启动 Node.js
    wasmModule.instance.exports.node_start();
    
    // 4. 返回 WebContainer 实例
    return new WebContainer(wasmModule, fs);
  }
  
  async spawn(command, args) {
    // 在 WASM Node.js 中执行命令
    return this.wasmModule.instance.exports.spawn(command, args);
  }
}

// 使用
const container = await WebContainer.boot();
await container.spawn('npm', ['install', 'react']);</code></pre>
        </div>

        <div class="success">
            <h3>总结:WebAssembly 如何实现 Node.js 在浏览器中运行</h3>
            <ol style="margin-left: 20px; margin-top: 10px;">
                <li><strong>编译转换</strong>:使用 Emscripten 将 Node.js 的 C/C++ 代码编译为 WebAssembly</li>
                <li><strong>系统调用模拟</strong>:通过 JavaScript 胶水代码模拟文件系统、网络等系统调用</li>
                <li><strong>虚拟文件系统</strong>:使用 IndexedDB 或 MemoryFS 实现持久化存储</li>
                <li><strong>进程管理</strong>:在 Web Worker 中运行进程,通过消息传递通信</li>
                <li><strong>网络模拟</strong>:使用 Service Worker 或 fetch API 模拟网络功能</li>
                <li><strong>性能优化</strong>:利用 WASM 的高性能特性,接近原生执行速度</li>
            </ol>
        </div>

        <h2>🌐 WebContainer 技术</h2>

        <div class="intro">
            <h3>什么是 WebContainer?</h3>
            <p>
                <strong>WebContainer</strong> 是由 StackBlitz 开发的一项革命性技术,它使用 WebAssembly (WASM) 在浏览器中运行完整的 Node.js 环境。
                这使得可以在浏览器中执行原本需要服务器环境的操作,如运行 npm install、执行构建命令等。
            </p>
        </div>

        <h3>1. WebContainer 核心原理</h3>
        <div class="architecture-diagram">
            <h4>WebContainer 架构:</h4>
            <pre><code>┌─────────────────────────────────────────┐
│  浏览器环境                               │
│  ┌───────────────────────────────────┐  │
│  │  WebContainer (WASM)               │  │
│  │  ┌─────────────────────────────┐ │  │
│  │  │  Node.js Runtime (WASM)     │ │  │
│  │  │  - fs (文件系统)              │ │  │
│  │  │  - process (进程管理)         │ │  │
│  │  │  - net/http (网络)            │ │  │
│  │  └─────────────────────────────┘ │  │
│  │  ┌─────────────────────────────┐ │  │
│  │  │  虚拟文件系统 (VFS)          │ │  │
│  │  │  - 存储在 IndexedDB          │ │  │
│  │  │  - 模拟真实文件系统           │ │  │
│  │  └─────────────────────────────┘ │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  应用层                           │  │
│  │  - npm install                    │  │
│  │  - npm run build                  │  │
│  │  - node server.js                 │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘</code></pre>
        </div>

        <div class="step">
            <span class="step-number">1</span>
            <strong>WebAssembly 实现 Node.js</strong>
            <p>使用 Emscripten 或类似工具将 Node.js 编译为 WebAssembly,使其可以在浏览器中运行。</p>
            <pre><code>// WebContainer 使用 WASM 版本的 Node.js
// 核心模块通过 WebAssembly 实现

// 文件系统操作
const fs = require('fs');
fs.writeFileSync('/app/index.js', 'console.log("Hello")');

// 进程管理
const { spawn } = require('child_process');
const process = spawn('npm', ['install']);

// 网络请求
const http = require('http');
const server = http.createServer((req, res) => {
  res.end('Hello from WebContainer!');
});
server.listen(3000);</code></pre>
        </div>

        <div class="step">
            <span class="step-number">2</span>
            <strong>虚拟文件系统 (VFS)</strong>
            <p>使用 IndexedDB 或 MemoryFS 实现虚拟文件系统,模拟真实的文件系统操作。</p>
            <pre><code>// WebContainer 的虚拟文件系统实现
class VirtualFileSystem {
  constructor() {
    // 使用 IndexedDB 持久化存储
    this.db = new IDBDatabase('vfs');
    this.cache = new Map();
  }

  async writeFile(path, content) {
    // 写入 IndexedDB
    await this.db.put('files', { path, content });
    this.cache.set(path, content);
  }

  async readFile(path) {
    if (this.cache.has(path)) {
      return this.cache.get(path);
    }
    const file = await this.db.get('files', path);
    this.cache.set(path, file.content);
    return file.content;
  }

  async mkdir(path) {
    await this.db.put('directories', { path });
  }

  async readdir(path) {
    return await this.db.getAll('files')
      .filter(file => file.path.startsWith(path));
  }
}

// 挂载到 Node.js 的 fs 模块
const vfs = new VirtualFileSystem();
// 通过 WASM 绑定,将 vfs 替换原生的 fs 实现</code></pre>
        </div>

        <div class="step">
            <span class="step-number">3</span>
            <strong>进程和网络模拟</strong>
            <p>模拟 Node.js 的进程管理和网络功能,使其在浏览器中可用。</p>
            <pre><code>// WebContainer 中的进程执行
class ProcessManager {
  async spawn(command, args) {
    // 在 Web Worker 中执行命令
    const worker = new Worker('/process-worker.js');
    
    return new Promise((resolve, reject) => {
      worker.postMessage({ command, args });
      
      worker.onmessage = (event) => {
        const { type, data } = event.data;
        
        if (type === 'stdout') {
          process.stdout.write(data);
        } else if (type === 'stderr') {
          process.stderr.write(data);
        } else if (type === 'exit') {
          resolve(data);
        }
      };
    });
  }
}

// 使用示例
const pm = new ProcessManager();
await pm.spawn('npm', ['install', 'react']);
await pm.spawn('npm', ['run', 'build']);</code></pre>
        </div>

        <h3>2. CodeSandbox 中的 WebContainer 应用</h3>
        <div class="code-block">
            <pre><code>// CodeSandbox 使用 WebContainer 的示例
import { WebContainer } from '@webcontainer/api';

// 初始化 WebContainer
const container = await WebContainer.boot();

// 挂载文件系统
await container.mount({
  'package.json': {
    file: {
      contents: JSON.stringify({
        name: 'my-app',
        dependencies: {
          'react': '^18.0.0'
        }
      })
    }
  },
  'src/index.js': {
    file: {
      contents: `import React from 'react';
console.log('Hello from WebContainer!');`
    }
  }
});

// 安装依赖(在浏览器中运行!)
const installProcess = await container.spawn('npm', ['install']);
await installProcess.exit;

// 运行构建命令
const buildProcess = await container.spawn('npm', ['run', 'build']);
await buildProcess.exit;

// 启动开发服务器
const devProcess = await container.spawn('npm', ['start']);

// 监听输出
devProcess.output.pipeTo(
  new WritableStream({
    write(data) {
      console.log(data);
    }
  })
);</code></pre>
        </div>

        <div class="info">
            <h3>WebContainer 的优势:</h3>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li><strong>真正的 Node.js 环境</strong>:可以运行真实的 npm 命令和构建工具</li>
                <li><strong>无需服务器</strong>:所有操作都在浏览器中完成</li>
                <li><strong>快速启动</strong>:比传统服务器方案更快</li>
                <li><strong>完全隔离</strong>:每个沙箱都有独立的文件系统和进程空间</li>
                <li><strong>支持服务器端代码</strong>:可以运行 Express、Next.js 等框架</li>
            </ul>
        </div>

        <h2>☁️ Serverless 技术在代码沙箱中的应用</h2>

        <div class="intro">
            <h3>什么是 Serverless 在代码沙箱中的作用?</h3>
            <p>
                在代码沙箱中,<strong>Serverless</strong> 技术主要用于处理需要服务器端能力的操作,
                如 API 代理、数据库连接、文件上传等。这些功能通过 Serverless Functions 实现,无需维护完整的服务器。
            </p>
        </div>

        <h3>1. Serverless Functions 架构</h3>
        <div class="architecture-diagram">
            <h4>Serverless 架构:</h4>
            <pre><code>┌─────────────────────────────────────────┐
│  浏览器沙箱环境                           │
│  ┌───────────────────────────────────┐  │
│  │  用户代码                          │  │
│  │  fetch('/api/users')              │  │
│  └───────────────────────────────────┘  │
│           │                              │
│           ▼                              │
│  ┌───────────────────────────────────┐ │
│  │  API Gateway (代理层)               │ │
│  │  - 路由请求到对应的 Function        │ │
│  └───────────────────────────────────┘ │
│           │                              │
│           ▼                              │
│  ┌───────────────────────────────────┐ │
│  │  Serverless Functions              │ │
│  │  ┌──────────┐  ┌──────────┐      │ │
│  │  │ Function1│  │ Function2 │      │ │
│  │  │ (API)    │  │ (Upload) │      │ │
│  │  └──────────┘  └──────────┘      │ │
│  └───────────────────────────────────┘ │
│           │                              │
│           ▼                              │
│  ┌───────────────────────────────────┐ │
│  │  外部服务                           │ │
│  │  - 数据库                           │ │
│  │  - 存储服务                         │ │
│  │  - 第三方 API                       │ │
│  └───────────────────────────────────┘ │
└─────────────────────────────────────────┘</code></pre>
        </div>

        <h3>2. CodeSandbox 的 Serverless 实现</h3>
        <div class="code-block">
            <pre><code>// CodeSandbox 的 Serverless Functions 示例

// 1. 用户代码中调用 API
// 在沙箱中运行的代码
fetch('/api/users')
  .then(res => res.json())
  .then(data => console.log(data));

// 2. CodeSandbox 的 API Gateway
class APIGateway {
  constructor() {
    this.functions = new Map();
    this.setupProxy();
  }

  // 注册 Serverless Function
  registerFunction(path, handler) {
    this.functions.set(path, handler);
  }

  // 设置代理
  setupProxy() {
    // 拦截沙箱中的 fetch 请求
    const originalFetch = window.fetch;
    window.fetch = async (url, options) => {
      // 检查是否是 API 请求
      if (url.startsWith('/api/')) {
        return this.handleAPIRequest(url, options);
      }
      // 其他请求正常处理
      return originalFetch(url, options);
    };
  }

  // 处理 API 请求
  async handleAPIRequest(url, options) {
    const path = url.replace('/api', '');
    const handler = this.functions.get(path);

    if (!handler) {
      return new Response(
        JSON.stringify({ error: 'Function not found' }),
        { status: 404 }
      );
    }

    try {
      // 执行 Serverless Function
      const result = await handler({
        method: options.method || 'GET',
        headers: options.headers,
        body: options.body,
        query: this.parseQuery(url)
      });

      return new Response(
        JSON.stringify(result),
        { 
          status: 200,
          headers: { 'Content-Type': 'application/json' }
        }
      );
    } catch (error) {
      return new Response(
        JSON.stringify({ error: error.message }),
        { status: 500 }
      );
    }
  }
}

// 3. 定义 Serverless Function
const apiGateway = new APIGateway();

// 注册用户 API
apiGateway.registerFunction('/users', async (req) => {
  // 这里可以连接数据库、调用外部 API 等
  const users = await fetch('https://jsonplaceholder.typicode.com/users');
  return await users.json();
});

// 注册文件上传 API
apiGateway.registerFunction('/upload', async (req) => {
  const formData = new FormData();
  formData.append('file', req.body);
  
  // 上传到云存储
  const response = await fetch('https://storage.example.com/upload', {
    method: 'POST',
    body: formData
  });
  
  return await response.json();
});</code></pre>
        </div>

        <h3>3. Serverless Functions 的实际应用</h3>
        <div class="step">
            <span class="step-number">1</span>
            <strong>API 代理</strong>
            <p>代理用户代码中的 API 请求,避免 CORS 问题,并可以添加认证、限流等功能。</p>
            <pre><code>// Serverless Function: API 代理
apiGateway.registerFunction('/proxy', async (req) => {
  const targetUrl = req.query.url;
  
  // 添加认证头
  const headers = {
    'Authorization': `Bearer ${process.env.API_KEY}`,
    ...req.headers
  };
  
  // 转发请求
  const response = await fetch(targetUrl, {
    method: req.method,
    headers,
    body: req.body
  });
  
  return await response.json();
});

// 用户代码中使用
fetch('/api/proxy?url=https://api.example.com/data')
  .then(res => res.json());</code></pre>
        </div>

        <div class="step">
            <span class="step-number">2</span>
            <strong>数据库操作</strong>
            <p>通过 Serverless Functions 安全地访问数据库,避免在客户端暴露数据库凭证。</p>
            <pre><code>// Serverless Function: 数据库查询
apiGateway.registerFunction('/db/users', async (req) => {
  // 在 Serverless Function 中安全地连接数据库
  const db = await connectDatabase(process.env.DATABASE_URL);
  
  if (req.method === 'GET') {
    const users = await db.query('SELECT * FROM users');
    return users;
  }
  
  if (req.method === 'POST') {
    const newUser = await db.query(
      'INSERT INTO users (name, email) VALUES (?, ?)',
      [req.body.name, req.body.email]
    );
    return newUser;
  }
});</code></pre>
        </div>

        <div class="step">
            <span class="step-number">3</span>
            <strong>文件处理</strong>
            <p>处理文件上传、图片处理、PDF 生成等需要服务器资源的操作。</p>
            <pre><code>// Serverless Function: 文件上传和处理
apiGateway.registerFunction('/upload', async (req) => {
  const file = req.body.file;
  
  // 上传到云存储
  const storageUrl = await uploadToS3(file);
  
  // 如果是图片,生成缩略图
  if (file.type.startsWith('image/')) {
    const thumbnail = await generateThumbnail(file);
    await uploadToS3(thumbnail, `${storageUrl}-thumb`);
  }
  
  return { url: storageUrl };
});</code></pre>
        </div>

        <h3>4. Serverless 与 WebContainer 的结合</h3>
        <div class="info">
            <p><strong>现代代码沙箱的完整架构:</strong></p>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li><strong>WebContainer</strong>:处理 Node.js 环境、构建工具、开发服务器</li>
                <li><strong>Serverless Functions</strong>:处理需要外部资源的操作(数据库、存储、第三方 API)</li>
                <li><strong>iframe 沙箱</strong>:隔离用户代码,确保安全</li>
            </ul>
        </div>

        <div class="architecture-diagram">
            <h4>完整架构图:</h4>
            <pre><code>┌─────────────────────────────────────────┐
│  浏览器环境                               │
│  ┌───────────────────────────────────┐  │
│  │  iframe 沙箱                       │  │
│  │  ┌─────────────────────────────┐  │  │
│  │  │  用户应用代码                │  │  │
│  │  │  - React/Vue/Angular        │  │  │
│  │  │  - 前端逻辑                  │  │  │
│  │  └─────────────────────────────┘  │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  WebContainer                    │  │
│  │  - Node.js 环境                   │  │
│  │  - npm install/build              │  │
│  │  - 开发服务器 (localhost:3000)    │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  Serverless Functions             │  │
│  │  - API 代理                       │  │
│  │  - 数据库操作                      │  │
│  │  - 文件处理                        │  │
│  └───────────────────────────────────┘  │
│           │                              │
│           ▼                              │
│  ┌───────────────────────────────────┐ │
│  │  云服务                             │ │
│  │  - 数据库                           │ │
│  │  - 存储                             │ │
│  │  - 第三方 API                       │ │
│  └───────────────────────────────────┘ │
└─────────────────────────────────────────┘</code></pre>
        </div>

        <h2>🔒 安全机制</h2>

        <h3>1. Content Security Policy (CSP)</h3>
        <pre><code>// 在 iframe 中设置 CSP
const meta = document.createElement('meta');
meta.httpEquiv = 'Content-Security-Policy';
meta.content = `
  default-src 'self';
  script-src 'unsafe-inline' 'unsafe-eval';
  style-src 'unsafe-inline';
  img-src data: https:;
  connect-src https:;
`;
iframeDoc.head.appendChild(meta);</code></pre>

        <h3>2. 代码沙箱限制</h3>
        <div class="warning">
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li><strong>禁止访问父页面:</strong>不使用 allow-same-origin</li>
                <li><strong>限制网络请求:</strong>只能访问允许的域名</li>
                <li><strong>禁止本地存储:</strong>限制 localStorage、IndexedDB 的使用</li>
                <li><strong>超时机制:</strong>长时间运行的代码会被终止</li>
            </ul>
        </div>

        <h3>3. 代码审查和过滤</h3>
        <pre><code>// 简单的危险代码检测
function isDangerousCode(code) {
  const dangerousPatterns = [
    /eval\s*\(/,
    /Function\s*\(/,
    /document\.cookie/,
    /localStorage/,
    /XMLHttpRequest/,
    /fetch\s*\(/,
  ];
  
  return dangerousPatterns.some(pattern => pattern.test(code));
}

// 在注入代码前检查
if (isDangerousCode(userCode)) {
  throw new Error('代码包含潜在危险操作');
}</code></pre>

        <h2>📊 技术栈对比</h2>

        <table class="comparison-table">
            <thead>
                <tr>
                    <th>特性</th>
                    <th>CodePen</th>
                    <th>CodeSandbox</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><strong>核心技术</strong></td>
                    <td>iframe + srcdoc</td>
                    <td>iframe + 模块加载器 + Web Worker</td>
                </tr>
                <tr>
                    <td><strong>代码隔离</strong></td>
                    <td>iframe sandbox</td>
                    <td>iframe sandbox + CSP</td>
                </tr>
                <tr>
                    <td><strong>模块系统</strong></td>
                    <td>无(直接执行)</td>
                    <td>自定义模块加载器</td>
                </tr>
                <tr>
                    <td><strong>包管理</strong></td>
                    <td>外部 CDN 链接</td>
                    <td>npm 包自动加载</td>
                </tr>
                <tr>
                    <td><strong>代码转换</strong></td>
                    <td></td>
                    <td>Babel / esbuild</td>
                </tr>
                <tr>
                    <td><strong>框架支持</strong></td>
                    <td>手动引入</td>
                    <td>自动配置(React/Vue/Angular)</td>
                </tr>
                <tr>
                    <td><strong>构建工具</strong></td>
                    <td></td>
                    <td>Webpack / Vite / Parcel</td>
                </tr>
                <tr>
                    <td><strong>热更新</strong></td>
                    <td>简单刷新</td>
                    <td>HMR (Hot Module Replacement)</td>
                </tr>
                <tr>
                    <td><strong>Node.js 环境</strong></td>
                    <td>不支持</td>
                    <td>WebContainer (WASM)</td>
                </tr>
                <tr>
                    <td><strong>服务器端代码</strong></td>
                    <td>不支持</td>
                    <td>支持 (Express/Next.js)</td>
                </tr>
                <tr>
                    <td><strong>Serverless Functions</strong></td>
                    <td></td>
                    <td>支持 API/数据库/存储</td>
                </tr>
            </tbody>
        </table>

        <h2>💡 实现要点总结</h2>

        <div class="benefits" style="background: #e6f3ff; padding: 20px; border-radius: 8px; margin: 30px 0;">
            <h3>CodePen 实现要点:</h3>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li>✅ 使用 <code>iframe.srcdoc</code> 快速注入代码</li>
                <li>✅ 实时监听编辑器变化,自动更新预览</li>
                <li>✅ 使用 sandbox 属性限制代码权限</li>
                <li>✅ 简单直接,适合代码片段展示</li>
            </ul>

            <h3 style="margin-top: 30px;">CodeSandbox 实现要点:</h3>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li>✅ 自定义模块系统,模拟 Node.js 环境</li>
                <li>✅ 使用 Web Worker 进行代码转换,不阻塞主线程</li>
                <li>✅ 从 CDN 动态加载 npm 包</li>
                <li>✅ 支持多种构建工具和框架</li>
                <li>✅ 实现 HMR 提供更好的开发体验</li>
                <li>✅ 使用 Service Worker 缓存资源</li>
                <li><strong>WebContainer 技术</strong>:在浏览器中运行完整的 Node.js 环境</li>
                <li><strong>Serverless Functions</strong>:处理需要服务器端能力的操作</li>
                <li><strong>虚拟文件系统</strong>:使用 IndexedDB 持久化存储</li>
            </ul>
        </div>

        <h2>🎯 实际应用场景</h2>

        <div class="step">
            <span class="step-number">1</span>
            <strong>在线代码演示</strong>
            <p>在文档、博客中嵌入可运行的代码示例</p>
        </div>

        <div class="step">
            <span class="step-number">2</span>
            <strong>快速原型开发</strong>
            <p>快速测试想法,无需搭建本地环境</p>
        </div>

        <div class="step">
            <span class="step-number">3</span>
            <strong>代码面试</strong>
            <p>在线编程面试,实时查看代码执行结果</p>
        </div>

        <div class="step">
            <span class="step-number">4</span>
            <strong>教学工具</strong>
            <p>编程教育平台,学生可以直接运行代码</p>
        </div>

        <h2>⚠️ 注意事项</h2>

        <div class="warning">
            <h3>性能考虑</h3>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li>频繁更新 iframe 内容可能导致性能问题</li>
                <li>大量 npm 包会增加加载时间</li>
                <li>代码转换需要时间,考虑使用 Web Worker</li>
            </ul>
        </div>

        <div class="info">
            <h3>安全考虑</h3>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li>永远不要使用 <code>allow-same-origin</code> 除非必要</li>
                <li>限制网络请求的目标域名</li>
                <li>对用户代码进行审查和过滤</li>
                <li>设置代码执行超时机制</li>
                <li><strong>WebContainer 安全</strong>:限制文件系统访问范围,隔离进程</li>
                <li><strong>Serverless Functions 安全</strong>:限制资源使用,防止滥用,添加认证机制</li>
            </ul>
        </div>

        <h2>🆚 技术演进对比</h2>

        <div class="platform-comparison">
            <div class="codepen">
                <h3>传统方案 (CodePen 早期)</h3>
                <ul style="margin-left: 20px; margin-top: 10px;">
                    <li>✅ iframe + srcdoc</li>
                    <li>✅ 简单直接</li>
                    <li>❌ 无法运行 Node.js</li>
                    <li>❌ 无法使用构建工具</li>
                    <li>❌ 无法运行服务器端代码</li>
                </ul>
            </div>

            <div class="codesandbox">
                <h3>现代方案 (CodeSandbox 2024+)</h3>
                <ul style="margin-left: 20px; margin-top: 10px;">
                    <li>✅ iframe 隔离</li>
                    <li>✅ WebContainer (Node.js in WASM)</li>
                    <li>✅ Serverless Functions</li>
                    <li>✅ 完整的开发环境</li>
                    <li>✅ 支持全栈应用</li>
                </ul>
            </div>
        </div>

        <div class="success">
            <h3>技术栈总结</h3>
            <p><strong>现代浏览器代码沙箱的完整技术栈:</strong></p>
            <ul style="margin-left: 20px; margin-top: 10px;">
                <li><strong>前端隔离</strong>:iframe + sandbox 属性</li>
                <li><strong>Node.js 环境</strong>:WebContainer (WebAssembly)</li>
                <li><strong>文件系统</strong>:虚拟文件系统 (IndexedDB/MemoryFS)</li>
                <li><strong>模块系统</strong>:自定义模块加载器</li>
                <li><strong>代码转换</strong>:Babel / esbuild (Web Worker)</li>
                <li><strong>服务器功能</strong>:Serverless Functions</li>
                <li><strong>热更新</strong>:HMR (Hot Module Replacement)</li>
                <li><strong>安全</strong>:CSP + 代码审查 + 资源限制</li>
            </ul>
        </div>

        <div style="text-align: center; margin-top: 40px; padding-top: 20px; border-top: 2px solid #eee; color: #666;">
            <p>💡 <strong>总结</strong>:浏览器端代码沙箱通过 iframe 隔离、模块系统、代码转换等技术,实现了在浏览器中安全运行用户代码的能力。</p>
        </div>
    </div>
</body>
</html>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions