vercel / vercel/workflow

`@workflow/builders` sends every esbuild-traversed JavaScript module through SWC during Nitro builds

Open
#3,051 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2.4k
Forks
365
Avg merge
2d 11h
Merged PRs (30d)
169

Description

TL;DR

With @workflow/nitro@5.0.0-beta.26, the builder's esbuild load path calls applySwcTransform() for every JS/TS module. This includes transitive deps that have no 'use workflow' or 'use step' directive.

Especially when using the AI SDK WorkflowAgent: its dependency graph sends 391 unique JavaScript modules through the transform; 383 contain no Workflow directive. For us, this translates to a 30s rebuild time for simple workflows.

Minimal Reproduction

Repository: https://github.com/ecumene/slow-workflows-swc-build

corepack enable
pnpm install --frozen-lockfile
pnpm profile:published
pnpm profile
pnpm benchmark
pnpm compare
Profile result
Build Transform calls Unique transitive JS Directive-free transitive JS Safe fast-path candidates
WorkflowAgent + fallback 1927 1892 1884 1875
WorkflowAgent (real graph only) 426 391 383 374
Control 1 1 0 0
Benchmark result

Five runs on macOS arm64 / Node 22.23.1:

Measurement Published PR fast path Speedup
Agent cold 3888.8 ms 2818.4 ms 1.38×
Agent rebuild after editing its workflow 2899.2 ms 1854.6 ms 1.56×
Control cold 1037.9 ms 1066.2 ms 0.97×

The benchmark generates a chain of 1,500 ordinary JavaScript modules so the timing difference is easy to reproduce. The generated files are ignored and contain no Workflow directives.

Suspected cause

createSwcPlugin() runs applySwcTransform() on every JavaScript and TypeScript module loaded by esbuild, even when a JavaScript file has no Workflow directive or serialization hook. The discovery pass uses the same transform.

Local comparison

The local patch skips SWC for JavaScript files without Workflow directives or serialization hooks. Workflow, step, serialization, and TypeScript files are still transformed.

Measurement Published builder Local fast path Speedup
Agent cold median 3888.8 ms 2818.4 ms 1.38×
Agent rebuild median 2899.2 ms 1854.6 ms 1.56×

The workflow and step remain in the manifest, edits still rebuild, and runtime output is unchanged.

Expected behavior

JavaScript without Workflow directives or serialization hooks should skip the Workflow SWC transform.

Environment
  • Node 22.23.1
  • pnpm 10.34.5
  • nitropack 2.13.1
  • workflow 5.0.0-beta.26
  • @workflow/nitro 5.0.0-beta.26
  • @ai-sdk/workflow 1.0.34
  • @ai-sdk/openai 4.0.17
  • ai 7.0.34

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at createSwcPlugin() and applySwcTransform(), then reproduce the issue with the linked benchmark commands. Trace the esbuild load and discovery passes for directive-free JavaScript modules; done means those modules skip the Workflow SWC transform while workflow, step, serialization, and TypeScript files still transform and rebuild correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
build-system, performance
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.