前言

若文章有误,欢迎读者留言反馈

兼容性注意:
Vite需要 Node.js 版本 14.18+16+。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。

认识Vite

Webpack是目前整个前端使用最多的构建工具,但是除了webpack之后也有其他的一些构建工具:

  • 比如rollupparcelgulpvite等等
  • rollup一般用来打包一些框架,更为常见;
  • parcel号称零配置的打包工具,但是本身比较大,用的会比较少一点;
  • gulp用来做自动化比较多一点;

什么是vite呢?官方的定位∶下一代前端开发与构建工具;
如何定义下一代开发和构建工具呢?

  • 我们知道在实际开发中,我们编写的代码往往是不能被浏览器直接识别的,比如ES6TypeScriptVue文件等等;
  • 所以我们必须通过构建工具来对代码进行转换、编译,类似的工具有webpackrollupparcel;
  • 但是随着项目越来越大,需要处理的JavaScript呈指数级增长,模块越来越多;
  • 构建工具需要很长的时间才能开启服务器,HMR也需要几秒钟才能在浏览器反应出来;

Vite(法语意为”快速的”,发音/it/)是一种新型前端构建工具,能够显著提升前端开发体验。

Vite的构造

它主要由两部分组成:

  • 一个开发服务器,它基于原生ES模块提供了丰富的内建功能,HMR的速度非常快速;
  • 一套构建指令,它使用rollup打开我们的代码【内置rollup】,并且它是预配置的,可以输出生成环境的优化过的静态资源;

浏览器原生支持模块化

创建一个目录作为项目根目录,在里面创建一个src文件夹和一个main.js文件,在其中随便写点代码:

1
console.log("Hello World")

再到src文件夹下创建一个js文件夹,再创建一个math.js文件,书写一点js代码

1
2
3
export function sum(num1, num2) {
return num1 + num2
}

然后导入到main.js文件中

1
2
3
4
import { sum } from "./js/math"

console.log("Hello World")
console.log(sum(1, 2))

接着再到项目根目录下创建一个index.html文件,再把main.js引入

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./src/main.js" type="module"></script>
</body>
</html>

我们来运行这个html文件,由于没有构建工具,那么它是否能打印出结果呢?
先说结论吧,对于版本比较高的浏览器已经支持ES Module,刚刚写的import其实已经支持了,但是现在浏览器控制台运行是报错的,如果想要让浏览器认识main.js模块,必须给script添加一个属性type="module"
添加这个属性,就相当于浏览器解析时允许代码使用ES Module

接着再次运行,但是浏览器控制台依然是报错的,它说这个math找不到,注意这时我们再回头看一下刚刚导入math是似乎没加后缀名,那么这里就得注意了,原生的ES Module后缀名都是不能掉的,之前在webpackjs文件能省去,那是因为webpack有自己的查找规则,它会一个一个后缀名进行添加查找,所以这里的后缀名得加上

1
2
3
4
5
-import { sum } from "./js/math"
+import { sum } from "./js/math.js"

console.log("Hello World")
console.log(sum(1, 2))

然后浏览器就能正常显示了
既然浏览器能直接识别我这里的代码,如果开发里我还写了request.js文件代码里面也是ES6代码,这些代码加在一起都是模块化的,而浏览器也是支持模块化的,是不是完全意味着开发阶段不需要用构建工具,那就省去了构建这个过程,直接运行就行了;等到真正打包上线的时候,因为我们要适配更多的用户的浏览器,某些用户使用浏览器可能就不支持ES6了,我们等到打包的时候再做构建转成ES5的代码

其实这也就是Vite的基本思想
目前只是写的ES6代码,万一还有ts文件和vue文件,这肯定是没办法直接跑到浏览器上的,就算是现在最新的浏览器它也不支持
那不支持,该怎么办呢?
Vite它将这些不识别的代码做了一个转化,转换为浏览器能识别的ES Module代码

虽然我们目前这些代码能跑,可是一旦有了ts代码,就不能跑了,所以还是需要构建工具

先在项目根目录下初始化一个package.json文件

1
2
3
4
# 创建package.json
npm init
# 快速创建package.json
npm init -y

再安装一个lodash-es

1
npm install lodash-es -S

main.js导入使用

1
2
3
4
5
6
7
8
9
10
11
import _ from 'lodash-es'

// import { sum } from "./js/math"
// 原生后缀名不能掉
import { sum } from "./js/math.js"

console.log("Hello World")
console.log(sum(1, 2))

// 使用lodash
console.log(_.join(['abc', 'def'], '-'))

但是这样浏览器运行是无法加载lodash的,在webpack中是有专门的包对这种路径做解析的,浏览器它是无法加载的,不认识,应该换为下面这种写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
// import _ from 'lodash-es'
// 浏览器无法加载上面这个包,找不到这个包所在位置
+import _ from '../node_modules/lodash-es/lodash.default.js'

// import { sum } from "./js/math"
// 原生后缀名不能掉
import { sum } from "./js/math.js"

console.log("Hello World")
console.log(sum(1, 2))

// 使用lodash
console.log(_.join(['abc', 'def'], '-'))

