Appearance
Vite 的模块化加载流程与 module script 特性
Vite 利用了浏览器原生对 ECMAScript Module(ESM)的支持,让模块的加载和依赖解析直接由浏览器完成,因此可以天然地实现按需加载和懒加载。Vite 在开发时并不需要像传统打包工具那样提前打包所有代码,而是在浏览器请求某个源码文件时,即时地对源码中的模块进行转换,然后返回给浏览器。之后,浏览器会根据实际需要自动请求相关模块,从而大大提升了开发时的响应速度和构建效率。
1. 静态服务搭建
- Vite 启动时会自动搭建一个本地静态服务(dev server),监听前端资源请求。
2. 中间件拦截与资源处理
- Vite 内部通过中间件(middleware)拦截所有 HTTP 请求,根据不同类型资源进行处理:
JS 模块请求
路径重写与依赖解析
- 如果响应类型为
.js,先读取响应体内容。 - 使用
es-module-lexer分析 AST,提取import的模块名。 - 遍历所有依赖,判断是否为 npm 模块(即路径不以
.或/开头)。 - 对 npm 模块进行路径重写,如
vue=>/@modules/vue。
- 如果响应类型为
动态依赖请求
- 修改后的 JS 内容返回给浏览器。
- 浏览器解析 import 语句后,会继续请求
/@modules/vue这类模块。(ESM 天然支持按需加载和懒加载,未使用到的 npm 模块不会发起请求) - 中间件再次拦截,检测请求路径是否包含
/@modules/。 - 若是 npm 依赖,则将
/@modules/替换为空,/@modules/vue->vue,获取真实模块名并从node_modules中读取实际文件内容返回。
非 JS 静态资源
- 其它如 CSS/图片等资源,Vite 也有相应插件和中间件做专门处理,但主流程类似:拦截请求,按需转换,返回浏览器可识别的格式。
3. Vue 单文件组件(.vue)处理
- 浏览器原生不支持
.vue文件,因此 Vite 做了如下专门处理:
优先处理
.vue文件- 如果请求路径以
.vue结尾,说明是 SFC(单文件组件)。 - Vite 使用
@vue/compiler-sfc解析该文件,拆分出 template、script、style 等部分。
- 如果请求路径以
输出 JS 代码串
通过字符串拼接 JS 代码,并处理 import 的第三方依赖。
若是 template 部分,会在 URL 上加
?type=template,如App.vue?type=template供后续请求。
jsimport { render as __render } from "/App.vue?type=template" export default { data() { return { msg: 'Hello Vite!' } }, render: __render } // 样式部分会被 Vite 以 <style> 注入或通过 CSS 插件处理模板编译
- 浏览器请求 template 部分时,Vite 检查
ctx.query.type,若为 template,则用compileTemplate将 HTML 模板编译成 AST,再生成渲染函数。
- 浏览器请求 template 部分时,Vite 检查
依赖递归解析
- .vue 文件中如有其它依赖(包括 npm 包、其它 .vue 文件),继续递归上述步骤,直到所有依赖被浏览器加载完成。
4. 典型工作流小结
- 浏览器加载
index.html,发现<script type="module" src="main.js"> - main.js 中 import 了
App.vue,Vite 拦截/App.vue,转换为 JS - App.vue import 了第三方依赖
vue,被重写成/@modules/vue,由 Vite 处理并返回 node_modules 下的实际代码 - App.vue 中的 template 被请求为
/App.vue?type=template,用 Vue 编译器编译为 render 函数 - 所有依赖递归加载,最终完整挂载页面
5. 优势及特性
- 即时依赖解析:按需请求和转换源码,无需预打包。
- 极致开发体验:修改文件秒级热更(HMR),无全量打包等待。
- 利用浏览器原生能力:模块依赖解析、缓存、并发加载都交给浏览器完成。
- 灵活中间件体系:可扩展自定义文件类型处理流程。
6. 补充说明
- 生产环境构建:Vite 开发时利用 ESM,生产阶段采用 Rollup 打包生成兼容传统浏览器的 bundle。
- 多种资源类型支持:Vite 通过插件机制扩展对 CSS、JSON、图像、Web Worker 等资源的模块化支持。
- 动态 import:Vite 支持原生
import()语法,只有真正需要的模块才会被请求和处理。