Skip to content

Commit 9d481c8

Browse files
committed
Merge branch 'main' into feature/example-ui-redesign
2 parents 7f14bfd + e6494aa commit 9d481c8

16 files changed

Lines changed: 1236 additions & 44 deletions

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.2.9] - 2026-02-08
9+
10+
### Added
11+
12+
- **`browser` field support in module resolution:** npm packages with a `browser` field in package.json now resolve to their browser-specific entry point. Supports both string form (`"browser": "lib/browser/index.js"`) and object form (`"browser": {"./lib/node.js": "./lib/browser.js"}`). This fixes compatibility with packages like `depd`, `debug`, and others that provide browser-optimized versions.
13+
14+
### Fixed
15+
16+
- **Safari Express crash:** Fixed `callSite.getFileName is not a function` error when running Express in Safari. The `depd` package (an Express dependency) uses V8-specific `Error.captureStackTrace` APIs that don't exist in WebKit. By respecting depd's `"browser"` field, the no-op browser version is now loaded instead.
17+
- **`Error.captureStackTrace` polyfill improvements:** Added `Error.stackTraceLimit` default, `.stack` getter interception on `Error.prototype` for lazy `prepareStackTrace` evaluation, re-entrancy protection, and error logging instead of silent fallback.
18+
819
## [0.2.8] - 2026-02-07
920

1021
### Added

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ fs.copyFileSync(getServiceWorkerPath(), './public/__sw__.js');
315315

316316
| Feature | almostnode | WebContainers |
317317
|---------|-----------|---------------|
318-
| **Bundle Size** | ~50KB | ~2MB |
318+
| **Bundle Size** | ~250KB gzipped | ~2MB |
319319
| **Startup Time** | Instant | 2-5 seconds |
320320
| **Execution Model** | Main thread or Web Worker (configurable) | Web Worker isolates |
321321
| **Shell** | `just-bash` (POSIX subset) | Full Linux kernel |

docs/api-reference.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
<a href="./nextjs-guide.html">Next.js</a>
4646
<a href="./vite-guide.html">Vite</a>
4747
</div>
48+
<div class="sidebar-group">
49+
<div class="sidebar-label">Tutorials</div>
50+
<a href="./tutorial-editor.html">Editor + Preview</a>
51+
</div>
4852
<div class="sidebar-group">
4953
<div class="sidebar-label">Reference</div>
5054
<a href="./api-reference.html" class="active">API Reference</a>
@@ -305,13 +309,34 @@ <h2>NextDevServer</h2>
305309
<p>A virtual Next.js dev server that supports both App Router and Pages Router, CSS Modules, API routes, dynamic routes, route groups, and HMR via React Refresh.</p>
306310
<p>Import from <code>almostnode/next</code>.</p>
307311

