refactor(nitro): use nitro v3 functionRules workflow routes#1575
refactor(nitro): use nitro v3 functionRules workflow routes#1575RihanArfan wants to merge 12 commits intomainfrom
functionRules workflow routes#1575Conversation
🦋 Changeset detectedLatest commit: d7d9685 The changes in this PR will be included in the next version bump. This PR includes changesets to release 17 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 |
e312e97 to
3eb081a
Compare
📊 Benchmark Results
workflow with no steps💻 Local Development
workflow with 1 step💻 Local Development
workflow with 10 sequential steps💻 Local Development
workflow with 25 sequential steps💻 Local Development
workflow with 50 sequential steps💻 Local Development
Promise.all with 10 concurrent steps💻 Local Development
Promise.all with 25 concurrent steps💻 Local Development
Promise.all with 50 concurrent steps💻 Local Development
Promise.race with 10 concurrent steps💻 Local Development
Promise.race with 25 concurrent steps💻 Local Development
Promise.race with 50 concurrent steps💻 Local Development
workflow with 10 sequential data payload steps (10KB)💻 Local Development
workflow with 25 sequential data payload steps (10KB)💻 Local Development
workflow with 50 sequential data payload steps (10KB)💻 Local Development
workflow with 10 concurrent data payload steps (10KB)💻 Local Development
workflow with 25 concurrent data payload steps (10KB)💻 Local Development
workflow with 50 concurrent data payload steps (10KB)💻 Local Development
Stream Benchmarks (includes TTFB metrics)workflow with stream💻 Local Development
stream pipeline with 5 transform steps (1MB)💻 Local Development
10 parallel streams (1MB each)💻 Local Development
fan-out fan-in 10 streams (1MB each)💻 Local Development
SummaryFastest Framework by WorldWinner determined by most benchmark wins
Fastest World by FrameworkWinner determined by most benchmark wins
Column Definitions
Worlds:
|
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests▲ Vercel Production (8 failed)express (2 failed):
fastify (2 failed):
hono (2 failed):
nitro (2 failed):
💻 Local Development (90 failed)fastify-stable (89 failed):
vite-stable (1 failed):
Details by Category❌ ▲ Vercel Production
❌ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 📋 Other
❌ Some E2E test jobs failed:
Check the workflow run for details. |
functionRules for workflow routesfunctionRules workflow routes
functionRules workflow routesfunctionRules workflow routes
- Update `nitro` catalog entry from `3.0.1-alpha.1` to `^3.0.260415-beta`. - Update workbench/nitro-v3 plugin to use `definePlugin` (the new public API) instead of `defineNitroPlugin` from nitro's internal runtime path, which is no longer exposed. - Update README link to the promoted nitro.build URL.
…utes
Bundle workflow routes inside the Nitro server using the base builder, and
use Nitro v3 `functionRules` to configure per-route runtime/trigger config
on Vercel (previously this went through a separate `LegacyVercelBuilder`
Build Output API pass, now retained only for Nitro v2 fallback).
- `isNitroV2()` uses `nitro.meta.majorVersion` when available (with
`routing` property as fallback for older nitropack releases).
- Adds unit tests for v2/v3 detection via `meta.majorVersion`.
- v3 deploy path registers `.well-known/workflow/v1/{step,flow,webhook}`
handlers with their appropriate queue triggers and `maxDuration` caps.
BREAKING CHANGE: Nitro v3+ deploys to Vercel now require a nitropack that
supports the `functionRules` option on `nitro.options.vercel`. Users
still on Nitro v2 are unaffected (they continue through the legacy
`VercelBuilder` path).
…s bundler
When nitro bundles `steps.mjs` / `workflows.mjs` (which the base builder
emits with `sourcemap: inline`) into `.output/server/index.mjs`, the
bundler does not consume the inline `//# sourceMappingURL=data:...`
comments from input files by default. As a result the emitted output map
only references nitro wrappers + node_modules and error stack traces point
at the bundled output rather than the original user `.ts` sources.
Two changes together make this work:
- Enable `nitro.options.sourcemap = true` on Vercel deploys so the bundler
emits an external `.mjs.map` alongside the server bundle.
- Add a `workflow:sourcemap-loader` plugin that intercepts files under
`<buildDir>/workflow/*.mjs` in its `load` hook, parses the inline
base64 sourcemap out of the trailing comment, strips the comment, and
returns `{ code, map }` so the bundler chains the map into the final
output.
With both in place, stack frames from step errors remap from
`.output/server/index.mjs:<N>` back to `workflows/99_e2e.ts` and
`helpers.ts` (the two assertions failing in the `E2E Vercel Prod Tests
(nitro)` CI job).
The plugin is registered via the `rollup:before` hook, which nitro fires
for all three supported bundlers (rolldown — the v3 default, rollup, and
vite). Its `load` hook returns a `SourceDescription` shape (`{ code, map }`)
that is accepted identically by rolldown and rollup.
…provement # Conflicts: # pnpm-lock.yaml
|
@vercel/workflow |
VaguelySerious
left a comment
There was a problem hiding this comment.
You probably know better than me whether the nits apply, so use your judgement there. Happy to approve this once the e2e tests are running again and CI is green
VaguelySerious
left a comment
There was a problem hiding this comment.
AI review: blocking issues found
| const source = nitro.options.virtual['#workflow/steps.mjs']; | ||
| expect(source).toContain('fromWebHandler'); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
AI Review: Note
Test coverage gap on the new v3 Vercel deploy paths
The added unit tests only cover isNitroV2 detection. None of the new v3 Vercel deploy plumbing is tested:
functionRuleskeys/values are correctly populated (step/flow/webhook entries, runtime conditional, triggers)nitro.options.sourcemap = trueis setnoExternalsmutation behaves correctly (and doesn't crash ontrue/false/missing — see blocking comment)- The
workflowSourcemapLoaderPluginproduces a{ code, map }shape when fed an esbuild-style inline sourcemap and falls through cleanly otherwise
Most of these are pure stub-driven assertions and would be cheap to add.
| * Extra esbuild options merged into every bundle this builder produces | ||
| * (steps, intermediate workflow, final workflow wrapper, webhook). | ||
| */ | ||
| esbuildOptions?: Partial<BuildOptions>; |
There was a problem hiding this comment.
AI Review: Nit
esbuildOptions: Partial<BuildOptions> is a broad surface for one knob
The new field accepts the full esbuild BuildOptions and is spread into four bundle calls with very different needs (steps: node/esm, workflow VM: neutral/cjs, webhook: node/esm, final wrapper: node/esm). The current spread order puts user options first so builder-required options like platform, format, bundle, plugins win — that's defensive — but the API still implies "you can pass any esbuild option" when in practice almost everything that matters is overridden.
Given the only consumer is sourcesContent: false, consider either narrowing the public type to a small allowlist or naming the field something closer to its actual purpose. Not blocking, but the surface area will be hard to take back later.
… maxDuration, guard sourcemap, use isNitroV2 in dev handler
Description
Currently we separately build the Workflows functions for the Vercel Build Output API when deploying a Nitro app to Vercel. This means the Workflows routes aren't part of the Nitro bundle.
This PR changes to now handle the Workflows routes as handlers within Nitro v3. Nitro v2 is untouched.
How did you test your changes?
Locally ran
nitro devin thenitro-v3workspace and visited the API routePOST /api/test-direct-step-call.PR Checklist - Required to merge
pnpm changesetwas run to create a changelog for this PRpnpm changeset --emptyif you are changing documentation or workbench appsgit commit --signoffon your commits)@vercel/workflowin a comment once the PR is ready, and the above checklist is complete