前言

我还是那句话,工具永远是服务于需求的。纵观整个前端生态的项目构建工具,有服务于 React 生态的 create-react-appumiNext.js 等。服务于 Vue 生态的 Vue CLIViteNuxt.js 等。它们都是耳熟能详的团队和大佬,为了解决各自需求而研发出来的前端构建工具。而我们要做的其实就是根据项目的需求,进行合理的选择和学习。说白了,在你没有决定权的时候,公司用什么,你就学什么。在你有话语权,能自己抉择的时候,哪个让你开发起来比较舒服,就用哪个。

这些构建工具中,有一个比较特殊,那就是 Vite,它是尤雨溪在发布 Vue 3.0 时,同步推出的一款前端构建工具。它不光服务于 Vue,同时也对其他的框架如 ReactSveltePreact 都有一定的支持,我们本着学新不学旧的理念,在项目中引进了 Vite 作为构建工具。

在开始使用 Vite 之前,我们来认识一下它。

知识点

  • Vite 是什么。
  • ViteWebpack 相比优势在哪里。
  • Vite 的构建原理。

Vite 是什么

我们引用官方的一句话来介绍它,“下一代前端开发与构建工具”。

它有以下几个特点:

1、 快速启动,Vite 会在本地启动一个开发服务器,来管理开发环境的资源请求。

2、相比 Webpack 的开发环境打包构建,它在开发环境下是无需打包的,热更新相比 Webpack 会快很多。

3、原生 ES Module,要什么就当场给你什么。而 Webpack 则是先将资源构建好之后,再根据你的需要,分配给你想要的资源。

尤雨溪在发布 Vite 前,发过这么一条微博。

img

从话语间可以看出,尤雨溪团队对该打包工具也是报以厚望,所以这里大家可以不必担心后续它们会放弃维护这个项目,当然也不能打包票。

Vite 与 Webpack 相比优势在哪里

接下来我们来聊聊,为什么说它是下一代前端开发与构建工具。是不是当代构建工具出了什么问题?

我们知道当代的前端构建工具有很多,比较受欢迎的有 WebpackRollupParcel等,绝大多数脚手架工具都是使用 Webpack 作为构建工具,如 Vue-CLI

在利用 Webpack 作为构建工具时,开发过程中,每次修改代码,都会导致重新编译,随着项目代码量的增多,热更新的速度也随之变慢,甚至要几秒钟才能看到视图的更新。

生产环境下,它将各个模块之间通过编码的方式联系在一起,最终生成一个庞大的 bundle 文件。

导致这些问题出现的原因,有以下几点:

1、HTTP 1.1 时代,各个浏览器资源请求并发是有上限的(如谷歌浏览器为 6 个,这导致你必须要减少资源请求数)。

2、浏览器并不支持 CommonJS 模块化系统(它不能直接运行在浏览器环境下,它是 Node 提出的模块化规范,所以需要经过 Webpack 的打包,编译成浏览器可识别的 JS 脚本)

3、模块与模块之间的依赖顺序和管理问题(文件依赖层级越多,静态资源也就变得越多,如果一个资源有 100 个依赖关系,可能需要加载 100 个网络请求,这对生产环境可能是灾难,所以在生产环境最终会打包成一个 bundle 脚本,会提前进行资源按需加载的配置。)

那么为什么现在又出现了不打包的构建趋势?

1、工程越来越庞大,热更新变得缓慢,十分影响开发体验。推动着我们不断地去创新,不断地尝试着去突破瓶颈。

2、各大浏览器已经开始慢慢的支持原生 ES Module (谷歌、火狐、SafariEdge 的最新版本,都已支持。这让我们看到了希望)。

3、HTTP 2.0 采用的多路复用。不用太担心请求并发量的问题。

4、越来越多的 npm 包开始采用了原生 ESM 的开发形式。虽然还有很多包不支持,但是我相信这将会是趋势。

我们通过表格的形式,对比一下 bundlebundleless 的区别。

img

Vite 构建原理

