fix(windows): externalize @ngrok/ngrok in Node server bundle#1013
Closed
scarson wants to merge 1 commit into
Closed
fix(windows): externalize @ngrok/ngrok in Node server bundle#1013scarson wants to merge 1 commit into
scarson wants to merge 1 commit into
Conversation
The bundled native addon from @ngrok/ngrok emits a separate .node file alongside the JS output, which makes bun build refuse --outfile with "cannot write multiple output files without an output directory". The build script has been silently broken on Windows since v0.15.12 when ngrok was added for pair-agent tunneling (garrytan#815). Windows users see fresh browse.exe/find-browse.exe after ./setup, but server-node.mjs stops updating — producing a Frankenstein install where a current CLI talks to a v0.15.11-era server over HTTP. Missing features: browser data platform (v0.16.0), cookie origin pinning + audit log (v0.16.4), ux-audit + snapshot heatmap (v0.17.0). Fix: externalize @ngrok/ngrok the same way playwright and bun:sqlite are already externalized. @ngrok/ngrok is used exclusively via dynamic import (`await import('@ngrok/ngrok')` in server.ts) so runtime semantics are unchanged — Node resolves it from node_modules on first pair-agent tunnel. Bundle drops back to a single file. Verified on clean clone: build succeeds, bundle loads under Node, v0.17 server features present.
Owner
|
Closing — duplicate of several PRs fixing the same @ngrok/ngrok Windows build issue. We'll pick the best approach and merge separately. Thank you for the contribution! |
garrytan
added a commit
that referenced
this pull request
Apr 16, 2026
… Windows @ngrok/ngrok has a native .node addon that causes `bun build --outfile` to fail with "cannot write multiple output files without an output directory". Externalize it alongside the existing runtime deps (playwright, diff, bun:sqlite), matching the exact pattern used for every other dynamic import in server.ts. Adds a policy comment explaining when to extend the externals list so the next native dep doesn't repeat this failure. Two community contributors independently converged on this fix: - @tomasmontbrun-hash (#1019) - @scarson (#1013) Also fixes issues #1010 and #960. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
garrytan
added a commit
that referenced
this pull request
Apr 16, 2026
Fixes shipped in this version: - Externalize @ngrok/ngrok so the Node server bundle builds on Windows (PRs #1019, #1013; issues #1010, #960) - Shell precedence fix so build/test failures no longer exit 0 in CI - Build validation test for server-node.mjs - Windows setup verifies @ngrok/ngrok native binary is loadable Credit: @tomasmontbrun-hash (#1019), @scarson (#1013). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
Owner
|
Thanks @scarson — landed your fix in #1024 (v0.18.0.1). Your diagnosis was particularly sharp: you caught that the bug had been shipping silently since v0.15.12 (which explained why Windows users were running a stale v0.15.11-era server bundle). That was the insight that motivated adding the root-cause fix — the Closing in favor of #1024, which credits you in the CHANGELOG and commit body. Great work. |
garrytan
added a commit
that referenced
this pull request
Apr 16, 2026
…1024) * fix(browse): externalize @ngrok/ngrok so Node server bundle builds on Windows @ngrok/ngrok has a native .node addon that causes `bun build --outfile` to fail with "cannot write multiple output files without an output directory". Externalize it alongside the existing runtime deps (playwright, diff, bun:sqlite), matching the exact pattern used for every other dynamic import in server.ts. Adds a policy comment explaining when to extend the externals list so the next native dep doesn't repeat this failure. Two community contributors independently converged on this fix: - @tomasmontbrun-hash (#1019) - @scarson (#1013) Also fixes issues #1010 and #960. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(package.json): subshell cleanup so || true stops masking build/test failures Shell operator precedence trap in both the build and test scripts: cmd1 && cmd2 && ... && rm -f .*.bun-build || true bun test ... && bun run slop:diff 2>/dev/null || true The trailing `|| true` was intended to suppress cleanup errors, but it applies to the entire `&&` chain — so ANY failure (including the build-node-server.sh failure that broke Windows installs since v0.15.12) silently exits 0. CI ran the build, the build failed, and CI reported green. Wrap the cleanup/slop-diff commands in subshells so `|| true` only scopes to the intended step: ... && (rm -f .*.bun-build || true) bun test ... && (bun run slop:diff 2>/dev/null || true) Verified: `bash -c 'false && echo A && rm -f X || true'` exits 0 (old, broken), `bash -c 'false && echo A && (rm -f X || true)'` exits 1 (new, correct). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(browse): add build validation test for server-node.mjs Two assertions: 1. `node --check` passes on the built `server-node.mjs` (valid ES module syntax). This catches regressions where the post-processing steps (perl regex replacements) corrupt the bundle. 2. No inlined `@ngrok/ngrok` module identifiers (ngrok_napi, platform- specific binding packages). Verifies the --external flag actually kept it external. Skips gracefully when `browse/dist/server-node.mjs` is missing — the dist dir is gitignored, so a fresh clone + `bun test` without a prior build is a valid state, not a failure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(setup): verify @ngrok/ngrok can load on Windows Mirror the existing Playwright verification step. Since @ngrok/ngrok is now externalized in server-node.mjs (resolved at runtime from node_modules), confirm the platform-specific native binary (@ngrok/ngrok-win32-x64-msvc et al.) is installed at setup time rather than surfacing the failure later when the user runs /pair-agent. Same fallback pattern: if `node -e "require('@ngrok/ngrok')"` fails, fall back to `npm install --no-save @ngrok/ngrok` to pull the missing binary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump to v0.18.0.1 for ngrok Windows fix + CI error-propagation Fixes shipped in this version: - Externalize @ngrok/ngrok so the Node server bundle builds on Windows (PRs #1019, #1013; issues #1010, #960) - Shell precedence fix so build/test failures no longer exit 0 in CI - Build validation test for server-node.mjs - Windows setup verifies @ngrok/ngrok native binary is loadable Credit: @tomasmontbrun-hash (#1019), @scarson (#1013). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mathiasmora2232
pushed a commit
to mathiasmora2232/gstack
that referenced
this pull request
May 30, 2026
…arrytan#1024) * fix(browse): externalize @ngrok/ngrok so Node server bundle builds on Windows @ngrok/ngrok has a native .node addon that causes `bun build --outfile` to fail with "cannot write multiple output files without an output directory". Externalize it alongside the existing runtime deps (playwright, diff, bun:sqlite), matching the exact pattern used for every other dynamic import in server.ts. Adds a policy comment explaining when to extend the externals list so the next native dep doesn't repeat this failure. Two community contributors independently converged on this fix: - @tomasmontbrun-hash (garrytan#1019) - @scarson (garrytan#1013) Also fixes issues garrytan#1010 and garrytan#960. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(package.json): subshell cleanup so || true stops masking build/test failures Shell operator precedence trap in both the build and test scripts: cmd1 && cmd2 && ... && rm -f .*.bun-build || true bun test ... && bun run slop:diff 2>/dev/null || true The trailing `|| true` was intended to suppress cleanup errors, but it applies to the entire `&&` chain — so ANY failure (including the build-node-server.sh failure that broke Windows installs since v0.15.12) silently exits 0. CI ran the build, the build failed, and CI reported green. Wrap the cleanup/slop-diff commands in subshells so `|| true` only scopes to the intended step: ... && (rm -f .*.bun-build || true) bun test ... && (bun run slop:diff 2>/dev/null || true) Verified: `bash -c 'false && echo A && rm -f X || true'` exits 0 (old, broken), `bash -c 'false && echo A && (rm -f X || true)'` exits 1 (new, correct). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(browse): add build validation test for server-node.mjs Two assertions: 1. `node --check` passes on the built `server-node.mjs` (valid ES module syntax). This catches regressions where the post-processing steps (perl regex replacements) corrupt the bundle. 2. No inlined `@ngrok/ngrok` module identifiers (ngrok_napi, platform- specific binding packages). Verifies the --external flag actually kept it external. Skips gracefully when `browse/dist/server-node.mjs` is missing — the dist dir is gitignored, so a fresh clone + `bun test` without a prior build is a valid state, not a failure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(setup): verify @ngrok/ngrok can load on Windows Mirror the existing Playwright verification step. Since @ngrok/ngrok is now externalized in server-node.mjs (resolved at runtime from node_modules), confirm the platform-specific native binary (@ngrok/ngrok-win32-x64-msvc et al.) is installed at setup time rather than surfacing the failure later when the user runs /pair-agent. Same fallback pattern: if `node -e "require('@ngrok/ngrok')"` fails, fall back to `npm install --no-save @ngrok/ngrok` to pull the missing binary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump to v0.18.0.1 for ngrok Windows fix + CI error-propagation Fixes shipped in this version: - Externalize @ngrok/ngrok so the Node server bundle builds on Windows (PRs garrytan#1019, garrytan#1013; issues garrytan#1010, garrytan#960) - Shell precedence fix so build/test failures no longer exit 0 in CI - Build validation test for server-node.mjs - Windows setup verifies @ngrok/ngrok native binary is loadable Credit: @tomasmontbrun-hash (garrytan#1019), @scarson (garrytan#1013). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Windows Node-compat server bundle build (
browse/scripts/build-node-server.sh) has been silently failing since v0.15.12 with:Root cause:
@ngrok/ngrok(added in #815 for pair-agent tunneling) pulls in a ~10 MB native.nodeaddon as a build asset.bun build --outfilerefuses any build that emits more than one file, so the script exits 1, leaves the oldserver-node.mjsin place, and the rest ofbun run buildcontinues. macOS/Linux users don't notice because theirbrowsebinary runs the server directly under Bun — but on Windows,browse.exespawnsnode server-node.mjs(Bun can't drive Playwright's Chromium on Windows: oven-sh/bun#4253, oven-sh/bun#9911), so a stale bundle is load-bearing.Net effect on Windows: a current
browse.exetalks to a v0.15.11-era server over HTTP after./setup. Missing features:media,data,download,scrape,archive, network capture,GET /file)ux-auditcommand +snapshot -H/--heatmap/pair-agentFix
One-line: externalize
@ngrok/ngrokalongside the existingplaywright/playwright-core/diff/bun:sqliteexternals. Ngrok is used exclusively via dynamic import inserver.ts:…so runtime semantics are unchanged — Node resolves it from
node_moduleson first/pair-agenttunnel, which is identical to howplaywrightalready works. Bundle drops back to a single file.Test plan
bun install && bash browse/scripts/build-node-server.shon a clean clone → builds successfully, emits onlyserver-node.mjsnode --input-type=module -e "import('./server-node.mjs')"loads without errors and starts the HTTP listenerux-audit,heatmap, content-security envelopes, 21 matches)/pair-agenttunnel create (not tested — need a paying ngrok account; relying on the fact thatplaywrightexternalization uses the same mechanism)🤖 Generated with Claude Code