5分钟学会 vite

组成

为什么 vite 既用了 esbuild 又用了 rollup ?
esbuild 在开发阶段(vite dev)使用,主要用来预编译第三方依赖和编译业务代码里的 typescript 代码。esbuild 在抹平了第三方依赖的语法差异(第三方依赖不一定是 ESM 的语法)的同时,保证了 vite dev 的开发速度。
rollup 只会在 vite build 的时候执行构建,主要是构建生产环境可稳定使用的包,依然使用 rollup 是因为 rollup 成熟稳定,具有大量优秀的插件。

开发服务器

原理:浏览器支持 esm 模块

vite 在开发的时候不进行构建,只是将所有内容转换成 esm 的内容,依赖利用浏览器自己来识别,就和 live server 打开本地 index.html 文件一样。
比如 index.html 导入了一张图片,vite 就让浏览器去磁盘中图片本来的位置引入这个文件。而 webpack 开发时会执行构建,同样引入一张图片,因为构建,这张图片就会放在 index.html 同级的 img 文件夹中。

vite 通过浏览器这种原生识别 esm 的方式来处理依赖,还额外做了什么?
通过浏览器原生来构建可以,但是存在两个严重问题:

  1. 浏览器不识别其他文件,比如 .vue 文件。
  2. js 依赖第三方包的时候,浏览器会发送过多的网络请求。比如引入 lodash,首先必须写出 node_modules 下的完整路径进行引入,这是一个很不方便的地方;更严重的是 lodash 的入口文件依赖了很多其他的模块,浏览器都会一一去发起请求去下载这些模块,请求非常多。

vite 在基于浏览器原生支持 esm 的基础上,解决了上述问题,提供了更便捷的方式。

总结:
浏览器原生支持 esm,更准确的说法是浏览器支持模块化,工程化。既然浏览器支持模块化,为什么我们还要将代码构建成 jQuery 开发时代的样子呢?显然是没有必要的。这就是 vite 和 webpack 最大的不同点。
vite 开发时,就像一个增强版的 live server,和我们平时打开 live sever 一样,入口文件是 html,html 里面引入的文件,让浏览器去解析引入。
而 webpack ,html 文件只是一个简单的模板,真正的入口是一个臃肿的 js 文件。开发时,浏览器打开的是前端没有工程化时期的标准项目结构。

|-js
|-img
|-css
|-index.html

其他类型文件

正因为 vite 底层是利用浏览器支持 esm 进行工程化的特点,所以 vite 对于 css 文件,图片文件这些,压根不需要什么 loader,因为背后是浏览器来识别,只要浏览器能直接认识这些文件就行。
对于 less,postcss,ts 这些文件,也只要安装一下它们自己对应的处理程序就好,比如 less 的命令行工具,当它把 less 文件转为 css 文件后,浏览器就能识别了。
但是浏览器网络请求中查看请求,请求的文件名称依然是xxx.less,但是里面的内容其实是 css 内容,而不是 less。想也想得到啊,肯定不是 less ,浏览器压根不认识 less,要真是 less 请求下来了也执行不了。但样式被正确执行了,所以里面肯定是 css 内容。打开文件查看也确实是 css 内容。

请求转发

这背后的原因是因为对于浏览器中来说,html 才是入口文件,html 中 src 请求的是 less,所以网络请求的当然是 less。但是呢,我们不能让浏览器真去请求 less 文件是吧,所以 vite 实际是转发了请求,让浏览器实际去请求了 less 转换生成的 css 文件。这也是为什么说 vite 是增强版的 live server,因为如果是 live server 肯定傻乎乎的去请求 less 文件了。
这种转发请求的需求非常大,为此 vite 将开发服务器从 1.0 版本的 koa,到 2.0 版本换成了 connect,因为 connect 更适合转发请求。

基本使用

安装

vite 基于 node,所以需要先安装 node。

安装 vite 工具:

  • npm i vite -D局部安装
  • npm i vite -G全局安装

通过 vite 来启动项目:

  • npx vite

vite 会开启开发服务器后去请求根目录的index.html文件,并且以该文件作为入口处理依赖。

特色

依赖预构建

开发时,vite 会使用 esbuild 将某些依赖预构建成 esm 模块。比如一些第三方包。

另外,在生产构建中则会使用 @rollup/plugin-commonjs 进行构建。

为什么要预构建?有两个原因:

  1. 兼容性:开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将作为 CommonJS 或 UMD 发布的依赖项转换为 ESM。并且执行智能导入分析。
  2. 性能:Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。比如上面的 lodash-es 600 多个模块。通过预构建成一个模块,我们就只需要一个 HTTP 请求。

在提升开发性能方面,vite 也使用了缓存。
文件系统缓存
Vite 会将预构建的依赖缓存到 node_modules/.vite。
image.png
vite 根据数据源来决定是否需要重新运行预构建步骤:

  • package.json 中的 dependencies 列表,比如新安装了某个包
  • 包管理器的 lockfile,例如 package-lock.json, yarn.lock,或者 pnpm-lock.yaml
  • 在 vite.config.js 相关字段中配置

只有在上述其中一项发生更改时,才需要重新运行预构建。
如果出于某些原因,你想要强制 Vite 重新构建依赖,你可以用 --force命令行选项启动开发服务器,或者手动删除 node_modules/.vite 目录。

