ViteConf 2022回顾:Vite是如何诞生的?

·  阅读 1294
ViteConf 2022回顾:Vite是如何诞生的?

ViteConf 2022 于10月11-12日举行。Vue 和 Vite 的作者尤雨溪发表了名为《How Vite Came to Be》的主题演讲。下面就来回顾一下这场演讲,看看 Vite 是如何诞生的!

下面先来回顾一下在这些构建工具出现之前是如何书写 Web 页面的。

IIFE

Web 开发早期,我们使用 JavaScript 的唯一方式就是在页面中引入<script>标签,所有 JavaScript 都在一个共享的全局作用域中解释执行。默认的方式就是在一个文件中编写所有业务逻辑:

<script src="app.js"></script>
<script src="module-a.js"></script>
<script src="module-b.js"></script>
复制代码

当业务变得复杂时,JavaScript 文件就会变得很臃肿,就要考虑把这些文件拆分成几个小的文件。但当时 JavaScript 并没有模块的概念,所有的文件都共享在全局作用域中,这时可能会使用 IIFE(立即执行函数)来分离作用域,不过这样仍需要通过全局作用域来进行通信,比如通过 window 对象:

;(function() {
  var localVar = 1

  window.App.foo = {
    // ...
  }
})()
复制代码

AMD

之后,一些早期的框架和库的作者就开始使用自己的模块加载器,并尝试将其标准化为 AMD,即 Asynchronous Module Definition(异步模块定义),Require.js 就是 AMD 的一种。RequireJS 是在开发环境下及时加载和转化模块的,可以通过编写插件来及时编译代码,它还支持通过打包命令来构建生产项目。不过,RequireJS 所有的转化都在浏览器端进行,在进行打包时,一些生产环境中不需要的代码在浏览器端也会被打进生产包中。

CommonJS

在 Node.js 兴起之后,CommonJS 模块化规范就成为了 JavaScript 模块的标准,并且影响至今。

image.png

browseify / webpack

因为开发者想要在浏览器端使用 Node.js 包,并且想要在浏览器和 Node.js 环境中使用同一模块格式,所以就出现了模块打包工具,例如 browseify 和 webpack。它们将 CommonJS 模块组合到一个 bundle 中,然后在页面尾部的 script 标签中进行引入。

image.png

2013年,尤雨溪开始编写 Vue,并产生了编写 SFC 的想法,就是将 template、script、style 编写在一个文件中来定义组件。可以通过编写 loaders 来将这些格式转化为可执行的 JavaScript,这样编译的开销也只会在构建时产生,而不会影响运行时性能。

image.png

于是,尤雨溪就在 browseify 和 webpack 中分别编写了转化 SFC 的插件:vueify 和 vue-loader,这两个插件至今仍然适用。

image.png

vue-cli

不过,这些构建工具对于大多数开发者而言还是太底层了。当越来越多的初学者尝试使用这些构建工具时,其实他们对于学习如何配置打包并不感兴趣,而是习惯于有一个入口来快速启动。

于是在2015年,尤雨溪做了 vue-cli,这是一个基于 Webpack 构建的 Vue 脚手架。vue-cli 做了很多如今已经成为标准的工作,例如预配置,即大部分通用功能可以开箱即用。为了达到这样的配置效果,基于webpack进行构建还是有很大工作量的,并且还要兼顾不同的配置,例如,是否使用 TypeScript,使用哪个测试库来运行测试用例,以确保这些配置项的不同组合可以正常运行。

image.png

除了 vue-cli,create-react-app(React官方脚手架)也使用了相似的配置来处理。值得一提的是,parcel 是第一个提出零配置概念的构建工具。

ES Modules

2015年,JavaScript 终于推出了自己的模块化标准 ES Modules。从某种程度上说,Vite 正在帮助 JavaScript 生态系统转向并收敛到 ESM 模块规范。

image.png

随着 ESM 的推出,基于 ESM 的构建工具出现了。Rollup 是第一个基于 ESM 的打包工具,ESM 是其唯一的模块标准,这让 Roolup 的核心代码非常简洁高效,但是,Roolup 并不支持热更新。所以,主流的解决方案,比如 Next.js、create-react-app、vue-cli 都是基于 webpack 的,因为用户更注重热更新的开发体验。

image.png

原生 ESM

2017年,浏览器终于支持了原生 ESM,这意味着以后可以在浏览器中直接使用 ESM 规范,而不是只能在构建时才能使用。

使用原生 ESM 进行构建并且使用 buildless 的方案会存在一些问题,因为有时候确实需要使用构建工具,比如使用 SFC 时,转化 TypeScript 时,使用 JSX、PostCSS 时,这些都需要一个构建阶段来进行处理。

image.png

原生 ESM 提供了 fetch 来进行 HTTP 请求,我们可以让 dev server 无需任何转化即可正常运行,并且这个 dev server 将会非常轻量,就像静态文件服务器一样。

