[builders] Fix Node.js builtin imports being relativized in step bundles#1644
Conversation
The esbuild fallback resolver introduced in 3308701 did not check esbuildResult.external, causing builtins like 'crypto' and 'node:path' to be treated as project-local files and rewritten to broken relative paths (e.g. '../../../../../../crypto'), failing downstream webpack builds.
🦋 Changeset detectedLatest commit: 87f9a4c The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📊 Benchmark Results
workflow with no steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) workflow with 1 step💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) workflow with 10 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) workflow with 25 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) workflow with 50 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) Promise.all with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) Promise.all with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) Promise.all with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express Promise.race with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express Promise.race with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) Promise.race with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) workflow with 10 sequential data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express workflow with 25 sequential data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) workflow with 50 sequential data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express workflow with 10 concurrent data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express workflow with 25 concurrent data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) workflow with 50 concurrent data payload steps (10KB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) Stream Benchmarks (includes TTFB metrics)workflow with stream💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) stream pipeline with 5 transform steps (1MB)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) 10 parallel streams (1MB each)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) fan-out fan-in 10 streams (1MB each)💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) SummaryFastest Framework by WorldWinner determined by most benchmark wins
Fastest World by FrameworkWinner determined by most benchmark wins
Column Definitions
Worlds:
❌ Some benchmark jobs failed:
Check the workflow run for details. |
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests▲ Vercel Production (2 failed)vite (2 failed):
🌍 Community Worlds (60 failed)mongodb-dev (1 failed):
redis-dev (1 failed):
turso-dev (1 failed):
turso (57 failed):
Details by Category❌ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
❌ 🌍 Community Worlds
✅ 📋 Other
❌ Some E2E test jobs failed:
Check the workflow run for details. |
There was a problem hiding this comment.
Pull request overview
Fixes a regression in the @workflow/builders SWC+esbuild plugin where Node.js builtin modules (e.g. crypto, node:path) could be misclassified as project-local paths during the esbuild fallback resolution path, causing them to be rewritten into invalid relative specifiers in step bundles.
Changes:
- Prevent builtin/external specifiers from being treated as “project-local” during the esbuild fallback resolver by checking
!esbuildResult.external. - Add a test asserting Node.js builtin imports remain bare specifiers (not relativized) in step bundle output.
- Add a patch changeset for
@workflow/builders.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
packages/builders/src/swc-esbuild-plugin.ts |
Avoids relativizing esbuild-resolved externals (covers Node.js builtins) when enhanced-resolve fails. |
packages/builders/src/swc-esbuild-plugin.test.ts |
Adds coverage to ensure crypto and node:path stay as bare import specifiers in bundled output. |
.changeset/fix-builtin-externalize.md |
Publishes the fix as a patch release note for @workflow/builders. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
crypto,node:path, etc.) were incorrectly treated as project-local files by the esbuild fallback resolver, causing them to be rewritten to broken relative paths like../../../../../../crypto!esbuildResult.externalcheck so modules that esbuild already considers external (builtins) are not relativizedcryptoandnode:pathstyle builtin importsBug
The esbuild fallback resolver added in 3308701 for path alias support did not check
esbuildResult.external. When a builtin likecryptois encountered:enhancedResolvefails (builtins aren't innode_modules)build.resolve()succeeds — esbuild resolves builtins as externalisProjectLocalFilecheck passed because the path doesn't contain/node_modules/shouldMakeRelative = true, andrelative(outdir, 'crypto')produces../../../../../../cryptoModule not found: Can't resolve '../../../../../../crypto'