但是这种方式是有弊端的,在浏览器控制台network中,我们刷新一下,是可以看到浏览器有很多请求的,lodash依赖了很多其它文件,浏览器就会认为也要加载,就会把这些文件全部都加载出来,每个js文件都要发一次请求,浏览器再解析这么多文件是非常消耗性能的,虽然没有使用构建工具,源代码也能跑起来,但是会有两个弊端:

  1. 某些文件是不识别的【ts文件、vue文件】
  2. 如果包之间的依赖太多,那么会发送过多的网络请求

vite它会帮我们解决。

Vite的安装和使用

注意: Vite本身也是依赖Node的,所以也需要安装好Node环境
首先,我们安装一下vite工具︰

1
2
3
4
# 全局安装
npm install vite -g
# 局部安装
npm install vite -D

这里我们只需要对于我们的这个项目进行打包,所以这里我们就用局部安装
使用一下vite

1
npx vite

执行完它就会我们搭建好本地服务,浏览器上运行显示正常,这个vite它对我们的源代码做了一个构建,然后搭建了一个本地服务,浏览器访问时,访问的是vite搭建的这个本地服务,然后vite这个服务就会给我们提供这里的源代码
但是这样似乎和原来没有什么区别,这里来看第一个区别:

  1. 导入文件时不需要加后缀名,vite它会帮自动我们加上后缀名的;
  2. 想从node_modules导入某个包,直接写上包名即可,不需要原来那样路径写很长;
  3. network中查看请求,它只有常见的几个请求了,因为它帮我们做了个打包,lodash虽然比较大,但是没有之前那么多http请求

Vite对于css、less的支持

src文件夹中创建个css文件夹,再在其中创建个style.css文件

1
2
3
body {
background-color: skyblue;
}

加入依赖图,它才会进行构建、打包
回到main.js文件中

1
2
// 导入样式
import "./css/style.css"

回到浏览器样式生效了,这也说明了vite默认就对css做了处理,不需要像webpack那样再做什么css-loaderstyle-loader处理
接着我们再到main.js文件中创建个空标签
1
2
3
4
const titleEl = document.createElement('div')
titleEl.className = "title"
titleEl.innerHTML = "Hello vite"
document.body.appendChild(titleEl)

再到css文件夹下创建一个title.less文件

1
2
3
4
5
6
7
@fontSize: 50px;
@fontColor: pink;

.title {
font-size: @fontSize;
color: @fontColor;
}

加入依赖图中,回到main.js文件中

1
import "./css/title.less"

这时下方也很快的出现了报错
[vite] Internal server error: Preprocessor dependency "less" not found. Did you install it?
大概意思是:我们当前预处理器它需要依赖我们less工具,但这个less工具没有找到,你安装了less工具吗
之前webpack也是需要依赖less工具[lessc],只不过在vite中,不需要less-loader,但是less工具依然还是要安装
局部安装less工具【注意停掉服务】:

1
npm install less -D

重新跑下服务,less文件就生效了

我们再来验证一下postcss,比如浏览器加上前缀,回到title.less文件中

1
2
3
4
5
6
7
8
9
@fontSize: 50px;
@fontColor: pink;

.title {
font-size: @fontSize;
color: @fontColor;
// 验证浏览器前缀
user-select: none;
}

浏览器上查看它是并没有帮我们加上浏览器前缀的,这时我们需要加上,一般会这样做:

  1. 我们还是需要postcss这个工具,用它来做转化
    1
    npm install postcss -D

注意postcss已经集合为一个小的生态,它还是需要相应的插件去实现功能,添加前缀我们可以使用之前autoprefixer插件,但是我们使用postcss-preset-env更多,它已经内置了autoprefixer插件
安装postcss-preset-env

1
npm install postcss-preset-env -D

注意不是安装完就结束了,我们还需要配置,再到项目根目录下创建一个postcss.config.js文件,添加如下代码:
1
2
3
4
5
module.exports = {
plugins: [
require('postcss-preset-env')
]
}

这时再重新跑下服务,前缀就成功加上了,我们也能发现vite它都不需要我们做任何配置,执行效率也比webpack高很多

Vite对TypeScript的支持

src文件夹下创建一个ts文件夹,再到其中创建一个mul.ts文件

1
2
3
export default function(num1: number, num2: number): number {
return num1 * num2
}

回到main.js文件中,导入使用

1
2
3
import mul from './ts/mul'

console.log(mul(10, 10))

重新跑一下,成功打印出结果,说明vite不需要我们做关于ts配置,直接写ts它就可以对于ts来做一些转化

Vite的原理

接上面,我们再到浏览器控制台的network中刷新一下来看一下这个请求的资源,如下图
10194

