Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-pseudo-package-bundling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@workflow/builders": patch
---

Fix workflow bundle to inline pseudo-packages instead of marking them external
17 changes: 15 additions & 2 deletions packages/builders/src/base-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from './apply-swc-transform.js';
import { createDiscoverEntriesPlugin } from './discover-entries-esbuild-plugin.js';
import { createNodeModuleErrorPlugin } from './node-module-esbuild-plugin.js';
import { createPseudoPackagePlugin } from './pseudo-package-esbuild-plugin.js';
import { createSwcPlugin } from './swc-esbuild-plugin.js';
import type { WorkflowConfig } from './types.js';
import { extractWorkflowGraphs } from './workflows-extractor.js';
Expand Down Expand Up @@ -371,6 +372,9 @@ export abstract class BaseBuilder {
// occur in deeply nested function calls across multiple files.
sourcemap: 'inline',
plugins: [
// Handle pseudo-packages like 'server-only' and 'client-only' by providing
// empty modules. Must run first to intercept these before other resolution.
createPseudoPackagePlugin(),
createSwcPlugin({
mode: 'step',
entriesToBundle: externalizeNonSteps
Expand Down Expand Up @@ -539,6 +543,9 @@ export abstract class BaseBuilder {
'.cjs',
],
plugins: [
// Handle pseudo-packages like 'server-only' and 'client-only' by providing
// empty modules. Must run first to intercept these before other resolution.
createPseudoPackagePlugin(),
createSwcPlugin({
mode: 'workflow',
workflowManifest,
Expand All @@ -547,8 +554,14 @@ export abstract class BaseBuilder {
// happens first, preventing false positives on Node.js imports in unused code paths
createNodeModuleErrorPlugin(),
],
// External packages that should not be bundled (e.g., server-only, client-only for Next.js)
external: this.config.externalPackages || [],
// NOTE: We intentionally do NOT use the external option here for workflow bundles.
// When packages are marked external with format: 'cjs', esbuild generates require() calls.
// However, the workflow VM (vm.runInContext) does not have require() defined - it only
// provides module.exports and exports. External packages would fail at runtime with:
// ReferenceError: require is not defined
// Instead, we bundle everything and rely on:
// - createPseudoPackagePlugin() to handle server-only/client-only with empty modules
// - createNodeModuleErrorPlugin() to catch Node.js builtin imports at build time
});
const interimBundle = await interimBundleCtx.rebuild();

Expand Down
4 changes: 4 additions & 0 deletions packages/builders/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export {
export { STEP_QUEUE_TRIGGER, WORKFLOW_QUEUE_TRIGGER } from './constants.js';
export { createDiscoverEntriesPlugin } from './discover-entries-esbuild-plugin.js';
export { createNodeModuleErrorPlugin } from './node-module-esbuild-plugin.js';
export {
createPseudoPackagePlugin,
PSEUDO_PACKAGES,
} from './pseudo-package-esbuild-plugin.js';
export { NORMALIZE_REQUEST_CODE } from './request-converter.js';
export { StandaloneBuilder } from './standalone.js';
export { createSwcPlugin } from './swc-esbuild-plugin.js';
Expand Down
Loading
Loading