312+
<h3>Methods</h3>
313+
<table>
314+
<thead><tr><th>Method</th><th>Signature</th><th>Description</th></tr></thead>
315+
<tbody>
316+
<tr><td><code>start</code></td><td><code>(): void</code></td><td>Start file watching for HMR. <strong>Required</strong> before HMR updates will fire.</td></tr>
317+
<tr><td><code>stop</code></td><td><code>(): void</code></td><td>Stop the server and clean up file watchers</td></tr>
318+
<tr><td><code>setHMRTarget</code></td><td><code>(window: Window): void</code></td><td>Set the iframe <code>contentWindow</code> as the HMR update target. Call inside the iframe's <code>onload</code> handler.</td></tr>
319+
<tr><td><code>handleRequest</code></td><td><code>(method, url, headers, body): Promise&lt;Response&gt;</code></td><td>Handle an HTTP request (used internally by the Service Worker bridge)</td></tr>
320+
</tbody>
321+
</table>
322+
323+
<h3>Events</h3>
324+
<table>
325+
<thead><tr><th>Event</th><th>Payload</th><th>Description</th></tr></thead>
326+
<tbody>
327+
<tr><td><code>'hmr-update'</code></td><td><code>{ type: 'update' | 'full-reload', path: string, timestamp: number }</code></td><td>Fired when a VFS file changes. JS/CSS files get <code>'update'</code>, others get <code>'full-reload'</code>.</td></tr>
328+
<tr><td><code>'listening'</code></td><td><code>port: number</code></td><td>Fired when <code>start()</code> is called</td></tr>
329+
</tbody>
330+
</table>
331+
308332
<!-- ViteDevServer -->
309333
<h2>ViteDevServer</h2>
310334
<div class="method-sig">
311335
<span class="kw">new</span> <span class="fn">ViteDevServer</span>(<span class="ty">vfs</span>: VirtualFS)
312336
</div>
313337
<p>A virtual Vite dev server with React support, JSX/TSX transforms, npm module resolution, and HMR via React Refresh.</p>
314338
<p>Import from <code>almostnode/vite</code>.</p>
339+
<p>Shares the same <code>start()</code>, <code>stop()</code>, <code>setHMRTarget()</code>, and <code>handleRequest()</code> methods as <code>NextDevServer</code>. Emits the same <code>'hmr-update'</code> event.</p>
315340

316341
<!-- Utility -->
317342
<h2>Utility Functions</h2>

docs/core-concepts.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
<a href="./nextjs-guide.html">Next.js</a>
4646
<a href="./vite-guide.html">Vite</a>
4747
</div>
48+
<div class="sidebar-group">
49+
<div class="sidebar-label">Tutorials</div>
50+
<a href="./tutorial-editor.html">Editor + Preview</a>
51+
</div>
4852
<div class="sidebar-group">
4953
<div class="sidebar-label">Reference</div>
5054
<a href="./api-reference.html">API Reference</a>

docs/index.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
<a href="./nextjs-guide.html">Next.js</a>
4646
<a href="./vite-guide.html">Vite</a>
4747
</div>
48+
<div class="sidebar-group">
49+
<div class="sidebar-label">Tutorials</div>
50+
<a href="./tutorial-editor.html">Editor + Preview</a>
51+
</div>
4852
<div class="sidebar-group">
4953
<div class="sidebar-label">Reference</div>
5054
<a href="./api-reference.html">API Reference</a>
@@ -133,7 +137,7 @@ <h2>Comparison with WebContainers</h2>
133137
<th>almostnode</th>
134138
<th>WebContainers</th>
135139
</tr>
136-
<tr><td>Bundle Size</td><td>~50KB</td><td>~2MB</td></tr>
140+
<tr><td>Bundle Size</td><td>~250KB gzipped</td><td>~2MB</td></tr>
137141
<tr><td>Startup Time</td><td>Instant</td><td>2-5 seconds</td></tr>
138142
<tr><td>Execution Model</td><td>Main thread or Web Worker</td><td>Web Worker isolates</td></tr>
139143
<tr><td>Shell</td><td><code>just-bash</code> (POSIX subset)</td><td>Full Linux kernel</td></tr>
@@ -200,6 +204,7 @@ <h2>Next Steps</h2>
200204
<li><a href="./security.html">Security &amp; Sandbox</a> — cross-origin isolation, security modes, and service worker setup</li>
201205
<li><a href="./nextjs-guide.html">Next.js Guide</a> — run a full Next.js dev server with App Router, HMR, and CSS Modules</li>
202206
<li><a href="./vite-guide.html">Vite Guide</a> — set up Vite with React and hot module replacement</li>
207+
<li><a href="./tutorial-editor.html">Tutorial: Editor + Preview</a> — build a file editor with live Next.js preview and cross-origin sandbox</li>
203208
<li><a href="./api-reference.html">API Reference</a> — full method signatures for every class and function</li>
204209
</ul>
205210

