Skip to content

fix(nest): stop declaring require twice in the CommonJS steps bundle - #4144

Open
torsello wants to merge 2 commits into
vercel:mainfrom
torsello:fix/nest-cjs-duplicate-require
Open

fix(nest): stop declaring require twice in the CommonJS steps bundle#4144
torsello wants to merge 2 commits into
vercel:mainfrom
torsello:fix/nest-cjs-duplicate-require

Conversation

@torsello

@torsello torsello commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #3778.

workflow-nest build --module commonjs writes a steps bundle that declares require twice, so importing it throws SyntaxError: Identifier 'require' has already been declared. The build reports success, so the failure surfaces later and indirectly — the flow route answers 500 and the run stays pending.

#rewriteStepsBundleForCjs prepends its own createRequire shim, but createStepsBundle already emits an ESM interop banner declaring the same binding. Nest passes bundleFinalOutput: false, so skipEsmRequireBanner stays false and the banner is always there.

The shim is redundant, so this drops it. Skipping the banner instead — the fix the issue suggests — would also drop __filename/__dirname, which createStepsBundle explicitly warns against in its JSDoc.

How did you test your changes?

Built workbench/nest with --module commonjs, before and after.

Before — build succeeds, bundle does not parse:

$ node packages/nest/dist/cli.js build --module commonjs --dirs src/workflows
✓ Compiled workflows in 1.0s (152 steps, 164 workflows)

$ sed -n '1,8p' .nestjs/workflow/steps.mjs
import { createRequire as __bundled_createRequire } from 'node:module';
const require = __bundled_createRequire(import.meta.url);
// biome-ignore-all lint: generated file
/* eslint-disable */
import { createRequire as __createRequire } from "node:module";
...
var require = __createRequire(import.meta.url);

$ node --check .nestjs/workflow/steps.mjs
SyntaxError: Identifier 'require' has already been declared

After — one declaration, parses clean:

$ sed -n '1,8p' .nestjs/workflow/steps.mjs
// biome-ignore-all lint: generated file
/* eslint-disable */
import { createRequire as __createRequire } from "node:module";
import { fileURLToPath as __fileURLToPath } from "node:url";
import { dirname as __pathDirname } from "node:path";
var require = __createRequire(import.meta.url);
var __filename = __fileURLToPath(import.meta.url);
var __dirname = __pathDirname(__filename);

$ grep -cE '(const|var|let) require =' .nestjs/workflow/steps.mjs
1

$ node --check .nestjs/workflow/steps.mjs   # exits 0

__filename/__dirname are still shimmed, since the banner is the one providing them.

Importing the bundle in this workbench then fails on MODULE_NOT_FOUND for ../../example/workflows/*.js — those live outside the app's src/, so they never land in its dist/. That is the shared-workbench layout, unrelated to this change; without the fix the bundle never parses far enough to attempt resolution at all.

pnpm --filter @workflow/nest test passes (35 tests), biome check is clean on the touched file.

@torsello
torsello requested a review from a team as a code owner September 12, 2026 11:11
@changeset-bot

changeset-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f22da80

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@workflow/nest Patch
workflow Patch
@workflow/world-testing Patch
@workflow/core Patch
@workflow/builders Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/web Patch
@workflow/astro Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch

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

@vercel

vercel Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

@torsello is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

`#rewriteStepsBundleForCjs` prepended its own `const require =
__bundled_createRequire(...)` shim, but `createStepsBundle` already emits an
ESM interop banner declaring `var require = __createRequire(...)`. Nest passes
`bundleFinalOutput: false`, so `skipEsmRequireBanner` stays false and the banner
is always present. Both statements declare `require` in one module scope, so the
bundle throws `SyntaxError: Identifier 'require' has already been declared`.

The build still reports success, so the failure surfaces later and indirectly:
the flow route answers 500 and the run stays pending.

The shim is redundant — the banner provides the same binding, plus `__filename`
and `__dirname` — so drop it. Skipping the banner instead would remove those two
and is explicitly warned against in `createStepsBundle`.

Fixes vercel#3778

Signed-off-by: Matias Torsello <23641125+torsello@users.noreply.github.com>
@torsello
torsello force-pushed the fix/nest-cjs-duplicate-require branch from a1fe769 to 9d0409c Compare September 12, 2026 11:38
@torsello

Copy link
Copy Markdown
Contributor Author

@vercel/workflow ready for review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[nest] Steps bundle declares require twice with --module commonjs

2 participants