浏览器缓存
解析后的依赖请求会以 HTTP 头 max-age=31536000,immutable 强缓存,以提高在开发时的页面重载性能。

  • 一旦被缓存,这些请求将永远不会再到达开发服务器。
  • 如果安装了不同的版本(这反映在包管理器的 lockfile 中),则附加的版本 query 字段会自动使它们失效。

如果你想通过本地编辑来调试依赖项,你可以:

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

HTTP 缓存
栗子:
image.png
从上面请求可以看到,是从 .vite 中请求预构建好的包,只有一个网络请求。并且 url 中带有 query,表示当前模块版本,当模块更改则会自动请求最新的版本。
并且开发服务器的响应中要求了进行缓存。
image.png
页面刷新,同样的模块就是从缓存中被加载,并且并没有发送请求,连请求头都没有。包一旦被缓存,请求不会到达开发服务器。

预览

vite 基于生产 vite build 打包出的项目结构,也是传统的结构,毕竟这种结构才是真正通用的。
对于这种构建产物,想要预览一般使用 live server,但是 vite 内置了这个功能。

  • npx vite preview:开启一个本地服务来预览打包后的效果。

vite VS webpack

开发环境⚡️速度的提升
使用JS开发的工具通常需要很长的时间才能启动开发服务器,且这个启动时间与代码量、代码复杂度正相关。即使使用HMR,文件修改后的效果也要几秒钟才能在浏览器中反应出来,代表如Webpack。那么Vite是如何解决如Webpack这样的构建工具一样,在复杂、多模块项目开发中启动慢、HMR慢的问题呢?
我们详细对比了开发环境中的Vite和Webpack,发现主要有如下不同:

Webpack Vite
先打包生成bundle,再启动开发服务器 先启动开发服务器,利用新一代浏览器的ESM能力,无需打包,直接请求所需模块并实时编译
HMR时需要把改动模块及相关依赖全部编译 HMR时只需让浏览器重新请求该模块,同时利用浏览器的缓存(源码模块协商缓存,依赖模块强缓存)来优化请求
内存高效利用 -

因此,针对开发环境中的启动慢问题:

  • Vite开发环境冷启动无需打包,无需分析模块之间的依赖,同时也无需在启动开发服务器前进行编译,启动时还会使用 esbuild 来进行预构建
  • 而 Webpack 启动后会做一堆事情,经历一条很长的编译打包链条,从入口开始需要逐步经历语法解析、依赖收集、代码转译、打包合并、代码优化,最终将高版本的、离散的源码编译打包成低版本、高兼容性的产物代码,这可满满都是 CPU、IO 操作啊,在 Node 运行时下性能必然是有问题。

针对HMR慢:

  • 即使只有很小的改动,Webpack依然需要构建完整的模块依赖图,并根据依赖图来进行转换。
  • 而Vite利用了ESM浏览器缓存技术,更新速度与项目复杂度无关。
    • 可以看到,如Snowpack、Vite这类面相非打包的构建工具,在开发环境启动时只需要启动两个Server,一个用于页面加载,一个用于HMR的Websocket。
    • 当浏览器发出原生的ESM请求,Server收到请求只需要编译当前文件后返回给浏览器,不需要管理依赖。

image.png

使用简单,开箱即用
相比Webpack需要对entry、loader、plugin等进行诸多配置,Vite的使用可谓是相当简单了。
只需执行初始化命令,就可以得到一个预设好的开发环境,开箱即获得一堆功能,包括:CSS预处理、html预处理、异步加载、分包、压缩、HMR等。
他使用复杂度介于Parcel和Webpack的中间,只是暴露了极少数的配置项和plugin接口,既不会像Parcel一样配置不灵活,又不会像Webpack一样需要了解庞大的loader、plugin生态,灵活适中、复杂度适中。

插件

Vite 可以使用插件进行扩展,这得益于 Rollup 优秀的插件接口设计和一部分 Vite 独有的额外选项。插件让 vite 功能愈发强大和完善。

配置插件:

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

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

vite 插件

查找插件:
社区中提供了很多插件,可自行查找选择使用。
插件列表

vite.config.js

vite.config.js

vite 对 vue 的支持

vite 通过插件对 vue 提供第一优先级支持:

  • Vue 3 单文件组件支持:@vitejs/plugin-vue
  • Vue 3 JSX 支持:@vitejs/plugin-vue-jsx
  • Vue 2 支持:underfin/vite-plugin-vue2

安装:npm install @vitejs/plugin-vue -D

配置插件:

// vite.config.js
import vue from '@vitejs/plugin-vue'

export default {
    
    
  plugins: [vue()]
}

vite 脚手架

在开发中,我们不可能所有的项目都使用vite从零去搭建,比如一个react项目、Vue项目。这个时候vite还给我们提供了对应的脚手架工具。

所以Vite实际上是有两个工具的:

  • vite:相当于是一个构件工具,类似于 webpack、rollup;
  • @vitejs/create-app:类似 vue-cli、create-react-app;

使用脚手架创建项目:

  • 安装脚手架:npm install @vitejs/create-app -g
  • 使用:create-app 项目名称

填好名称,就可以选择想要创建的项目了,比如 vue 或者 react 等等。

官网提供了一种便捷的方式创建项目,它其实就是自动完成了脚手架的安装并使用。

  • npm create vite@latest

同样填好项目名后就可以选择项目框架了。

对于 vue 项目,可以直接使用npm init vue@latest创建。
它相当于进一步自动完成了上面的几个步骤,亲儿子果然不一样。

猜你喜欢

转载自blog.csdn.net/qq_43220213/article/details/129607396