实现一个 Mini Vite
Wip...
这是一个系列文章,主要面对那些想了解 Vite 基础原理的读者。当然,其实更多的是记录我自己的学习过程,如有错误,欢迎指正 »
Vite 主要特性和优势
Vite 是一个现代化的前端构建工具,它具有以下主要特性和优势:
- 极快的冷启动: 利用原生 ES 模块,无需打包即可直接启动开发服务器。
- 即时的热模块替换(HMR): 精确和快速的更新,无需刷新页面。
- 真正的按需编译: 只编译浏览器请求的内容,大大提高了开发效率。
- 优化的构建: 使用 Rollup 进行生产环境构建,输出高度优化的静态资源。
- 通用的插件接口: 支持开发和构建两种场景的插件 API。
- 完全类型化的 API: 使用 TypeScript 编写,提供完整的类型定义。
为了更直观地展示 Vite 的工作流程,我们可以使用一个流程图来说明:
开发服务器
Vite的开发服务器基于原生ES模块实现,主要特点包括:
- 中间件架构:使用 Connect 作为中间件框架,处理各种 HTTP 请求。
- 模块重写:拦截浏览器的 ES 模块请求,进行路径重写和内容转换。
- 按需编译:只在浏览器请求模块时才编译它们,大大加快了启动速度。
- 源码映射:为转换后的代码生成 sourcemap,方便调试。
依赖预构建
- 原因:
- 统一格式,cjs 和 umd 到 esm 模块
- 性能:将有许多内部 esm 模块的依赖项转为单个模块
- 缓存处理:
- 预构建依赖使用强缓存
- 源码模块使用协商缓存
- 裸模块导入转换
HMR
Vite 的 HMR 机制基于原生 ES 模块,实现了精确的更新而无需刷新整个页面:
- WebSocket 通信:服务器和客户端通过 WebSocket 保持连接,实时通知更新。
- 模块图:维护一个模块依赖图,精确定位需要更新的模块。
- 边界分析:确定更新的边界,只重新执行必要的模块。
- 状态保留:尽可能保留应用程序的状态,只更新变化的部分。
构建优化
Vite 在生产环境使用 Rollup 进行构建,采用了多种优化策略:
- css 代码分割:异步加载的模块,它所加载的 css 也会被单独打包成一个模块。
- 预加载指令生成:为入口 chunk 和 HTML 中直接引入自动生成的
<link rel="modulepreload">指令。 - 异步 chunk 加载优化:vite 会扫描所有异步 chunk 并找到他们之间的共同依赖,并打包为一个单独的文件,减少网络请求嵌套和模块被重复加载的问题。
- 资源内联:小型资源内联到 bundle 中,减少 http 请求。
- Tree Shaking:消除未使用的代码,减小最终包的大小。