[PR #293] [CLOSED] fix: stub node:async_hooks in client builds to prevent Rollup errors #453

Closed
opened 2026-05-06 12:39:52 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/293
Author: @Divkix
Created: 3/6/2026
Status: Closed

Base: mainHead: fix/async-hooks-browser-stub


📝 Commits (4)

  • 0108ac0 fix: stub node:async_hooks in client builds to prevent Rollup errors
  • 2454868 fix: address PR #293 review — extensionless shim path + tests
  • ab57ce5 Merge branch 'cloudflare:main' into fix/async-hooks-browser-stub
  • f07748c fix(tests): use dynamic import instead of require in async_hooks tests

📊 Changes

3 files changed (+101 additions, -3 deletions)

View changed files

📝 packages/vinext/src/index.ts (+12 -3)
packages/vinext/src/shims/async-hooks-browser.ts (+17 -0)
📝 tests/shims.test.ts (+72 -0)

📄 Description

Summary

  • Shim files import AsyncLocalStorage from node:async_hooks. When resolved into the client (browser) build, Vite externalizes node:async_hooks to __vite-browser-external — an empty stub with no named exports. This causes Rollup named-export failures.
  • Server environments (rsc, ssr) use real node:async_hooks natively via nodejs_compat. Only the client environment needs a stub.
  • Adds a browser-safe AsyncLocalStorage stub at packages/vinext/src/shims/async-hooks-browser.ts with no-op methods (run() passes through, getStore() returns undefined — matching existing _als.getStore() ?? _fallbackState patterns in shims).
  • Extends the resolveId filter to match node:async_hooks and redirect to the stub only when this.environment.name === "client".

Reproduction

  1. Invalidate build cache (e.g., change chunk graph or delete .vite/)
  2. Run bun run build on an App Router project with shims that import AsyncLocalStorage
  3. Build fails with Rollup error: "AsyncLocalStorage" is not exported by "__vite-browser-external"

Fix

Two changes:

  1. New file: packages/vinext/src/shims/async-hooks-browser.ts — browser-safe no-op AsyncLocalStorage class
  2. Modified: packages/vinext/src/index.ts — extended resolveId hook to redirect node:async_hooks → stub in client environment only

Test plan

  • Clean build succeeds without Rollup named-export errors
  • The browser stub's run() correctly passes through the callback return value
  • Server environments (rsc, ssr) still use real node:async_hooks — no behavioral change
  • biome check passes on all changed files

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/293 **Author:** [@Divkix](https://github.com/Divkix) **Created:** 3/6/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/async-hooks-browser-stub` --- ### 📝 Commits (4) - [`0108ac0`](https://github.com/cloudflare/vinext/commit/0108ac00f85ce9468b869cff4cc356044086cac4) fix: stub node:async_hooks in client builds to prevent Rollup errors - [`2454868`](https://github.com/cloudflare/vinext/commit/24548686dabab9aaa0a45a4fabc0c2de07e444b5) fix: address PR #293 review — extensionless shim path + tests - [`ab57ce5`](https://github.com/cloudflare/vinext/commit/ab57ce50582c061397b16d9695a64032f54fd793) Merge branch 'cloudflare:main' into fix/async-hooks-browser-stub - [`f07748c`](https://github.com/cloudflare/vinext/commit/f07748c96ee33e842d8c572382e20bbc4144bf73) fix(tests): use dynamic import instead of require in async_hooks tests ### 📊 Changes **3 files changed** (+101 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/index.ts` (+12 -3) ➕ `packages/vinext/src/shims/async-hooks-browser.ts` (+17 -0) 📝 `tests/shims.test.ts` (+72 -0) </details> ### 📄 Description ## Summary - Shim files import `AsyncLocalStorage` from `node:async_hooks`. When resolved into the **client** (browser) build, Vite externalizes `node:async_hooks` to `__vite-browser-external` — an empty stub with no named exports. This causes **Rollup named-export failures**. - Server environments (rsc, ssr) use real `node:async_hooks` natively via `nodejs_compat`. Only the client environment needs a stub. - Adds a browser-safe `AsyncLocalStorage` stub at `packages/vinext/src/shims/async-hooks-browser.ts` with no-op methods (`run()` passes through, `getStore()` returns `undefined` — matching existing `_als.getStore() ?? _fallbackState` patterns in shims). - Extends the `resolveId` filter to match `node:async_hooks` and redirect to the stub **only** when `this.environment.name === "client"`. ## Reproduction 1. Invalidate build cache (e.g., change chunk graph or delete `.vite/`) 2. Run `bun run build` on an App Router project with shims that import `AsyncLocalStorage` 3. Build fails with Rollup error: `"AsyncLocalStorage" is not exported by "__vite-browser-external"` ## Fix Two changes: 1. **New file**: `packages/vinext/src/shims/async-hooks-browser.ts` — browser-safe no-op `AsyncLocalStorage` class 2. **Modified**: `packages/vinext/src/index.ts` — extended `resolveId` hook to redirect `node:async_hooks` → stub in client environment only ## Test plan - [x] Clean build succeeds without Rollup named-export errors - [x] The browser stub's `run()` correctly passes through the callback return value - [x] Server environments (rsc, ssr) still use real `node:async_hooks` — no behavioral change - [x] `biome check` passes on all changed files --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 12:39:52 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#453
No description provided.