Vite的学习 | 青训营

73 阅读6分钟

前端项目的痛点

  1. 模块化

ESM (ECMAScript Modules)、CommonJS、UMD (Universal Module Definition) 都是前端模块化的不同标准或方法,它们各自有自己的特点和用途。然而,这些不同的模块化方法也可能会引发一些前端项目中的问题或挑战。 1)兼容性问题: 不同的模块化方法在不同的环境中支持程度不同。 2)构建配置复杂性: 由于不同的模块化方法在不同的环境中使用,项目可能需要根据目标环境来配置不同的构建流程。 3)性能问题: 不同的模块化方法可能对性能产生影响。例如,ESM 支持静态分析,使得一些优化变得可能,但在一些情况下可能会引入额外的网络请求。CommonJS 则是动态加载模块,可能会导致较大的启动延迟。 4)代码体积: 使用不同的模块化方法,可能会导致在最终的构建文件中引入不必要的模块化代码,从而增加项目的代码体积。 5)开发者团队技能: 项目中使用多种模块化方法可能需要开发团队具备更多的技能,因为开发者需要熟悉不同的模块化语法和配置。 2. 资源编译 前端资源编译是指将开发阶段的源代码(如HTML、CSS、JavaScript等)进行处理和优化,生成适合部署到生产环境的最终文件。 前端开发领域不断涌现新的技术和工具,可能需要不断更新构建工具和流程,以适应新技术的引入。 3. 产物质量 代码体积过大会导致加载时间增加网络传输成本首次渲染延迟缓存问题 代码性能会导致运行时性能问题内存占用增加 5. 开发效率

前端项目的核心要素

简单来说前端项目核心要素就是资源,这些资源可以是逻辑代码(js、ts、jsx...)、样式代码...

Snipaste_2023-08-14_20-20-06.png

前端构建工具的意义

  1. 模块化方案:提供模块加载方案、兼容不同模块规范
  2. 语法转译:高级语法转译(Sass、TS);资源加载(图片、字体、worker)
  3. 产物质量:产物压缩、无用代码删除、语法降级
  4. 开发效率:热更新

Vite

定位:新一代前端构建工具

  1. No-bundle开发服务,源文件无需打包
  2. 生产环境基于Rollup的Bundler

核心特征

  1. 高性能,dev启动速度和热更新速度非常快!
  2. 简单易用,开发者体验好

基于原生ESM开发的服务优势

  • 无需打包项目源代码,减少了bundle的性能开销
  • 天然的按需加载
  • 可以利用文件级的浏览器缓存

vite的使用

项目初始化

npm i -g pnpm
pnpm create vite
pnpm install
npm run dev

使用Sass/Scss & CSS Module

pnpm install sass --save-dev

创建样式文件: 在你的项目中创建一个 Sass/Scss 样式文件,例如 styles.scss使用 CSS 模块: 在 Vite 中使用 CSS 模块非常简单。只需在 CSS 文件名中添加 .module 后缀即可。 例如,如果你的样式文件名是 styles.module.scss,则 Vite 将会自动将它识别为 CSS 模块。 在组件中使用样式: 在你的组件中,你可以通过导入样式来使用 CSS 模块。

<template>
  <div class="my-component">This is a component</div>
</template>

<style module>
.my-component {
  color: red;
}
</style>

在上面的例子中,.my-component 类名是局部作用域的,不会影响到其他组件。 在样式中使用变量和混合器(Mixins): 你可以像往常一样在 Sass/Scss 样式中使用变量和混合器。

// styles.module.scss

$primary-color: blue;

.my-component {
  color: $primary-color;
}

编译和启动开发服务器: 运行 Vite 的开发服务器来查看样式的效果。

npm run dev

使用 HMR

Vite 的 HMR(热模块替换)功能,可以让你在开发过程中更加高效地实时查看代码变化的效果,而无需手动刷新页面。 无需额外配置,自动开启。

生产环境Tree Shaking

Vite 在生产环境中自动进行 Tree Shaking,这是一种优化技术,用于移除未使用的代码,从而减小最终构建产物的体积。Tree Shaking 可以有效地删除不被项目使用的代码,以提高应用程序的性能和加载速度。在 Vite 中,Tree Shaking 是默认开启的,无需额外配置。 Snipaste_2023-08-14_20-20-06.png

优化原理

  1. ES 模块系统: ES 模块系统是 JavaScript 的一种模块化规范,它具有静态性质,这意味着模块之间的依赖关系在代码编译时就能够被确定下来,而不是在运行时。这为 Tree Shaking 提供了实现的基础。
  2. 静态分析: 在代码编译阶段,编译器可以通过静态分析的方式,检查模块之间的依赖关系。通过分析模块导出和导入的关系,编译器可以确定哪些模块、变量、函数等被其他模块引用,以及哪些没有被引用。
  3. 标记未引用代码: 编译器通过静态分析标记出哪些代码被其他模块引用,哪些代码没有被引用。标记未引用代码的方式通常是在编译时创建一个标记表,记录每个变量、函数等是否被引用。
  4. 优化和剪裁: 一旦标记出未引用的代码,编译器就可以在构建过程中将这些未引用的代码从最终的构建产物中删除。这样就可以实现在构建产物中只保留那些真正被使用的代码,从而减小文件体积。
  5. 动态导入处理: 需要注意的是,动态导入(Dynamic Import)在静态分析阶段无法被完全解析,因为它们是在运行时才会被执行的。然而,现代的工具和编译器可以通过一些启发式的方法,尽量在编译时预测动态导入的情况,以便进行更好的优化。

Vite 整体架构

Snipaste_2023-08-14_20-52-11.png

关键技术

依赖预构建

依赖预构建主要有两个目的:

  • CommonJS 和 UMD 兼容性:  开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将作为 CommonJS 或 UMD 发布的依赖项转换为 ESM。
  • 性能:  Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。

Vite使用esbuild在初次启动开发服务器前把检测到的依赖进行预构建。Vite 基于ESM,在使用某些模块时,由于模块依赖了另一些模块,依赖的模块又基于另一些模块。会出现页面初始化时一次发送数百个模块请求的情况。

代码压缩

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

热更新原理

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

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