One Graph, Two Objectives: Reconstructing Vite Before Production
A Vite application becomes easier to reason about when one ordinary page is treated as a set of cooperating responsibilities rather than as “the build.” This checkpoint connects the browser request, dependency optimizer, module graph, cache, plugin pipeline, file watcher, and HMR channel so the reader can diagnose where work happens and why. It also establishes the precise boundary that production must cross: the source relationships remain meaningful, but their delivery shape must change.
Imagine a page with an HTML entry, a main module, a framework component, a stylesheet, an image, and a package from npm. The page is small enough to describe, but it exercises nearly the whole development model. Vite does not assign one undifferentiated operation to this page. Each relationship is handled by the layer that owns it.
One page, several owners
The HTML entry tells the browser which module begins the application. Vite treats that HTML as source, so it can process the module script, CSS references, and recognized asset references. The browser requests the entry module, and Vite's plugin pipeline resolves it, loads it, and transforms it. If the module imports a component, the browser asks for that component, and the same request-driven path continues.
The plugin pipeline owns the question “what does this identifier mean, and what code should be returned for it?” A framework plugin may compile a component file. Vite's own transforms may turn TypeScript or JSX into browser-executable JavaScript. An asset plugin may turn an imported image into a URL module. These are transformations, not dependency optimization and not HMR decisions.
The dependency optimizer owns a narrower but important boundary. When the main module reaches a bare npm import, the browser cannot resolve the package name on its own. If the package is CommonJS or internally split into many modules, direct browser loading would also be awkward or expensive. The optimizer prepares an ESM-compatible development module and stores it in its cache. The browser can then request the rewritten optimized URL while application source continues to be served on demand.
The module graph owns relationships and state. It records that the entry imports the component, that the component imports the stylesheet and image, and that the entry or component imports the optimized dependency. It also associates transformed results with module identities and remembers which modules import one another. That information is what lets Vite distinguish a changed component from every other file in the repository.
The file watcher owns the trigger for a source edit. The HMR system then uses the graph to decide whether the change can be accepted at a boundary, propagated to an importer, or escalated to a full reload. The hot channel owns delivery of the update to the browser. None of these layers is interchangeable. A stale dependency cache is not fixed by adding an HMR handler; a missing HMR boundary is not fixed by pre-bundling a package.
This separation gives a complete development loop without calling every step “the build.” A source module is resolved, loaded, transformed, recorded, and cached. A dependency is discovered, made compatible, optimized, and cached under a different policy. A changed file is invalidated, traced through importers, and either accepted or reloaded.