参考文献:

最近在公司也接近实习了差不多 3 个月的时间,期间也不免接触了比较多的真实项目,有用 Vue2 + JS 的,有用 Vue3 + TS 的,也有用 tsx 写 Vue 的。

这些零零散散的项目所使用的上线打包工具都是基于我们公司内部的 workbench 前端脚手架进行启动的,而作为底层的打包工具便是 Webpack。这让我这个基本上只深度接触过 Vite 的人比较感兴趣:为什么公司开发一般都用 Webpack 而不是 Vite 呢?因此,我决定去进行一些系统性的调研。

# 打包原理

# Webpack

首先,我们需要明确的是 Webpack 它是一个 模块打包工具。按照其官网给出的定义,它具有三个主要的能力:

  • 编译代码能力:主要指的是将一些相对高级的 JS 语法编译成低级的语法,如把 ES6 编译成 ES5。
  • 模块整合能力:Webpack 会将开发阶段编写的不同 JS 文件的代码 全部整合到一个 JS 中,称为 bundle.js 这就是 Webpack 主要的打包方式。
  • 万物皆可模块能力:默认的 Webpack 仅仅支持 .js 文件的编译和打包,面对 Less、Scss 这种特殊的 .css 文件则显得束手无策。但是它同时提供了名为 Loader 的机制,能够加载、解析并打包用户配置的 Loader 的加载目标,并将其以统一的形式打包到 bundle.js 中或是其他的文件中。

由上我们可以大概猜得到了,Webpack 本身是基于传统的 全量打包 模式,也就是将全部的资源文件打包成一个或者多个 bundle 文件,比较适合用在生产环境中。

当然,Webpack 也有其 HMR 机制。不过由于全量打包模式的限制,这也就意味着更改一个文件之后需要对包含该文件的 bundle 进行重新构建,比较大的限制了 HMR 的性能。而且项目一大,几百个 .js 文件相互引用,打包时间往往越来越长,性能可能会随着项目规模的增大而下降。

而对于真实的生产环境打包,实际上就是和开发环境一样的操作,将全部的资源都打包成 bundle 进行部署。可以说是开发阶段和部署阶段采用相同的策略。

# Vite

熟悉 Vue 的同学肯定都听过 Vite。在 Vite 当中实际上是集成了两种不同的工具:

而 Vite 本身充分利用了 ESM 的静态分析特性,它是一个 按需打包 的工具。

# Esbuild

对于 Esbuild,就一个字: ,它的设计理念就是为 而生。在开发环境,Vite 的内置服务器实际上起的是 Esbuild 的服务。Esbuild,顾名思义,是一个构建 ES 模块的工具。它能够充分利用浏览器原生的 ESM 机制,不需要在开发的时候预先打包所有代码 ,启动开发服务器时仅仅会加载必要的模块。

而我们知道,ESM 和 CJS 之间最大的区别就在于其 “静态”。对 ESM 模块的解析在编译阶段便完成,从而能够精准的确定某部分有用还是没用,从而进行 tree-shaking。而对于 Esbuild 而言,它本身是基于编译型语言 Go 编写而成,其并发性、编译性能以及自身轻量化的架构设计,因此大大加快了文件解析、代码转换以及打包的速度。这也是 Esbuild 快的主要原因

而对于 HMR,自然是 ESM 的专场了。我们可以看一下使用 Vite 启动的本地开发环境,查看源代码:

按需打包

可以看到,基本上和我们本地的 vscode 文件结构目录是一致的。这也就意味着,HMR 只会更改发生了变化的那个文件,大大提升了开发阶段的性能。

并且基于 ESM,能够和浏览器的调试工具完美的结合起来进行调试,因为浏览器运行的代码就是你编写的代码,能够非常精准快速的定位到你的实际 bug 区域,并不用像 webpack 那样在编译产物中寻找实际编写的代码区域,调试体验也非常良好。

# Rollup

在生产阶段,则采用的是 Rollup。

Rollup 的特点之一就是在于它对于代码分割(code splitting)的支持相较于 Esbuild 更加的完善。它能够借助 ESM 静态的特性,根据项目的依赖关系自动拆分模块并生成多个按需加载的文件。

另外一个重要的特点,便是 Tree-Shaking(摇树优化)。Rollup 是业界公认的 tree-shaking 实现非常优秀的打包工具之一。基于 Rust,它能够进行相较于 Esbuild 更深层次的静态分析,甚至能够分析到函数级别、变量级别,能够完全的剔除掉未使用的部分。比如,如果一个模块中定义了多个函数,而只用到了其中一个,Rollup 能够将未使用的函数完全剔除。并且基于 ESM 的编译时解析特性,Rollup 能够在编译时对各个模块进行深入到变量层次的解析,从而进行最充分的 tree-shaking 来剔除掉无用代码。

另外,Rollup 的插件生态也是它的亮点之一。我们都知道 webpack 发展了这么多年,形成了非常庞大的插件以及 Loader 生态,而 Rollup 作为新起之秀,它的插件生态的增长规模十分迅速,已经接近 webpack 的数量级了。目前 Vite 官方在它的配置文件中配置的绝大多数插件也都是用于 Rollup 的。

那么肯定有人会问:为什么不继续用 Esbuild 来打包呢?因为 Esbuild 只是非常单纯的为快而生,它强大的静态分析能够能力完美的适配 HMR,但一旦涉及到打包层次的处理,无论是 静态分析精度、代码转换优化,都比 Rollup 要差得多。Rollup 的设计理念之一便是 生成高质量的生产包 而并不是快,所以生产和开发阶段采用不同的包各司其职,也是情有可原。