众所周知,Vite 的生产模式和开发模式是不同的概念。我们先聊聊,Vite 的开发模式。

首先要明确一点,Vite 在开发模式下,有一个 依赖预构建 的概念。

什么是依赖预构建

Vite 启动开发服务器之后,它将第三方依赖的多个静态资源整合为一个,比如 lodashqsaxios 等这类资源包,存入 ·node_modules/.vite 文件下。

为什么需要依赖预构建

如果直接采用 ES Module 的形式开发代码,会产生一大串依赖,就好像俄罗斯套娃一样,一层一层的嵌套,在浏览器资源有限的情况下,同时请求大量的静态资源,会造成浏览器的卡顿,并且资源响应的时间也会变慢。

我们先不通过 Vite,而是手动搭建原生 ES Module 开发形式,通过引入 lodash-es 包,实现一个数组去重的小例子,来详细分析为什么需要依赖预构建。

新建 test1 文件夹,通过 npm init -y 初始化了一个前端工程:

img

手动新建 index.html,通过 script 标签,引入 main.js。这里注意,需要将 type 属性设置为 module,这样才能支持 ES Module 模块化开发。

通过 npm 安装 lodash-es,这里我们之所以不使用 lodash,是因为 lodash 不是通过 ES Module 形式开发的,直接通过相对路径引入会报错,需要通过 Webpack 打包构建。

1
npm i lodash-es

新建 main.js 添加去重逻辑:

1
2
3
4
5
import uniq from "./node_modules/lodash-es/uniq.js";

const arr = [1, 2, 3, 3, 4];

console.log(uniq(arr));

这里我们采用 VSCode 的插件,Live Server,来启动项目。

img

安装完之后,在项目中双击 index.html,找到右下角的 「Go Live」,如下所示:

img

点击后,自动启动一个 Web 服务,浏览器自动打开,如下所示:

img

结果正确,数组中的 3 被去除了,接下来关键的一个点,我们点击 Network 查看,资源引入情况:

img

我们只是获取去重方法,却意外引入了 59 资源,这是为什么呢?

我们先查看 main.js 内的代码,如下所示:

img

代码中只有在首行通过 import 引入了 ./node_modules/lodash-es/uniq.js,所以 uniq.js 被作为资源引入进来,我们再看 uniq.js 的情况:

img

uniq.js 中,首行通过 import 引入了 _baseUniq.js,我们继续:

img

_baseUniq.js 中,引入了上图箭头中的一些脚本,不用往下看,我盲猜这种俄罗斯套娃的模式,会一直引用到 uniq.js 相关的所有脚本代码。

这只是一个 uniq 方法,足足就引入了 59 个资源,这仿佛是在军训浏览器,也就是谷歌能跟它博弈几个回合,引入的包再多几个,我估计也是顶不住的。

所以这时候 Vite 便引入了「依赖预构建」的概念。

依赖现预构建浅析

同样的,再通过 Vite 构建出一个 React 项目,去实现上述逻辑,我们观察 Vite 是怎么作的。

首先通过 Vite 指令生成项目:

1
npm init @vitejs/app test2 --template react

并安装 lodash-es,修改入口脚本 main.jsx

1
2
3
4
5
import uniq from "lodash-es/uniq.js";

const arr = [1, 2, 3, 3, 4];

console.log(uniq(arr));

我们观察浏览器的 Network,如下所示:

img

注意上图,执行 npm run dev 后,脚本中引用 lodash-es/uniq 的路径是在 /node_modules/.vite 文件夹下,并且左下角的请求资源数,也没有我们之前原生 ES Module 时的多,少了足足 3/4 还多。

再观察文件目录:

img

lodash-es/uniq 已经被 Vite 提前预编译到了 .vite 文件夹下,这样代码中直接去这个文件夹拿现成的包,就不必再递归地去加载很多静态资源脚本。

总结

本章节,通过实例分析,对 Vite 有了初步的了解。那么下一章节,我将带大家通过 Vite 去搭建一个 React 的完整开发环境。