This document describes the transform pipeline in Vite's development server, which handles the transformation of source files into browser-executable code. It covers the complete transformRequest flow, including module resolution, plugin hook execution, Oxc-based code transformation, and result caching.
For information about the plugin container that executes these hooks, see Plugin Container and Hook Execution. For details on how HMR updates trigger re-transformation, see Hot Module Replacement (HMR).
The transform pipeline is the core mechanism that converts source files (TypeScript, JSX, CSS, etc.) into code that can be executed in the browser. When the browser requests a module during development, Vite intercepts the request, transforms the module through a series of plugin hooks, and returns the processed code.
Vite 8 utilizes a dual-mode architecture where the dev server uses a PluginContainer to emulate the build-time pipeline provided by Rolldown.
Sources:
The transformRequest function orchestrates the entire transformation process. It is the main entry point called by the transformMiddleware for each module request.
The transform process uses multiple caching layers to ensure performance:
EnvironmentModuleNode.transformResult: Stores the latest successful transformation in memory packages/vite/src/node/server/transformRequest.ts48-55_pendingRequests: A Map in DevEnvironment that prevents duplicate transforms for concurrent requests to the same URL. It stores the request promise, a timestamp, and an abort function packages/vite/src/node/server/transformRequest.ts141-146etag package and stored in the TransformResult for browser-level 304 responses packages/vite/src/node/server/transformRequest.ts4 packages/vite/src/node/server/transformRequest.ts52The doTransform function handles the lifecycle of resolving, loading, and transforming a module.
| Step | Entity | Purpose |
|---|---|---|
| 1 | environment.moduleGraph.getModuleByUrl | Checks if a module node already exists for the URL packages/vite/src/node/server/transformRequest.ts158 |
| 2 | getCachedTransformResult | Validates if the existing memory cache is still fresh based on timestamps packages/vite/src/node/server/transformRequest.ts209-224 |
| 3 | pluginContainer.resolveId | Resolves the URL to a unique file system ID if no module node exists packages/vite/src/node/server/transformRequest.ts172 |
| 4 | loadAndTransform | Orchestrates the sequential execution of load and transform hooks packages/vite/src/node/server/transformRequest.ts191-199 |
| 5 | _registerRequestProcessing | Registers the promise so other systems (like HMR) can wait for completion packages/vite/src/node/server/transformRequest.ts203 |
Sources:
Once an ID is resolved, Vite enters the loadAndTransform stage which utilizes the EnvironmentPluginContainer.
The EnvironmentPluginContainer manages the execution of Rolldown/Rollup-compatible hooks:
load(id): Plugins can return source code and optional sourcemaps for an ID. If no plugin returns code, Vite falls back to reading the file from the file system packages/vite/src/node/server/pluginContainer.ts550-600transform(code, id): A sequential pipeline where each plugin modifies the code. Each step can return a new code string and a sourcemap packages/vite/src/node/server/pluginContainer.ts700-850Sources:
Vite ensures that sourcemaps remain accurate across multiple transformations by merging them at each stage of the pipeline.
Vite uses combineSourcemaps to merge multiple levels of sourcemaps into a single map that points back to the original source packages/vite/src/node/server/pluginContainer.ts73
For browser debugging, Vite can inject the sourcesContent directly into the map if it is missing, ensuring the original source is visible in DevTools even for virtual modules packages/vite/src/node/server/sourcemap.ts69-73
Vite supports the x_google_ignoreList extension to hide internal or node_modules files from debugger stack traces packages/vite/src/node/server/sourcemap.ts161-167 This is configured via the server.sourcemapIgnoreList option in ResolvedConfig packages/vite/src/node/server/index.ts180-182
Sources:
Vite's dev server is "on-demand," meaning it transforms files only when requested.
The cachedTransformMiddleware acts as a fast-path. It checks the If-None-Match header from the browser against the etag stored in the EnvironmentModuleGraph. If they match, it returns a 304 Not Modified status, avoiding any disk I/O or plugin execution packages/vite/src/node/server/middlewares/transform.ts89-106
Vite supports "soft invalidation," where a module is marked as potentially stale but its cached result can still be used if certain conditions (like HMR updates) allow for it packages/vite/src/node/server/transformRequest.ts219-224
If a module is invalidated (e.g., via a file change) while a transformation is already in progress, the transformRequest logic detects this by comparing the timestamp of the request with the lastInvalidationTimestamp of the ModuleNode. If the module was invalidated after the request started, the pending request is aborted and a new transformation is triggered packages/vite/src/node/server/transformRequest.ts112-126
Sources:
| Class/Function | File | Role |
|---|---|---|
transformRequest | transformRequest.ts | Orchestrates the resolution, loading, and transformation of a URL packages/vite/src/node/server/transformRequest.ts78 |
EnvironmentPluginContainer | pluginContainer.ts | Executes the resolveId, load, and transform hooks for a specific environment packages/vite/src/node/server/pluginContainer.ts175 |
transformMiddleware | middlewares/transform.ts | Intercepts HTTP GET requests for modules and calls transformRequest packages/vite/src/node/server/middlewares/transform.ts122 |
EnvironmentModuleNode | moduleGraph.ts | Holds the transformResult and metadata for a single module in an environment packages/vite/src/node/server/moduleGraph.ts104-105 |
combineSourcemaps | utils.ts | Merges a chain of sourcemaps into a single result packages/vite/src/node/utils.ts73 |
Sources:
Refresh this wiki