我们可以看到它请求的文件扩展名就是lessts
前面也提到过vite它会在本地建一个服务器,在webpack中使用的是express,而在vite1里面用的服务器是koa,但是从vite2开始便不再用koa了,用的是connect,本地服务器并不是直接把.less文件和.ts文件直接给浏览器,浏览器无法解析这两个文件的,vite的一些工具把我们编写的这两个.less文件和.ts文件做了个转化生成新的文件同时也还叫这个名字,并且这两个文件里面的代码变成了es6js代码【我们可以在浏览器控制台的response中查看】,注意css也是变成了js代码,待会它会通过style标签注入到页面里面去的
当我们浏览器去请求这两个文件时,vite的本地服务它对于请求做了个拦截和转发,这也是它为什么要使用connect的原因,connect非常方便做这个转发,这个转发其实请求的是新生成的ES6js`代码文件,然后返回给浏览器,浏览器就会解析,显示

如果有兴趣可以到node_modules下去找一下vite其中的package.json文件中它是有这个connect的包版本号的

Vite对vue的支持

我们在src下创建一个vue的文件夹再创建个App.vue文件,并书写一点代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
<h2>{{ message }}</h2>
</div>
</template>

<script type="text/javascript">
export default {
data() {
return {
message: "Hello vue"
}
}
}
</script>

<style lang="less" scoped>
h2 {
color: #fff;
}
</style>

当然既然要使用vue,首先肯定得安装一下vue,我们这里安装vue3就行了

1
npm install vue -D

然后再到main.js文件中导入createApp和根组件来使用

1
2
3
4
5
6
import { createApp } from "vue"
// 导入根组件
import App from "./vue/App.vue"

// vue
createApp(App).mount("#app")

由于需要挂载容器,我们去index.html模板中添加一下

1
<div id="app"></div>

然后使用npx vite命令来跑一下,发现其实是会报错的,需要安装一个插件
[vite] Internal server error: Failed to parse source for import analysis because the content contains invalid JS syntax. Install @vitejs/plugin-vue to handle .vue files.

vitevue提供第一优先级支持:

  • Vue3单文件组件支持: @vitejs/plugin-vue
  • Vue3 JSX支持: @vitejs/plugin-vue-jsx
  • Vue2支持: underfin/vite-plugin-vue2

对于vue3安装一下插件

1
npm install @vitejs/plugin-vue -D

安装完这个插件之后我们还需要做配置,在项目根目录下创建个vite.config.js文件

1
2
3
4
5
import vue from '@vitejs/plugin-vue'

export default {
plugins: [vue()]
}

注意node版本,文章开头说过,然后重新npx vite浏览器就能成功显示了
然后我们再到node_modules下,它有个.vite文件,它是我们第一次执行npx vite的时候做的一个预打包【主要是对依赖的库如vuelodash】,它有个好处就是我们把这一次运行停掉,再次npx vite时,这两个就不需要再做预打包了,并且在终端看一下这个时间,很明显的快了一些,当然它内部也是做了判断的,并不会出现修改了还用之前的

Vite打包项目及预览

vite它里面提供了一个build,直接去执行里面这个build就行了

1
npx vite build

打包成功后,它会在项目根目录下生成一个dist文件夹
一般打包后,我们也会对其在浏览器上测试一下,直接运行打包文件夹里的index.html文件也可以吗,但是vite它提供了另外一个工具preview,即预览,让它去执行里面的preview就可以了
1
npx vite preview

然后我们就可以预览进行测试了
但是在真实开发里面,我们一般不会一直去写npx命令,我们会在package.json文件的scripts脚本中编写【scripts里面有个默认的test,把它删掉】
1
2
3
4
5
6
7
8
9
{
...
"scripts": {
"serve": "vite",
"build": "vite build",
"preview": "vite preview"
},
...
}

之后我们通过npm run xxx的方式去执行就可以了

ESBuild解析

vite打包非常快,还有个原因就是ESBuild
ESBuild的特点:

  • 超快的构建速度,并且不需要缓存【babel去转换还需要利用缓存,但是ESBuild速度很快,不需要做缓存】;
  • 支持ES6CommonJS的模块化 ;
  • 支持ES6Tree Shaking【比如某个函数从未使用过那么就可以通过Tree Shaking删除掉】 ;
  • 支持GoJavaScriptAPI ;
  • 支持TypeScriptJSX等语法编译 ;
  • 支持SourceMap ;
  • 支持代码压缩 ;
  • 支持扩展其他插件 ;

我们可以发现ESBuildbabel很像,但是功能更加强一点,ESBuild还可以做代码压缩,babel一般不做这个,而Tree Shaking要到webpack中做,相当于兼顾了一些webpack的功能

ESBuild为什么这么快呢?

  • 使用Go语言编写的,可以直接转换成机器代码,而无需经过字节码;
  • ESBuild可以充分利用CPU的多内核,尽可能让它们饱和运行;
  • ESBuild的所有内容都是从零开始编写的,而不是使用第三方,所以从一开始就可以考虑各种性能问题;

Vite的项目创建方式

以上项目搭建从零开始的,但是真实开发里面不可能从零搭建一个项目,这里我们任意创建个文件夹来存放vite项目,利用vscode的终端输入如下命令

1
npm init vite

它会让我们填项目名称,这里不需要删除,直接输入项目名称即可,然后是选择框架、ts
创建完之后安装一下依赖,然后根据它的脚本就可以本地运行、预览和打包