@vue/dev-server

于是,在2019年,尤雨溪创建了 @vue/dev-server,它能够进行转化,并且使用原生 ESM 的 import 语法来加载 Vue 的 SFC 组件。然而,这存在两个问题:

  • 如何处理 npm 依赖;
  • 如何在原生 ESM 中进行热更新。

image.png

由于他一直忙于 Vue 3 的开发工作,就没有持续跟进这两个问题。

Vite 0.1

直到一年后,突然想到了如何在原生 ESM 中进行热更新,然后就开始不断编码和测试。Vite 就正式诞生了,它能够同时转化并运行 Vue 的 SFC,并且能够处理原生 ESM 的热更新。第一个 release 版本的核心逻辑比较粗糙,并且仅支持 Vue组件,因为最初的想法是找到一个轻量的 vue-cli 的替代品。

image.png

Vite 0.2

Vite 诞生之后,下一步任务就是从概念验证阶段过渡到重构阶段。 在调研中发现,@web/dev-server 也是一个 bundless 的 dev你server。所以,当时的想法就是创建一个支持原生 ESM 热更新的 dev server。

调研之后,考虑仅把 Vite 作为 ESM 服务器的中间件来使用。但是从更深层次来看,有一个更宏大的愿景,就是把 Vite 作为一个开箱即用的工具,像 Vue 和 parcel 那样。所以,如果仅把 Vite 作为 dev server 中间件就限制了它的发挥。

image.png

在使用完基于 Koa 的 es-dev-server 之后,最初的设想是每一个插件都当做 Koa 的中间件来执行。所以 Vue 转变了思路,Vue 的插件将会是一个 Koa 中间件。

Vite 0.4

于是,在两天之后,尤雨溪使用 JavaScript 实现了热更新,这个过程需要处理通用的 JavaScript 逻辑,以及 npm 依赖的问题。当时选择了使用 Snowpack 1.0 来进行处理,而现在用 seinstall 代替了 Snowpack。Snowpack 1.0 是基于 Rollup 预配置实现的可以转化 npm 包的工具,无论是什么格式,转化为 ESM 之后都能在浏览器中正常运行。这就解决了各种模块规范混用的问题,将它们统一转化为 ESM 格式,这样才能在浏览器中运行。

image.png

Vite 0.5

在 0.5 版本中,为了更好的输出构建产物,尤雨溪决定继续在生产环境中使用 Rollup。Vite 成为了一个基于 Rollup 的热更新 dev server。

image.png

VitePress

为了验证这些插件和API是否是弹性并且可扩展的,来为更多的解决方案赋能,特别是在服务端渲染的场景下。所以,在 Vue 的生态中,提供了一个静态站点生成器:VitePress,它是一个基于 Vite 的高级别应用。它允许通过路由去编写 HTML 文件,并且可以在其中引入 Vue 组件。VitePress 还可以用来生成文档,并提供了服务端渲染的能力,它可以将 markdown 解析成 Vue 组件并编译它,最后通过服务端渲染生成 HTML。

image.png

Vite 1.0 之前

在发布 Vite 1.0 之前, Vite 实现了和 vue-cli 相同的功能,吸引了越来越多的用户,也因此发现了很多 bug,大多数 bug 都和 npm 依赖以及模块格式有关。在 2022年4月至11月期间,Vite 发布了 91 个 release 版本。

但是,最终 1.0 版本并未落地,因为在开发 1.0 时,尤雨溪意识到 Vite 并不仅仅是 vue-cli 的替代品,Vite 其实可以做两件事:

  • 作为与框架无关的最小配置打包工具来提供给用户,这本质上是一个更通用的 vue-cli,目的是让每一个框架都能使用;
  • 为框架作者提供一个共享工具层。这样,对于使用 Nuxt.js、SvelteKit、Next.js 等框架的用户,无需再重复造轮子,可以专注于更有意义的工作。

Vite 2.0

为了完成上述目标,尤雨溪决定重写 Vite。2020 年 12 月开始重写 Vite 2.0。

  • 首要目标就是将 Vite 和框架解耦;
  • 受到 WMR 启发,选择了通用 Rollup 兼容插件 API;
  • 受到 SvelteKit 启发,采用了全新的 SSR 运行时;
  • 使用基于 esbuild 的依赖预打包方案,处理依赖的速度提升近百倍。

最终,在 2021 年 2 月 16日,Vite 2.0 正式发布。

image.png

组建团队

尤雨溪的时间和精力被分散到了 Vite 和 Vue 两个项目中,仍然需要确保 Vue 可以正常迭代。因此,在 2021 年 3 月正式组建团队。目前,Vite 的绝大多数的日常维护工作都是由团队成员完成的, 最近的 Vite 3.0 主要版本也是来自团队成员的努力。

image.png

相关资源

分类:
前端
收藏成功!
已添加到「」, 点击更改