Skip to content

fix(next) - in next server actions, direct "use step" calls can fail in production because client-mode transform prunes step-only imports#1312

Merged
TooTallNate merged 4 commits intovercel:mainfrom
NathanColosimo:fix/next-server-action-step-imports
Mar 11, 2026
Merged

fix(next) - in next server actions, direct "use step" calls can fail in production because client-mode transform prunes step-only imports#1312
TooTallNate merged 4 commits intovercel:mainfrom
NathanColosimo:fix/next-server-action-step-imports

Conversation

@NathanColosimo
Copy link
Contributor

@NathanColosimo NathanColosimo commented Mar 10, 2026

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::Client keeps 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:

  • App Router
  • use server
  • server action directly importing a "use step" function
  • step depends on imported helpers

Tests

Updated SWC fixture expectations for client-mode outputs where step-body-only imports/locals now need to be preserved.

cargo test -p swc_workflow

Let me know if you want less tests / formatting I can make this more minimal!

@NathanColosimo NathanColosimo requested a review from a team as a code owner March 10, 2026 01:53
@changeset-bot
Copy link

changeset-bot bot commented Mar 10, 2026

🦋 Changeset detected

Latest commit: a7d8694

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

This PR includes changesets to release 16 packages
Name Type
@workflow/builders Patch
@workflow/swc-plugin Patch
@workflow/astro Patch
@workflow/cli Patch
@workflow/nest Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/vitest Patch
workflow Patch
@workflow/world-testing Patch
@workflow/nuxt Patch
@workflow/core Patch
@workflow/web-shared 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
Copy link
Contributor

vercel bot commented Mar 10, 2026

@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>
Copy link
Member

@TooTallNate TooTallNate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  1. spec.md not updated — Per repo rules (AGENTS.md), any change to the SWC plugin transform behavior must be reflected in packages/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.

  2. workbench/nextjs-webpack/app/home-client.tsx is broken — This file is added but imports from @/app/workflows/args and @/app/workflows/types, neither of which exist in the webpack workbench. The webpack page.tsx is also not updated to use the new component. This will cause build failures.

Minor Notes

  • The import path cleanup (removing .js extensions) 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.ts and discover-entries-esbuild-plugin.ts

I, nathancolosimo <nathancolosimo@gmail.com>, hereby add my Signed-off-by to this commit: 150d175
I, nathancolosimo <nathancolosimo@gmail.com>, hereby add my Signed-off-by to this commit: 429747f

Signed-off-by: nathancolosimo <nathancolosimo@gmail.com>
Copy link
Member

@TooTallNate TooTallNate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@NathanColosimo
Copy link
Contributor Author

@TooTallNate The files did already exist

@TooTallNate TooTallNate dismissed stale reviews from themself March 11, 2026 06:00

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.

Copy link
Member

@TooTallNate TooTallNate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. spec.md — Updated with clear documentation of DCE behavior differences between Workflow and Client modes.
  2. webpack workbench — Works correctly via symlinks. Supporting files (args.ts, types.ts, updated page.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.

@TooTallNate TooTallNate merged commit d72c822 into vercel:main Mar 11, 2026
69 of 104 checks passed
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.

Next server actions: direct "use step" calls can fail in production because client-mode transform prunes step-only imports

2 participants