Vite学习 | 青训营

75 阅读4分钟

一、vite的简介

  1. 定位:新一代前端构建工具
  2. 两大组成部分: No-bundle开发服务,源文件无需打包、生产环境基于rollup的bundler 3.核心特征:
  • 高性能、简单易用
  • 超快的冷服务器启动
  • 即时的模块更新
  • 真正的按需编译
  • 更小的打包体积

二、vite使用

项目初始化

  • 提前安装 pnpm:npm i -g pnpm
  • 初始化命令:pnpm create vite
  • 安装依赖:pnpm install
  • 启动项目:npm run dev

三、 vite 整体架构

3.1 关键技术:依赖预打包

  • 预打包原因:避免node_modules 过多的文件请求、将commomjs格式转换为esm格式

  • 实现原理:服务启动前扫描代码中用到的依赖、用esbuild对依赖代码进行预打包、改写import语句,指定依赖为预构建产物路径

3.2 关键技术:单文件编译

用esbulid编译TS/JSX、

  • 优势:编译速度提升10-100x
  • 局限性:不支持类型检查、不支持语法降级到ESS

3.3 关键技术:代码压缩

esbulid 作为默认压缩工具,替换传统的Terser、Uglify.js等压缩工具

3.4 关键技术:插件机制

  • 开发阶段:模拟rollup 插件机制
  • 生产环境:直接使用rollup

四、vite 插件开发

  • 代码分割:拆包

问题:无法进行并发请求、缓存复用率低

  • js编译工具
  • 语法安全降级
  • 服务器渲染SSR

五、 Vite原理

5.1 ESM&esbuild

1.ESM:

在ES6没有出现之前,随着js代码日益膨胀,往往会对资源模块化来提效,这也就出现了多个模块化方案。如CommonJS常用于服务端,AMD、CMD规范常用在客户端。ES6出现后,紧接着出现了ESM。ESM是浏览器支持的一种模块化方案,允许在浏览器实现模块化。

  • CommonJS:模块同步,如Browserify会对代码进行解析,整理出代码中的所有模块依赖关系,然后把nodejs的模块编译成浏览器可用的模块,相关的模块代码都打包在一起,形成一个完整的JS文件,这个文件中不会存在 require 这类的模块化语法,变成可以在浏览器中运行的普通JS,运行时加载
  • AMD:模块异步,依赖前置,是requireJS在推广过程中对模块定义的规范化产出,加载完依赖后立即执行依赖模块,依赖加载成功后执行回调
  • CMD:模块异步,延迟执行,是seaJS在推广过程中对模块定义的规范化产出,就近依赖,先加载所有依赖模块,运行时才执行require内容,按顺序执行

与CommonJS、AMD不同,ESM的对外接口只是一种静态定义,为编译时加载,遇到模块加载命令import,就会生成一个只读引用。等脚本真正执行时,再根据这个只读引用,到被加载的那个模块内取值。由于ESM编译时就能确定模块的依赖关系,因此能够只包含要运行的代码,可以显著减少文件体积,降低浏览器压力。

2.esbulid: Vite 对 js/ts 的处理没有使用如 glup, rollup 等传统打包工具,而是使用了 esbuild。esbuild 是一个全新的js打包工具,底层使用了go,大量使用了并行操作,可以充分利用CPU资源。esbuild支持如babel, 压缩等的功能。

对比各打包工具性能,可以看到esbuild比rollup等工具快十几倍。

5.2 请求拦截:

Vite 的基本实现原理,就是启动一个 koa 服务器拦截由浏览器请求 ESM的请求。通过请求的路径找到目录下对应的文件做一定的处理最终以 ESM的格式返回给客户端。

5.3 热更新原理:

Vite 的热加载原理,其实就是在客户端与服务端建立了一个 websocket 连接,当代码被修改时,服务端发送消息通知客户端去请求修改模块的代码,完成热更新。

  • 服务端:服务端做的就是监听代码文件的改变,在合适的时机向客户端发送 websocket 信息通知客户端去请求新的模块代码。
  • 客户端:Vite 中客户端的 websocket 相关代码在处理 html 中时被写入代码中。可以看到在处理 html 时,vite/client 的相关代码已经被插入。