fix(next) - in next server actions, direct "use step" calls can fail in production because client-mode transform prunes step-only imports#1312
Conversation
🦋 Changeset detectedLatest commit: a7d8694 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 |
|
@NathanColosimo is attempting to deploy a commit to the Vercel Labs Team on Vercel. A member of the Team first needs to authorize it. |
Fix bug where the SWC compiler bug prunes step-only imports in the client-mode transformation Signed-off-by: Nathan Rajlich <n@n8.io>
TooTallNate
left a comment
There was a problem hiding this comment.
Review Summary
The core SWC fix is correct and well-reasoned — client-mode DCE was incorrectly skipping step function body analysis, causing imports/helpers used only inside step bodies to be pruned. The analyze_step_function_bodies flag cleanly separates Workflow mode (bodies replaced → skip analysis) from Client mode (bodies preserved → must analyze). The test fixture updates confirm the fix works as expected.
The builder changes (relative path prefix fix, .output ignore, build artifact filtering) are also good and address real edge cases.
Blocking Issues
-
spec.mdnot updated — Per repo rules (AGENTS.md), any change to the SWC plugin transform behavior must be reflected inpackages/swc-plugin-workflow/spec.md. The spec currently has no mention of dead code elimination. This PR changes DCE semantics and should document the behavioral difference between Workflow and Client modes. -
workbench/nextjs-webpack/app/home-client.tsxis broken — This file is added but imports from@/app/workflows/argsand@/app/workflows/types, neither of which exist in the webpack workbench. The webpackpage.tsxis also not updated to use the new component. This will cause build failures.
Minor Notes
- The import path cleanup (removing
.jsextensions) and nuxt config fix are fine - The repro page structure (
test-direct-step-call-server-action/) follows Next.js patterns well - Consider sharing the build artifact directory list between
base-builder.tsanddiscover-entries-esbuild-plugin.ts
TooTallNate
left a comment
There was a problem hiding this comment.
Re-review
Thanks for the updates. The spec.md addition is well-written and accurately documents the DCE behavioral difference between Workflow and Client modes — that blocking issue is resolved.
However, the webpack workbench issue is still present. The only file changed in workbench/nextjs-webpack/ is app/home-client.tsx, which imports from:
@/app/workflows/args— does not exist in the webpack workbench@/app/workflows/types— does not exist in the webpack workbench
Additionally, workbench/nextjs-webpack/app/page.tsx is not updated to use the new HomeClient component, and workbench/nextjs-webpack/app/workflows/definitions.ts still has the old structure (no server-only, still exports materializeWorkflowArgs and WorkflowDefinition directly).
The simplest fix would be to remove workbench/nextjs-webpack/app/home-client.tsx from this PR entirely, since the webpack workbench refactoring is incomplete. That can be done in a follow-up.
|
@TooTallNate The files did already exist |
Dismissing: the webpack workbench concern was incorrect — the app directory uses symlinks to the turbopack workbench, so all supporting files (args.ts, types.ts, page.tsx, definitions.ts) are shared automatically.
TooTallNate
left a comment
There was a problem hiding this comment.
Re-review (corrected)
Apologies for the previous incorrect reviews regarding the webpack workbench — I missed that workbench/nextjs-webpack/app/ uses symlinks to the turbopack workbench, so page.tsx, workflows/, etc. are all shared automatically. Both previous blocking concerns are now resolved:
- spec.md — Updated with clear documentation of DCE behavior differences between Workflow and Client modes.
- webpack workbench — Works correctly via symlinks. Supporting files (
args.ts,types.ts, updatedpage.tsx,definitions.ts) are all shared through the symlinked directories.
Summary
The core SWC fix is correct: ComprehensiveUsageCollector now respects a new analyze_step_function_bodies flag that is true in Client mode (where step bodies are preserved) and false in Workflow mode (where they're replaced with stubs). All three skip sites (visit_mut_fn_decl, visit_mut_export_decl, visit_mut_var_declarator) are properly updated. Test fixture expectations are updated to match.
The builder changes (.output ignore, relative path prefix fix, build artifact filtering) are solid improvements.
One minor nit remains inline about the webpack home-client.tsx being a real file instead of a symlink.
Closes #1311
This fixes a production-only bug where a
"use step"function imported directly outside workflow context could fail because client-mode dead-code elimination removed imports/local helpers used only inside the step body.Root cause
TransformMode::Clientkeeps step bodies intact, but the usage collector treated step bodies like workflow-mode replacements and skipped analyzing them.Fix
In client mode, usage analysis now includes step-function bodies.
Repro
Added a focused Next Turbopack repro for:
use server"use step"functionTests
Updated SWC fixture expectations for client-mode outputs where step-body-only imports/locals now need to be preserved.
cargo test -p swc_workflowLet me know if you want less tests / formatting I can make this more minimal!