Skip to content

fix(swc-plugin): count destructuring-default references in DCE usage analysis#2398

Open
pranaygp wants to merge 2 commits into
mainfrom
pgp/swc-plugin-fix
Open

fix(swc-plugin): count destructuring-default references in DCE usage analysis#2398
pranaygp wants to merge 2 commits into
mainfrom
pgp/swc-plugin-fix

Conversation

@pranaygp

Copy link
Copy Markdown
Contributor

Fixes #2396.

Problem

The SWC plugin's dead-code-elimination (DCE) usage analysis did not count identifier references that appear as default values inside a destructuring pattern (e.g. const { ttl = TTL } = options;). When a module-scope const was referenced only through such a destructuring default, the DCE pass treated it as unused and stripped it from the emitted bundle — while keeping the code that referenced it. The result was a runtime ReferenceError: <const> is not defined when the default fired.

This is mode-independent (reproduces in both step and workflow mode) and class-independent (a plain top-level function exhibits it too). It shipped as a worked-around bug in the kill-switch pattern (#1858) and remains latent in workbench/vitest/workflows/cookbook/distributed-abort-controller.ts.

Root cause

In ComprehensiveUsageCollector::visit_mut_var_declarator, the collector visited only the initializer and deliberately skipped the entire var_decl.name pattern (to avoid marking the binding name as "used"). For destructuring patterns, the default-value initializer expressions live inside var_decl.name — so references like the TTL in { ttl = TTL } were never added to used_identifiers, and remove_dead_code then pruned the still-referenced declaration.

Fix

Added visit_pat_default_initializers, which walks a binding pattern and visits only the default-value initializer expressions (and computed keys) — ObjectPatProp::KeyValue values, ObjectPatProp::Assign.value, AssignPat.right, array element defaults, rest args — while still not marking the binding names themselves as used. visit_mut_var_declarator now calls it on var_decl.name.

Function-parameter destructuring defaults were already covered: visit_mut_fn_decl visits params in full (confirmed by the existing default-parameter-usage fixture), so no change was needed there.

Tests

  • New fixture destructuring-default-references-module-const/ asserts that two module-scope consts referenced only via destructuring defaults — one inside a class static method, one inside a plain exported function — survive in both step and workflow mode. A third, genuinely-unused const is still stripped, confirming DCE is not over-broadened.
  • Verified the fixture fails on main (consts stripped) and passes with the fix.
  • Full cargo test -p swc_workflow suite green (128 fixture tests + error tests).

Spec

Updated packages/swc-plugin-workflow/spec.md (both the step-mode and workflow-mode DCE sections) to note that a reference counts even when it appears only inside a destructuring-default initializer.

Relation to prior fixes

Same symptom class as #1944 (DCE removing a declaration that surviving code references) but a distinct root cause: #1944 was about DCE ordering relative to step hoisting; this is about the usage collector never traversing destructuring-default initializers at all, and reproduces with no nested/hoisted steps involved.

🤖 Generated with Claude Code

…analysis

The DCE usage collector skipped the entire variable name pattern when
visiting a `VarDeclarator` (to avoid marking the binding name as "used").
But default-value initializers inside destructuring patterns live in that
pattern — e.g. the `TTL` in `const { ttl = TTL } = options;` — so those
references were invisible to the collector. A module-scope `const`
referenced only through such a default was treated as unused and stripped,
while the surviving code kept reading it, producing a runtime
`ReferenceError` when the default fired.

Traverse the default-value initializer expressions (and computed keys)
within destructuring patterns while still not marking the binding names
themselves, so the referenced declaration is preserved. Function-parameter
defaults were already covered (params are visited in full).

Fixes #2396.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 13, 2026 06:29
@pranaygp pranaygp requested a review from a team as a code owner June 13, 2026 06:29
@changeset-bot

changeset-bot Bot commented Jun 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5f05ea6

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

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

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Jun 14, 2026 8:14am
example-nextjs-workflow-webpack Ready Ready Preview, Comment Jun 14, 2026 8:14am
example-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-astro-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-express-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-fastify-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-hono-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-nitro-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-nuxt-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-sveltekit-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-tanstack-start-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workbench-vite-workflow Ready Ready Preview, Comment Jun 14, 2026 8:14am
workflow-docs Ready Ready Preview, Comment, Open in v0 Jun 14, 2026 8:14am
workflow-swc-playground Ready Ready Preview, Comment Jun 14, 2026 8:14am
workflow-tarballs Ready Ready Preview, Comment Jun 14, 2026 8:14am
workflow-web Ready Ready Preview, Comment Jun 14, 2026 8:14am

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

⚠️ Results below are stale and not from the latest commit. This comment will be updated when CI completes on the latest run.

Benchmarks are running...


_Started at: _


📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 0.041s (-8.5% 🟢) 1.007s (~) 0.966s 10 1.00x
💻 Local Express 0.044s (~) 1.006s (~) 0.961s 10 1.09x
🐘 Postgres Nitro 0.061s (-7.5% 🟢) 1.013s (~) 0.952s 10 1.50x
💻 Local Next.js (Turbopack) 0.063s (~) 1.007s (~) 0.944s 10 1.54x
🐘 Postgres Next.js (Turbopack) 0.070s (+4.5%) 1.011s (~) 0.941s 10 1.71x
🐘 Postgres Express 0.077s (+22.7% 🔺) 1.035s (+2.1%) 0.958s 10 1.89x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 0.268s (-25.2% 🟢) 2.208s (-14.8% 🟢) 1.941s 10 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.089s (-1.5%) 2.006s (~) 0.917s 10 1.00x
💻 Local Nitro 1.091s (~) 2.006s (~) 0.915s 10 1.00x
🐘 Postgres Nitro 1.108s (~) 2.010s (~) 0.902s 10 1.02x
💻 Local Next.js (Turbopack) 1.133s (-0.9%) 2.006s (~) 0.873s 10 1.04x
🐘 Postgres Express 1.142s (+2.7%) 2.033s (+1.2%) 0.892s 10 1.05x
🐘 Postgres Next.js (Turbopack) 1.164s (+2.1%) 2.011s (~) 0.847s 10 1.07x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 1.804s (+2.3%) 3.491s (-9.5% 🟢) 1.687s 10 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 10.522s (~) 11.019s (~) 0.497s 3 1.00x
💻 Local Nitro 10.523s (~) 11.022s (~) 0.500s 3 1.00x
💻 Local Express 10.543s (~) 11.023s (~) 0.480s 3 1.00x
💻 Local Next.js (Turbopack) 10.808s (~) 11.021s (~) 0.213s 3 1.03x
🐘 Postgres Next.js (Turbopack) 10.865s (~) 11.018s (~) 0.153s 3 1.03x
🐘 Postgres Express 11.055s (+4.8%) 11.478s (+4.2%) 0.423s 3 1.05x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 14.528s (+4.0%) 16.091s (+2.2%) 1.563s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 13.705s (~) 14.027s (~) 0.322s 5 1.00x
💻 Local Express 13.794s (~) 14.026s (~) 0.232s 5 1.01x
🐘 Postgres Nitro 13.985s (~) 14.218s (+1.4%) 0.233s 5 1.02x
🐘 Postgres Express 14.262s (+3.2%) 14.654s (+4.5%) 0.392s 5 1.04x
💻 Local Next.js (Turbopack) 14.380s (~) 15.029s (~) 0.650s 4 1.05x
🐘 Postgres Next.js (Turbopack) 14.595s (+1.3%) 15.021s (~) 0.426s 4 1.06x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 24.572s (+0.8%) 26.176s (~) 1.604s 3 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 12.377s (~) 13.025s (~) 0.648s 7 1.00x
💻 Local Express 12.413s (-1.3%) 13.025s (~) 0.612s 7 1.00x
🐘 Postgres Nitro 12.507s (-0.9%) 13.018s (~) 0.512s 7 1.01x
🐘 Postgres Express 13.540s (+7.6% 🔺) 14.183s (+8.9% 🔺) 0.642s 7 1.09x
💻 Local Next.js (Turbopack) 13.776s (~) 14.026s (-1.0%) 0.250s 7 1.11x
🐘 Postgres Next.js (Turbopack) 13.848s (-1.5%) 14.161s (-2.9%) 0.312s 7 1.12x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 33.827s (+14.6% 🔺) 35.912s (+11.1% 🔺) 2.085s 3 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.200s (-1.8%) 2.008s (~) 0.808s 15 1.00x
💻 Local Express 1.220s (-4.4%) 2.005s (~) 0.785s 15 1.02x
💻 Local Nitro 1.234s (+4.2%) 2.007s (~) 0.773s 15 1.03x
🐘 Postgres Next.js (Turbopack) 1.285s (-1.7%) 2.007s (~) 0.723s 15 1.07x
💻 Local Next.js (Turbopack) 1.326s (-2.8%) 2.006s (~) 0.680s 15 1.11x
🐘 Postgres Express 1.426s (+17.8% 🔺) 2.072s (+3.2%) 0.646s 15 1.19x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.904s (-30.4% 🟢) 4.716s (-16.0% 🟢) 1.812s 7 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.391s (-1.6%) 2.470s (+3.2%) 1.079s 13 1.00x
🐘 Postgres Express 1.520s (+6.9% 🔺) 2.348s (+9.1% 🔺) 0.828s 13 1.09x
🐘 Postgres Next.js (Turbopack) 1.594s (+0.8%) 2.152s (-7.2% 🟢) 0.558s 14 1.15x
💻 Local Nitro 1.710s (-3.1%) 2.006s (-3.2%) 0.296s 15 1.23x
💻 Local Express 1.727s (-16.2% 🟢) 2.006s (-20.0% 🟢) 0.279s 15 1.24x
💻 Local Next.js (Turbopack) 1.811s (+2.9%) 2.150s (~) 0.339s 14 1.30x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 4.214s (+50.8% 🔺) 6.291s (+45.3% 🔺) 2.077s 5 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.606s (-1.2%) 4.011s (-3.1%) 2.405s 8 1.00x
🐘 Postgres Express 2.048s (+25.6% 🔺) 4.461s (+11.2% 🔺) 2.413s 7 1.28x
🐘 Postgres Next.js (Turbopack) 3.278s (+1.9%) 4.013s (~) 0.735s 8 2.04x
💻 Local Express 4.722s (-16.4% 🟢) 5.345s (-11.1% 🟢) 0.622s 6 2.94x
💻 Local Nitro 4.852s (+7.8% 🔺) 5.179s (~) 0.327s 6 3.02x
💻 Local Next.js (Turbopack) 5.428s (+17.3% 🔺) 6.214s (+24.0% 🔺) 0.786s 5 3.38x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 4.594s (+15.3% 🔺) 6.791s (+14.4% 🔺) 2.197s 5 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.239s (+1.7%) 2.007s (~) 0.769s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.327s (+2.8%) 2.009s (~) 0.681s 15 1.07x
💻 Local Next.js (Turbopack) 1.354s (-0.5%) 2.006s (~) 0.653s 15 1.09x
🐘 Postgres Express 1.429s (+16.7% 🔺) 2.024s (+0.9%) 0.595s 15 1.15x
💻 Local Express 1.546s (~) 2.007s (~) 0.460s 15 1.25x
💻 Local Nitro 1.613s (+5.0% 🔺) 2.073s (+3.3%) 0.461s 15 1.30x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.045s (-7.1% 🟢) 4.960s (-1.0%) 1.916s 7 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.417s (-0.8%) 2.316s (+4.2%) 0.899s 13 1.00x
🐘 Postgres Next.js (Turbopack) 1.542s (+0.5%) 2.222s (+3.8%) 0.680s 14 1.09x
🐘 Postgres Express 1.716s (+27.3% 🔺) 2.614s (+21.5% 🔺) 0.899s 12 1.21x
💻 Local Next.js (Turbopack) 1.951s (-5.0%) 2.293s (-18.8% 🟢) 0.343s 14 1.38x
💻 Local Express 1.958s (-9.1% 🟢) 2.317s (-10.6% 🟢) 0.359s 13 1.38x
💻 Local Nitro 2.222s (+22.6% 🔺) 2.737s (+23.1% 🔺) 0.515s 11 1.57x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.337s (-15.7% 🟢) 4.836s (-13.8% 🟢) 1.500s 7 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.579s (-5.4% 🟢) 3.760s (-12.7% 🟢) 2.181s 8 1.00x
🐘 Postgres Express 1.799s (-12.7% 🟢) 4.014s (-3.1%) 2.216s 8 1.14x
🐘 Postgres Next.js (Turbopack) 3.277s (-0.7%) 4.448s (+10.8% 🔺) 1.171s 7 2.08x
💻 Local Nitro 5.056s (-6.9% 🟢) 5.514s (-5.7% 🟢) 0.457s 6 3.20x
💻 Local Express 5.729s (-6.0% 🟢) 6.014s (-9.1% 🟢) 0.285s 5 3.63x
💻 Local Next.js (Turbopack) 6.084s (+20.9% 🔺) 6.518s (+18.2% 🔺) 0.434s 6 3.85x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.955s (-61.7% 🟢) 5.252s (-55.7% 🟢) 1.297s 7 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.569s (-1.6%) 1.006s (~) 0.437s 60 1.00x
💻 Local Express 0.595s (-2.5%) 1.005s (~) 0.410s 60 1.05x
💻 Local Nitro 0.636s (+8.2% 🔺) 1.039s (+3.4%) 0.403s 58 1.12x
🐘 Postgres Express 0.749s (+32.3% 🔺) 1.227s (+22.0% 🔺) 0.478s 49 1.32x
🐘 Postgres Next.js (Turbopack) 0.828s (+2.7%) 1.006s (~) 0.179s 60 1.45x
💻 Local Next.js (Turbopack) 0.880s (+0.9%) 1.021s (-1.7%) 0.142s 59 1.55x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 7.080s (+37.9% 🔺) 8.880s (+27.3% 🔺) 1.800s 7 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.316s (-6.2% 🟢) 2.008s (~) 0.691s 45 1.00x
💻 Local Express 1.500s (-1.5%) 2.006s (~) 0.507s 45 1.14x
💻 Local Nitro 1.516s (+0.9%) 2.006s (~) 0.490s 45 1.15x
🐘 Postgres Express 1.698s (+17.3% 🔺) 2.239s (+9.1% 🔺) 0.541s 41 1.29x
🐘 Postgres Next.js (Turbopack) 1.958s (+2.5%) 2.150s (+3.6%) 0.192s 42 1.49x
💻 Local Next.js (Turbopack) 2.129s (~) 3.007s (~) 0.878s 30 1.62x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 16.186s (+15.4% 🔺) 17.808s (+9.2% 🔺) 1.622s 6 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 2.658s (-2.8%) 3.058s (+0.8%) 0.400s 40 1.00x
💻 Local Express 3.280s (-1.2%) 3.977s (-0.8%) 0.698s 31 1.23x
💻 Local Nitro 3.301s (+2.5%) 4.009s (~) 0.708s 30 1.24x
🐘 Postgres Express 3.534s (+28.0% 🔺) 3.965s (+26.4% 🔺) 0.431s 31 1.33x
🐘 Postgres Next.js (Turbopack) 3.866s (~) 4.043s (-3.3%) 0.178s 30 1.45x
💻 Local Next.js (Turbopack) 4.399s (+1.3%) 5.011s (~) 0.611s 24 1.66x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 26.417s (-14.4% 🟢) 28.274s (-14.1% 🟢) 1.856s 5 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.240s (-4.5%) 1.006s (~) 0.766s 60 1.00x
🐘 Postgres Next.js (Turbopack) 0.294s (-4.3%) 1.006s (-1.7%) 0.712s 60 1.23x
🐘 Postgres Express 0.381s (+52.2% 🔺) 1.051s (+4.4%) 0.670s 58 1.59x
💻 Local Express 0.429s (+9.4% 🔺) 1.005s (~) 0.576s 60 1.79x
💻 Local Nitro 0.448s (+12.4% 🔺) 1.022s (+1.7%) 0.574s 59 1.87x
💻 Local Next.js (Turbopack) 0.564s (-2.4%) 1.005s (~) 0.441s 60 2.35x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.239s (+18.8% 🔺) 3.835s (-7.1% 🟢) 1.595s 16 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.411s (-2.6%) 1.041s (-2.3%) 0.630s 87 1.00x
🐘 Postgres Express 0.594s (+42.2% 🔺) 1.131s (+8.7% 🔺) 0.537s 80 1.45x
🐘 Postgres Next.js (Turbopack) 0.606s (+9.8% 🔺) 1.207s (+14.7% 🔺) 0.601s 75 1.48x
💻 Local Express 2.234s (+3.2%) 2.853s (+5.0% 🔺) 0.619s 32 5.44x
💻 Local Nitro 2.299s (+8.5% 🔺) 2.913s (+9.6% 🔺) 0.614s 31 5.60x
💻 Local Next.js (Turbopack) 2.478s (+1.5%) 3.261s (+2.4%) 0.784s 28 6.03x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.884s (+6.5% 🔺) 4.572s (+3.0%) 1.688s 20 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.780s (-7.1% 🟢) 1.386s (-8.8% 🟢) 0.606s 87 1.00x
🐘 Postgres Express 0.905s (+11.4% 🔺) 1.722s (+8.5% 🔺) 0.817s 70 1.16x
🐘 Postgres Next.js (Turbopack) 3.068s (+18.2% 🔺) 3.858s (+12.1% 🔺) 0.791s 32 3.93x
💻 Local Express 9.593s (-2.1%) 10.116s (-2.4%) 0.523s 12 12.30x
💻 Local Nitro 9.874s (+5.6% 🔺) 10.362s (+4.1%) 0.487s 12 12.66x
💻 Local Next.js (Turbopack) 10.461s (+3.1%) 11.119s (+0.8%) 0.658s 11 13.41x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 6.710s (+5.3% 🔺) 8.134s (-2.9%) 1.424s 15 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -

🔍 Observability: Nitro

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.163s (-0.5%) 2.004s (~) 0.010s (-17.9% 🟢) 2.017s (~) 0.854s 10 1.00x
💻 Local Nitro 1.164s (~) 2.005s (~) 0.010s (+5.1% 🔺) 2.018s (~) 0.853s 10 1.00x
🐘 Postgres Nitro 1.165s (~) 1.998s (~) 0.001s (-30.8% 🟢) 2.010s (~) 0.846s 10 1.00x
💻 Local Next.js (Turbopack) 1.208s (~) 2.003s (~) 0.013s (+19.0% 🔺) 2.019s (~) 0.811s 10 1.04x
🐘 Postgres Next.js (Turbopack) 1.225s (-4.0%) 2.002s (~) 0.001s (+10.0% 🔺) 2.011s (~) 0.786s 10 1.05x
🐘 Postgres Express 1.299s (+11.2% 🔺) 2.000s (~) 0.001s (-53.3% 🟢) 2.028s (+0.9%) 0.729s 10 1.12x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.396s (-26.8% 🟢) 3.704s (-19.7% 🟢) 0.584s (-13.9% 🟢) 4.709s (-18.9% 🟢) 2.313s 10 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -

🔍 Observability: Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.567s (-2.2%) 2.006s (~) 0.005s (-2.6%) 2.026s (~) 0.459s 30 1.00x
💻 Local Express 1.579s (-1.1%) 2.010s (~) 0.013s (+11.9% 🔺) 2.025s (~) 0.446s 30 1.01x
💻 Local Nitro 1.580s (~) 2.010s (~) 0.014s (+4.6%) 2.027s (~) 0.447s 30 1.01x
💻 Local Next.js (Turbopack) 1.747s (~) 2.009s (~) 0.012s (-8.6% 🟢) 2.023s (~) 0.277s 30 1.11x
🐘 Postgres Next.js (Turbopack) 1.756s (-0.6%) 2.010s (~) 0.005s (+3.8%) 2.026s (~) 0.270s 30 1.12x
🐘 Postgres Express 1.916s (+20.3% 🔺) 2.351s (+17.2% 🔺) 0.004s (-15.8% 🟢) 2.376s (+17.3% 🔺) 0.460s 26 1.22x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 5.747s (-6.7% 🟢) 6.881s (-12.9% 🟢) 0.244s (+29.0% 🔺) 7.635s (-11.2% 🟢) 1.889s 8 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -

🔍 Observability: Nitro

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.751s (-5.3% 🟢) 1.045s (~) 0.000s (-75.0% 🟢) 1.069s (~) 0.318s 57 1.00x
🐘 Postgres Next.js (Turbopack) 1.024s (+1.4%) 1.462s (+0.6%) 0.000s (+Infinity% 🔺) 1.471s (+0.7%) 0.447s 41 1.36x
🐘 Postgres Express 1.411s (+84.9% 🔺) 1.876s (+82.2% 🔺) 0.000s (-100.0% 🟢) 1.905s (+81.2% 🔺) 0.494s 32 1.88x
💻 Local Express 1.421s (+2.9%) 2.013s (~) 0.000s (+66.7% 🔺) 2.016s (~) 0.595s 30 1.89x
💻 Local Nitro 1.451s (+2.3%) 2.013s (~) 0.000s (+30.0% 🔺) 2.016s (~) 0.565s 30 1.93x
💻 Local Next.js (Turbopack) 1.494s (-0.8%) 2.013s (~) 0.000s (-23.1% 🟢) 2.016s (~) 0.522s 30 1.99x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.723s (-18.6% 🟢) 3.680s (-21.3% 🟢) 0.000s (+Infinity% 🔺) 4.056s (-21.6% 🟢) 1.333s 15 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -

🔍 Observability: Nitro

fan-out fan-in 10 streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.542s (-5.4% 🟢) 2.066s (-3.4%) 0.000s (+Infinity% 🔺) 2.079s (-4.8%) 0.536s 29 1.00x
🐘 Postgres Next.js (Turbopack) 2.059s (+4.0%) 2.481s (+3.3%) 0.000s (~) 2.503s (+3.9%) 0.444s 25 1.34x
🐘 Postgres Express 2.682s (+65.9% 🔺) 3.163s (+47.9% 🔺) 0.000s (+180.0% 🔺) 3.199s (+48.7% 🔺) 0.517s 20 1.74x
💻 Local Next.js (Turbopack) 2.938s (-2.3%) 3.553s (+0.8%) 0.000s (-23.0% 🟢) 3.557s (+0.8%) 0.619s 17 1.90x
💻 Local Nitro 3.144s (+2.1%) 3.778s (~) 0.000s (-44.4% 🟢) 3.781s (~) 0.637s 16 2.04x
💻 Local Express 3.217s (~) 3.961s (-1.7%) 0.001s (-6.2% 🟢) 3.968s (-1.6%) 0.752s 16 2.09x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 4.374s (-2.0%) 5.657s (-8.0% 🟢) 0.000s (+Infinity% 🔺) 6.076s (-9.1% 🟢) 1.702s 10 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -

🔍 Observability: Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Express 12/21
🐘 Postgres Nitro 21/21
▲ Vercel Nitro 21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 💻 Local 11/21
Next.js (Turbopack) 🐘 Postgres 14/21
Nitro 🐘 Postgres 16/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

⚠️ Results below are stale and not from the latest commit. This comment will be updated when CI completes on the latest run.

Tests are running...


_Started at: _


Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 1298 0 212 1510
✅ 💻 Local Development 1744 0 219 1963
✅ 📦 Local Production 1895 0 219 2114
❌ 🐘 Local Postgres 1880 1 233 2114
✅ 🪟 Windows 151 0 0 151
❌ 📋 Other 878 1 178 1057
Total 7846 2 1061 8909

❌ Failed Tests

🐘 Local Postgres (1 failed)

nextjs-turbopack-canary (1 failed):

  • experimental_setAttributes fire-and-forget: void experimental_setAttributes lands without awaiting
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 125 0 26
✅ example 125 0 26
✅ express 125 0 26
✅ fastify 125 0 26
✅ hono 125 0 26
✅ nextjs-turbopack 149 0 2
✅ nextjs-webpack 149 0 2
✅ nitro 125 0 26
✅ nuxt 125 0 26
✅ vite 125 0 26
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 126 0 25
✅ express-stable 126 0 25
✅ fastify-stable 126 0 25
✅ hono-stable 126 0 25
✅ nextjs-turbopack-canary 132 0 19
✅ nextjs-turbopack-stable-lazy-discovery-disabled 151 0 0
✅ nextjs-turbopack-stable-lazy-discovery-enabled 151 0 0
✅ nextjs-webpack-canary 132 0 19
✅ nextjs-webpack-stable-lazy-discovery-enabled 151 0 0
✅ nitro-stable 126 0 25
✅ nuxt-stable 126 0 25
✅ sveltekit-stable 145 0 6
✅ vite-stable 126 0 25
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 126 0 25
✅ express-stable 126 0 25
✅ fastify-stable 126 0 25
✅ hono-stable 126 0 25
✅ nextjs-turbopack-canary 132 0 19
✅ nextjs-turbopack-stable-lazy-discovery-disabled 151 0 0
✅ nextjs-turbopack-stable-lazy-discovery-enabled 151 0 0
✅ nextjs-webpack-canary 132 0 19
✅ nextjs-webpack-stable-lazy-discovery-disabled 151 0 0
✅ nextjs-webpack-stable-lazy-discovery-enabled 151 0 0
✅ nitro-stable 126 0 25
✅ nuxt-stable 126 0 25
✅ sveltekit-stable 145 0 6
✅ vite-stable 126 0 25
❌ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 125 0 26
✅ express-stable 125 0 26
✅ fastify-stable 125 0 26
✅ hono-stable 125 0 26
❌ nextjs-turbopack-canary 130 1 20
✅ nextjs-turbopack-stable-lazy-discovery-disabled 150 0 1
✅ nextjs-turbopack-stable-lazy-discovery-enabled 150 0 1
✅ nextjs-webpack-canary 131 0 20
✅ nextjs-webpack-stable-lazy-discovery-disabled 150 0 1
✅ nextjs-webpack-stable-lazy-discovery-enabled 150 0 1
✅ nitro-stable 125 0 26
✅ nuxt-stable 125 0 26
✅ sveltekit-stable 144 0 7
✅ vite-stable 125 0 26
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 151 0 0
❌ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 126 0 25
✅ e2e-local-dev-tanstack-start- 126 0 25
✅ e2e-local-postgres-nest-stable 125 0 26
✅ e2e-local-postgres-tanstack-start- 125 0 26
✅ e2e-local-prod-nest-stable 126 0 25
✅ e2e-local-prod-tanstack-start- 126 0 25
❌ e2e-vercel-prod-tanstack-start 124 1 26

📋 View full workflow run


Some E2E test jobs failed:

  • Vercel Prod: failure
  • Local Dev: failure
  • Local Prod: success
  • Local Postgres: failure
  • Windows: success

Check the workflow run for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes the SWC plugin’s DCE usage analysis so module-scope declarations referenced only via destructuring default initializers (e.g. const { ttl = TTL } = options) are correctly counted as “used”, preventing runtime ReferenceErrors when defaults fire.

Changes:

  • Extend ComprehensiveUsageCollector to traverse destructuring patterns and visit only default-value initializers (and computed keys), without marking binding identifiers as used.
  • Add a regression fixture covering module-scope const preservation in both step and workflow modes (and confirming truly-unused consts are still removed).
  • Update the SWC plugin spec and add a changeset for the patch release.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/swc-plugin-workflow/transform/src/lib.rs Adds visit_pat_default_initializers and wires it into visit_mut_var_declarator so destructuring-default references are counted for DCE.
packages/swc-plugin-workflow/transform/tests/fixture/destructuring-default-references-module-const/input.js New fixture input reproducing the destructuring-default-only reference pattern and an unused const.
packages/swc-plugin-workflow/transform/tests/fixture/destructuring-default-references-module-const/output-step.js Step-mode snapshot asserting referenced consts survive and unused const is removed.
packages/swc-plugin-workflow/transform/tests/fixture/destructuring-default-references-module-const/output-workflow.js Workflow-mode snapshot asserting referenced consts survive and unused const is removed.
packages/swc-plugin-workflow/spec.md Documents that destructuring-default initializers count as references for DCE in both modes.
.changeset/swc-destructuring-default-dce.md Patch changeset describing the DCE fix and the prevented runtime error.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* origin/main:
  docs: document run idempotency (#2011)
  Render attr_set events and run attributes in observability UI (#2393)
  [ci] Fix backport job model slug (#2403)
  [ci] Comment on PR when backport fails, revert to use opus 4.8 (#2400)
  Update queue client to 0.3.1 (#2399)
  fix(deps): upgrade esbuild to 0.28.1 (GHSA-gv7w-rqvm-qjhr) (#2395)
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.

[swc-plugin] DCE strips module-scope declarations referenced only by destructuring defaults → ReferenceError

2 participants