Skills Development Building A Browser IDE With WebContainers

Building A Browser IDE With WebContainers

v20260423
stackblitz-core-workflow-a
This workflow details how to build a complete, browser-based Integrated Development Environment (IDE). Using WebContainers, it integrates key components like a file explorer, Monaco editor, integrated terminal, and live preview. This architecture is crucial for developing interactive coding playgrounds, educational web tools, or embedding robust development sandboxes into existing web applications.
Get Skill
124 downloads
Overview

StackBlitz Core Workflow A: Browser IDE

Overview

Build a complete browser-based IDE using WebContainers: file explorer, code editor (Monaco/CodeMirror), integrated terminal (xterm.js + jsh), and live preview iframe. This is the architecture behind bolt.new.

Instructions

Step 1: HTML Layout

<div id="app">
  <div id="file-tree"></div>
  <div id="editor"></div>
  <div id="terminal"></div>
  <iframe id="preview"></iframe>
</div>

Step 2: Boot and Mount Project

import { WebContainer, FileSystemTree } from '@webcontainer/api';

const files: FileSystemTree = {
  'package.json': {
    file: { contents: JSON.stringify({
      name: 'playground', type: 'module',
      scripts: { dev: 'vite' },
      dependencies: { vite: '^5.0.0' },
    }) },
  },
  'index.html': {
    file: { contents: '<!DOCTYPE html><html><body><div id="app"></div><script type="module" src="/src/main.js"></script></body></html>' },
  },
  src: { directory: {
    'main.js': { file: { contents: 'document.getElementById("app").innerHTML = "<h1>Hello!</h1>";' } },
  }},
};

const wc = await WebContainer.boot();
await wc.mount(files);

Step 3: File Tree with Live Updates

async function renderFileTree(path = '/') {
  const entries = await wc.fs.readdir(path, { withFileTypes: true });
  const tree = document.getElementById('file-tree')!;

  for (const entry of entries) {
    if (entry.name === 'node_modules') continue;
    const fullPath = `${path}${path === '/' ? '' : '/'}${entry.name}`;
    const el = document.createElement('div');
    el.textContent = entry.isDirectory() ? `📁 ${entry.name}` : `📄 ${entry.name}`;
    el.onclick = async () => {
      if (!entry.isDirectory()) {
        const content = await wc.fs.readFile(fullPath, 'utf-8');
        editor.setValue(content); // Monaco editor
        currentFile = fullPath;
      }
    };
    tree.appendChild(el);
  }
}

Step 4: Save Editor Changes to WebContainer

let currentFile = '/src/main.js';

// Monaco editor onChange
editor.onDidChangeModelContent(async () => {
  const content = editor.getValue();
  await wc.fs.writeFile(currentFile, content);
  // Vite HMR will auto-reload the preview
});

Step 5: Terminal + Preview

// Terminal
const jsh = await wc.spawn('jsh', { terminal: { cols: 80, rows: 12 } });
jsh.output.pipeTo(new WritableStream({
  write(data) { terminal.write(data); },
}));

// Install and start dev server
const install = await wc.spawn('npm', ['install']);
await install.exit;
await wc.spawn('npm', ['run', 'dev']);

// Preview iframe
wc.on('server-ready', (port, url) => {
  document.getElementById('preview')!.src = url;
});

Error Handling

ErrorCauseSolution
Preview blankServer not ready yetWait for server-ready event
HMR not workingVite not runningCheck npm install succeeded
File tree emptyMount failedVerify FileSystemTree structure

Resources

Next Steps

For embedding and sharing projects, see stackblitz-core-workflow-b.

Info
Category Development
Name stackblitz-core-workflow-a
Version v20260423
Size 3.82KB
Updated At 2026-04-28
Language