# 配置复杂度

# Webpack

Webpack 一开始就是 纯粹让用户自己定制功能 的。如果想要在一个已有的项目中引入 Webpack 打包,用户需要安装好 Webpack 之后新建 webpack.config.js 来对各种细节进行定制化配置。然而,这说得好听点叫 “可定制化程度高”,说难听点便是 “配置过于冗杂”。

而且它默认只支持 JS 文件的编译和打包,对其他的文件统统需要自行的配置 Loader 来进行加载。虽然目前市面上关于 Webpack 最佳实践配置方案的确不少,但是这不开箱即用的配置对用户来说还是不太友好的。

不过相对的,Webpack 的插件系统生态较为成熟。目前主流的前端打包性能优化方案,都可以在插件中找到对应的解决方法。结合目前流行的前端框架,许多使用 CLI 创建的项目都已经自带了 Webpack 的打包优化方案,不用用户操心。

# Vite

和 Webpack 不同,Vite 天生内置了对多种常见文件类型的支持。它开箱即用地处理了大部分前端开发中的资源类型,无需像 Webpack 那样手动配置 Loader。

ViteWebpack 不同,Vite 不需要手动配置 Loader 来处理大多数非 JavaScript 文件。这是因为 Vite 内置了对多种常见文件类型的支持,它开箱即用地处理了大部分前端开发中的资源类型,无需像 Webpack 那样手动配置 Loader,比如:

  • 图片、字体、媒体文件:Vite 支持直接导入图片(如 .png , .jpg , .svg )、字体(如 .woff , .ttf )、视频 / 音频文件(如 .mp4 , .mp3 )等,这些文件会自动被处理成资源 URL。
  • JSON:Vite 支持导入 .json 文件,默认会将 JSON 文件解析为 JavaScript 对象。
  • TypeScript:Vite 自动支持 TypeScript,无需额外配置,只需在项目中使用 .ts 文件即可。
  • CSS 预处理器:如 .scss.sass.less.styl 等文件,Vite 能够自动处理,无需手动添加 Loader。

关于插件系统,虽然 Esbuild & Rollup 的插件系统没有 Webpack 那么完善,不过基于 Rollup 本身的打包优化,实际需要插件的情形并不多,并且也可以自己写。这应该也算是唯一的一点小小不足?不过对于现阶段的开发来说完全够用了。

# 支持的框架

# Webpack

  • Webpack:框架无关,支持包括 React、Vue、Angular 等在内的几乎所有前端框架。
  • Vite:最初是为 Vue 设计的,但现在已经扩展支持了其他主流框架,如 React、Svelte 等。Vite 在处理 Vue 项目时,表现得更出色,因为它是由 Vue 团队开发的,官方支持非常好。

关于这个,我们需要回到 Webpack 的最核心的也是最开始默认支持的部分:JS 编译和打包。实际上,你可以在任何使用 JS 的项目中都可以用它来打包,无论你是单纯的 npm 包项目、Node 后端项目、用 Vue & React 的前端项目,都是可以使用它的。它框架无关,仅仅需要配置一些 Loader 和 Plugin 即可。

# Vite

Vite 怎么诞生的大家都清楚,它是和 Vue3 几乎同一时间到来的,它最初也只是为了改善 Vue 的开发构建体验而被开发的。

Vite 虽然也是一个框架无关的工具,但是 Vite 比较倾向于按照它的预定模板进行指定前端项目构建并开发。现阶段在 Node 等偏后端的项目中的应用较少。

# 社区与发展趋势

# Webpack

作为传统的打包工具,Webpack 依然拥有庞大的社区支持和丰富的文档资源。就我个人的体验和经历来说,大公司内部如果涉及到内部的一些数据中台的搭建,往往都是基于 webpack 来自行设计开发项目的运行构建工具的,自由度相对较高,适合内部前端项目统一管理、启动、部署等流程的集成。

不过,随着前端技术的发展,一些开发者开始寻找性能更优、配置更简单的替代品。

# Vite

Vite 是现代构建工具的代表,尤其是在开发速度和体验上表现非常突出。随着 Vite 的流行,它逐渐成为许多新项目的默认选择,并且官方团队(如 Vue 和 Svelte)对其有较强的支持。

目前比较倾向于,单个简单的项目使用 Vite 来进行构建和打包,效果是会比 Webpack 要好。

# 总结

我们可以试着总结一下:

Webpack 更适合大型、复杂、需要大量定制化和特定插件支持的项目,尤其是企业的前端数据中台往往涉及到不同的多个项目拆分与整合,而这个整合所依赖的平台往往是由自由度高的 Webpack 进行定制化构建的。倒不如说, “基于 Webpack 构建内部的前端统一部署与构建平台” 这件事本身就已经算是一个大工程了。

Vite 更注重开发阶段的体验,特别适合中小型项目或对开发速度要求较高的项目。如果是使用 Vue 或 React 等框架进行开发,Vite 会提供更快的响应时间和简化的配置。一般我们使用现代 Vue 体系技术栈进行开发,比如 Nuxt、Vue3 等,我们基本默认使用 Vite。

而且 Vite 现阶段的生态如日中天,React、Solidjs、Svelte、Angular,基本叫得上名字的框架都可以使用 Vite 的官方构建工具进行构建项目:
现阶段支持的框架