浅谈Vite | 青训营笔记

195 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的的第10天

官网

为什么需要Vite?(前端工程痛点)

vite.png

  • 模块化:ESM、CommonJS、UMD
  • 资源编译:高级语法(>ES6)、TS的转译、CSS预处理
  • 产物质量:代码体积(冗余?压缩?)、代码性能
  • 开发效率:热更新
  • 。。。

前端构建工具的意义

前端工程化.png

什么是Vite?

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

两大组成部分

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

核心特征

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

当下问题

缓慢的启动 ⇒ 项目编译等待时间长

缓慢的热更新 ⇒ 修改代码后不能实时更新

瓶颈在何处?

  1. bundle 带来的性能开销 ⇒ 不bundle了

    1. 浏览器原生ESM支持,天然的按需加载

      ESM.png

    2. 无需打包项目源代码

    3. 可以利用文件级的浏览器缓存

  2. JavaScript 语言的性能瓶颈 ⇒ 用Rust、Go

基于Esbuild的编译性能优化

Esbuild —— 基于Golang开发的前端工具

  1. 打包器 Bundler
  2. 编译器 Transformer
  3. 压缩器 Minifier

Vite 使用 esbuild 将 TypeScript 转译到 JavaScript,约是 tsc速度的 20~30 倍,同时 HMR 更新反映到浏览器的时间小于 50ms。

内置 Web 构建能力

内置许多开箱即用的功能,大大减少了使用webpack时基础配置的时间。

上手使用

项目初始化

# 安装pnpm
# npm i -g pnpm

# 初始化命令
pnpm create vite

# 安装依赖
pnpm install

# 启动项目
pnpm run dev

使用Sass

使用CSS Module模块化方案,防止ClassName命名冲突。

sass

生产环境Tree-shaking

  1. 基于ESM的import/export语句依赖关系,与运行时状态无关。
  2. 在构建阶段将未使用到的代码进行删除。

commonjs.png

Vite整体架构

image.png

Pre-bundle预打包

  1. 避免node_modules过多的文件请求:

    1. 一些包将它们的 ES 模块构建作为许多单独的文件相互导入。例如,lodash-es 有超过 600 个内置模块!当我们执行 import { debounce } from 'lodash-es'  时,浏览器同时发出 600 多个 HTTP 请求!尽管服务器在处理这些请求时没有问题,但大量的请求会在浏览器端造成网络拥塞,导致页面的加载速度相当慢。
    2. 依赖预构建仅会在开发模式下应用,并会使用 **esbuild**将依赖转为 ESM 模块。在生产构建中则会使用 @rollup/plugin-commonjs
  2. 将CommonJS / UMD格式转化为ESM格式。

如何实现?

  1. 服务启动前扫描代码中用到的依赖。

  2. 用esbuild对依赖代码进行预打包。

  3. 改写import语句,指定依赖为预构建产物路径。

    prebundle.png

文件系统缓存

Vite 会将预构建的依赖缓存到 node_modules/.vite。它根据几个源来决定是否需要重新运行预构建步骤:

  • package.json 中的 dependencies 列表
  • 包管理器的 lockfile,例如 package-lock.jsonyarn.lock,或者 pnpm-lock.yaml
  • 可能在 vite.config.js 相关字段中配置过的

如果出于某些原因,你想要强制 Vite 重新构建依赖,你可以用 --force命令行选项启动开发服务器,或者手动删除 node_modules/.vite目录。

HTTP缓存

依赖是强缓存的: Vite 通过 HTTP 头max-age=31536000,immutable来缓存请求得到的依赖,以提高在开发时的页面重载性能。一旦被缓存,这些请求将永远不会再到达开发服务器。如果更换了新的版本的依赖,你可以:

  1. 通过浏览器调试工具的 Network 选项卡暂时禁用缓存;
  2. 重启 Vite dev server,并添加 -force 命令以重新构建依赖;
  3. 重新载入页面。

使用插件

Vite 可以使用插件进行扩展,这得益于 Rollup 优秀的插件接口设计和一部分 Vite 独有的额外选项。这意味着 Vite 用户可以利用 Rollup 插件的强大生态系统,同时根据需要也能够扩展开发服务器和 SSR 功能。

若要使用一个插件,需要将它添加到项目的 devDependencies并在 vite.config.js配置文件中的 plugins数组中引入它。

npm add -D @vitejs/plugin-legacy

// vite.config.js
import legacy from '@vitejs/plugin-legacy'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    legacy({
      targets: ['defaults', 'not IE 11']
    })
  ]
})

语法安全降级

  • 上层解决方案:@vitejs/plugin-legacy

  • 底层原理

    • 借助Babel Transpile(转译)代码

      babel.png

    • 提前注入Polyfill(垫片),如core-js、regenerator-runtime

服务端渲染

SSR.png

底层标准

底层标准.png