docs/nextjs-guide.html

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
<a href="./nextjs-guide.html" class="active">Next.js</a>
4646
<a href="./vite-guide.html">Vite</a>
4747
</div>
48+
<div class="sidebar-group">
49+
<div class="sidebar-label">Tutorials</div>
50+
<a href="./tutorial-editor.html">Editor + Preview</a>
51+
</div>
4852
<div class="sidebar-group">
4953
<div class="sidebar-label">Reference</div>
5054
<a href="./api-reference.html">API Reference</a>
@@ -181,20 +185,28 @@ <h2>CSS Modules</h2>
181185
<p>Classes are scoped with a hash to prevent collisions between components.</p>
182186

183187
<h2>Hot Module Replacement</h2>
184-
<p>The dev server supports HMR through React Refresh. When you change a file in the VFS, the server detects it and pushes updates to the browser without a full page reload:</p>
185-
<pre><code><span class="cm">// Initial page</span>
186-
vfs<span class="op">.</span><span class="fn">writeFileSync</span><span class="op">(</span><span class="str">'/app/page.tsx'</span><span class="op">,</span> <span class="str">`
187-
export default function Home() {
188-
return &lt;h1&gt;Version 1&lt;/h1&gt;;
189-
}
190-
`</span><span class="op">);</span>
191-
192-
<span class="cm">// Later, update the file — HMR kicks in automatically</span>
188+
<p>The dev server supports HMR through React Refresh. Two things are required for HMR to work:</p>
189+
<ol>
190+
<li>Call <code>devServer.start()</code> — this enables file watching on the VFS</li>
191+
<li>Call <code>devServer.setHMRTarget(iframe.contentWindow)</code> — this tells the server where to send updates via <code>postMessage</code></li>
192+
</ol>
193+
<p>Once both are set up, writing to the VFS triggers HMR automatically:</p>
194+
<pre><code><span class="kw">const</span> devServer <span class="op">=</span> <span class="kw">new</span> <span class="fn">NextDevServer</span><span class="op">(</span>vfs<span class="op">,</span> <span class="op">{</span> port<span class="op">:</span> <span class="num">3000</span><span class="op">,</span> root<span class="op">:</span> <span class="str">'/'</span> <span class="op">});</span>
195+
devServer<span class="op">.</span><span class="fn">start</span><span class="op">();</span> <span class="cm">// Required: enables file watching for HMR</span>
196+
197+
<span class="cm">// After bridge setup and iframe load:</span>
198+
devServer<span class="op">.</span><span class="fn">setHMRTarget</span><span class="op">(</span>iframe<span class="op">.</span>contentWindow<span class="op">);</span> <span class="cm">// Required: HMR delivery target</span>
199+
200+
<span class="cm">// Now updating a file triggers HMR automatically</span>
193201
vfs<span class="op">.</span><span class="fn">writeFileSync</span><span class="op">(</span><span class="str">'/app/page.tsx'</span><span class="op">,</span> <span class="str">`
194202
export default function Home() {
195203
return &lt;h1&gt;Version 2&lt;/h1&gt;;
196204
}
197205
`</span><span class="op">);</span></code></pre>
206+
<div class="callout">
207+
<div class="callout-title">Important</div>
208+
<p>Without <code>devServer.start()</code>, the server won't watch the VFS for changes and HMR updates won't fire. This is the most common cause of HMR not working.</p>
209+
</div>
198210

199211
<h2>Configuration</h2>
200212
<p>You can provide a <code>next.config.js</code> for path aliases and other options:</p>

docs/security.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
<a href="./nextjs-guide.html">Next.js</a>
4646
<a href="./vite-guide.html">Vite</a>
4747
</div>
48+
<div class="sidebar-group">
49+
<div class="sidebar-label">Tutorials</div>
50+
<a href="./tutorial-editor.html">Editor + Preview</a>
51+
</div>
4852
<div class="sidebar-group">
4953
<div class="sidebar-label">Reference</div>
5054
<a href="./api-reference.html">API Reference</a>

0 commit comments

Comments
 (0)