[Proposal] Viteless Vitest (Engine-Agnostic API) #10271
Replies: 5 comments 5 replies
-
|
Would there be support for native Node.JS as a "framework"? This would actually be the main attraction for me - using vitest with native TS support and native loaders/resolvers in Node. |
Beta Was this translation helpful? Give feedback.
-
|
What would this mean for cross-framework setups? Right now we have project-level configs (previously workspaces) which would then be rolled up into the root workspace but this feels like an intentional departure from this approach? |
Beta Was this translation helpful? Give feedback.
This comment was marked as off-topic.
This comment was marked as off-topic.
-
|
There has been some confusion because of the naming of the proposal. The framework in the name is a more generic term, not the frontend framework (like sveltekit or nuxt which are supported already because they use vite). The proposal is about a generic interface that Vitest could understand without relying on After some discussion we think that |
Beta Was this translation helpful? Give feedback.
-
|
I'm reading this is a combined proposal to solve #9664 (comment) and #9501 (comment). If so, is there a path in this proposal for people to compose engines together? I don't want to get rid of Vite's bundling, etc, because my code ends up bundled; but I do want to run the tests on a different runtime (Deno) in addition to Node.js. The way I read this proposal, it's locking people into any one runtime + any one bundler instead of many runtimes + any one bundler (e.g. #10271 (comment)). Is there a way in this proposal to keep Vite while running on (multiple) non-Node.js runtimes, or is that a separate discussion? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Note
The original proposal referred to the new contract as a "framework". After some discussion, the team decided to rename it to "engine" to avoid confusion with frontend frameworks. Vitest already supports many frameworks built on top of Vite; this proposal focuses on supporting more ways to run code, including non-Vite frameworks and no-bundler approaches.
Vitest's tight coupling with Vite has historically been one of its greatest strengths: instant HMR, a unified config, and a shared plugin ecosystem made it the natural choice for projects already invested in the Vite toolchain. That same coupling has also become its most significant constraint. As Vitest matures into a general-purpose test runner, the assumption that every consumer wants (or can afford) a full Vite pipeline in their test process is increasingly hard to justify.
A test runner's job is to execute tests reliably and quickly; everything else, including the transformation pipeline, module graph, and dev server, exists to support that. Decoupling these concerns would let Vitest meet users where they are, whether that's a Webpack-based monorepo, a pure Node service, a Deno project, or a Bun-first codebase.
Summary
Add an
--engineflag that points to a package responsible for adapting Vitest to a specific build/runtime environment. The engine package exports a set of instructions (classes/exports/utilities) that Vitest's core uses through a stable contract, and it owns config resolution for that environment. Vite becomes one such engine, shipped as the default. Other engines (esbuild, rsbuild, Rolldown, Oxc, native Node, Deno, Bun, Webpack) can be written independently.Motivation
Vitest's runner, expectations, snapshotting, mocking, reporters, and watch UX already do not rely on any of the Vite features. The coupling to Vite lives at the edges: transforming source files, resolving modules, hot-reloading, serving assets, and the config pipeline itself, which today is
vite.config.tswith atestfield. A real extension point would let users pick a different transformer or runtime without forking the runner, and would let the Vitest team treat Vite as one of several integrations instead of the only one.Prior Art
This proposal is inspired by
unpluginproject, which lets a single plugin work across many build tools by writing it against a shared contract. Vitest's contract goes the other way (one host plugging into many backends rather than one plugin plugging into many hosts), but the basic idea of a small, stable interface between core and adapter packages is the same.Proposal
An engine is a regular npm package that the user references by name on the command line:
The flag is CLI-only on purpose. The engine is what decides what a config file looks like and how it gets loaded. So the framework choice has to come from one of: the
--engineflag, an environment variable, or a small top-level marker file that Vitest reads before anything else. The exact discovery rules will be settled in implementation.The package's main export could be a factory that returns a set of instructions Vitest's core uses to:
The exact shape of these instructions (which functions, properties, classes, exports) is left open in this RFC on purpose. It will be pinned down in a follow-up once we have at least two non-Vite implementations to compare against.
Vitest's startup becomes: read the
--engineflag, load that package, ask for its instructions, hand config resolution off to it, and then drive the rest of the runner against the returned contract. Everything not covered by the contract (the test runner,expect, mocking, snapshots, reporters, the UI, coverage) keeps working unchanged.Migration
No breaking changes for existing users. Omitting
--engineresolves to@vitest/engine-vite, which preserves today's behavior, including readingvite.config.ts/vitest.config.tsand accepting thetestfield. The currentviteModuleRunner: falsemode becomes the prototype for a@vitest/engine-nodeadapter and is the obvious first non-Vite engine to ship.Open Questions
--engineoutside the CLI: env var, marker file,package.jsonfield, or some mix, given that a config file can't be the source of truth.Non-Goals
Beta Was this translation helpful? Give feedback.
All reactions