大家好,我叫CUGGZ。ViteConf2022将于10月11-12日举行。Vue和Vite的作者游玉玺发表了题为《How Vite Came to Be》的主题演讲。让我们回顾一下这篇演讲,看看Vite是如何诞生的!我们先来回顾一下在这些构建工具出现之前网页是如何编写的。在IIFEWeb开发初期,我们使用JavaScript的唯一方式是在页面中引入当业务变得复杂时,JavaScript文件会变得非常臃肿,所以需要考虑将这些文件拆分成几个小文件。但那时候的JavaScript没有模块的概念,所有的文件都是在全局范围内共享的。这时候可能会使用IIFE(立即执行函数)来分离作用域,但这仍然需要通过全局作用域进行通信,比如通过window对象:;(function(){varlocalVar=1window.App.foo={//...}})()在AMD之后,一些早期的框架和库作者开始使用他们自己的模块加载器,并尝试将其标准化为AMD,即AsynchronousModuleDefinition(异步模块定义),Require.js是一个有点像AMD。RequireJS在开发环境中及时加载和转换模块,通过编写插件可以及时编译代码。它还支持通过打包命令构建生产项目。但是,RequireJS的所有转换都是在浏览器端进行的。在打包的时候,一些生产环境不需要的代码也会被打包到浏览器端的生产包中。在Node.js中CommonJS兴起后,CommonJS模块化规范成为了JavaScript模块的标准,并影响至今。browseify/webpack由于开发者希望在浏览器端使用Node.js打包,并且希望在浏览器和Node.js环境中使用相同的模块格式,因此出现了browseify、webpack等模块打包工具。他们将CommonJS模块组合成一个包,然后将其包含在页面末尾的脚本标记中。2013年,尤雨熙开始写Vue,萌生了写SFC的想法,就是把模板、脚本、样式写在一个文件里定义组件。可以通过编写加载器将这些格式转换为可执行的JavaScript,这样编译开销仅在构建时产生,而不会影响运行时性能。于是,尤雨熙分别在browseify和webpack中编写了转换SFC的插件:vueify和vue-loader,这两个插件今天依然适用。vue-cli但是,这些构建工具对于大多数开发人员来说仍然太低级。当越来越多的初学者尝试使用这些构建工具时,他们其实并不是对学习如何配置打包感兴趣,而是习惯了有一个入口可以快速上手。于是在2015年,游雨溪做了vue-cli,这是一个基于Webpack的Vue脚手架。vue-cli做了很多现在已经是标准的事情,比如预配置,也就是大部分常用的功能都可以开箱即用。要实现这样的配置效果,基于webpack的构建还有很多工作要做,还要考虑到不同的配置,比如是否使用TypeScript,使用哪个测试库跑测试用例,确保这些配置项的不同组合工作正常。除了vue-cli,create-react-app(React官方脚手架)也使用类似的配置进行处理。值得一提的是parcel是第一个提出零配置概念的构建工具。ESModules2015年,JavaScript终于推出了自己的模块化标准ESModules。在某种程度上,Vite正在帮助JavaScript生态系统转向并融合到ESM模块规范。随着ESM的引入,出现了基于ESM的构建工具。Rollup是第一个基于ESM的打包工具。ESM是其唯一的模块标准,这使得Roolup的核心代码非常简洁高效。但是,Roolup不支持热更新。所以主流的方案,比如Next.js、create-react-app、vue-cli都是基于webpack的,因为用户更看重热更新的开发体验。原生ESM2017年,浏览器终于??支持原生ESM,这意味着ESM规范可以直接在浏览器中使用,而不仅仅是在构建时使用。使用原生ESM构建和使用buildless都存在一些问题,因为有时候确实需要使用构建工具,比如在使用SFC的时候,在转换TypeScript的时候,在使用JSX、PostCSS的时候,这些都需要一个构建阶段来处理。原生的ESM提供了fetch来发起HTTP请求,我们不需要任何转换就可以让devserver正常运行,而且这个devserver会非常轻量级,就像一个静态文件服务器。@vue/dev-server所以,在2019年,游雨溪创建了@vue/dev-server,可以转换使用原生的ESM导入语法来加载Vue的SFC组件。但是,这有两个问题:如何处理npm依赖项。如何在原生ESM中进行热更新。由于一直忙于Vue3的开发,所以没有跟进这两个问题。直到一年后的vite0.1,我突然想到了如何在原生ESM中进行热更新,然后开始不断的编码和测试。Vite正式诞生。可以同时转换运行Vue的SFC,可以处理原生ESM的热更新。第一个release版本的核心逻辑比较粗糙,只支持vue组件,因为最初的想法是想找一个轻量级的vue-cli替代品。Vite0.2Vite诞生后,接下来的任务就是从概念验证阶段过渡到重构阶段。在研究中,发现@web/dev-server也是一个捆绑的开发服务器。因此,当时的想法是打造一个支持原生ESM热更新的devserver。在做了一些研究之后,考虑将Vite仅用作ESM服务器的中间件。但在更深层次上,有一个更宏大的愿景,即使用Vite作为一个开箱即用的工具,就像Vue和parcel一样。因此,如果仅将Vite作为开发服务器中间件使用,其性能将受到限制。使用基于Koa的es-dev-server后,最初的想法是每个插件都作为一个Koa中间件来执行。所以Vue改变了主意,Vue插件将是一个Koa中间件。Vite0.4于是,两天后,游雨溪用JavaScript实现了热更新。这个过程需要处理常见的JavaScript逻辑和npm依赖项。当时选择了Snowpack1.0进行处理,现在使用seinstall代替了Snowpack。Snowpack1.0是一个可以基于Rollup预配置转换npm包的工具。不管是什么格式,转换成ESM后都可以在浏览器中正常运行。这样就解决了各种模块规范混用的问题,统一转换成ESM格式,以便在浏览器中运行。Vite0.5在0.5版本中,为了更好的输出构建产品,游鱼溪决定在生产环境中继续使用Rollup。Vite成为基于Rollup的热更新开发服务器。为了验证这些插件和API是否具有灵活性和可扩展性,VitePress赋能了更多的解决方案,尤其是服务端渲染场景。因此,在Vue生态中,提供了一个静态站点生成器:VitePress,它是一个基于Vite的高层应用。它允许通过路由编写HTML文件,并且可以在其中引入Vue组件。VitePress也可以用来生成文档,提供服务端渲染能力。它可以将markdown解析成Vue组件并编译,最终通过服务端渲染生成HTML。在Vite1.0之前,在Vite1.0发布之前,Vite实现了与vue-cli相同的功能,吸引了越来越多的用户,也发现了很多bug,其中大部分与npm依赖和模块格式有关。在2022年4月至11月期间,Vite发布了91个版本。不过1.0版本最终并没有落地,因为在开发1.0的时候,尤雨熙意识到Vite不仅仅是vue-cli的替代品,Vite其实可以做两件事:作为一个独立于框架的最小配置打包工具来提供对于用户来说,这本质上是一个更通用的vue-cli,旨在供每个框架使用;为框架作者提供共享工具层。这样一来,使用Nuxt.js、SvelteKit、Next.js等框架的用户就不需要重新发明轮子,可以专注于更有意义的工作。Vite2.0为了完成上述目标,尤雨熙决定重写Vite。Vite2.0重写于2020年12月开始,主要目标是将Vite与框架解耦;受WMR的启发,选择了通用的Rollup兼容插件API;受SvelteKit的启发,采用了新的SSR运行时;采用基于esbuild的依赖预打包方案,依赖处理速度提升近百倍。终于在2021年2月16日,Vite2.0正式发布。游雨溪团队建设所花费的时间和精力分为Vite和Vue两个项目,还是要保证Vue能够正常迭代。因此,团队的正式组建将于2021年3月进行。目前Vite的大部分日常维护工作都是由团队成员完成的,最近Vite3.0的大版本也是团队成员的努力。相关资源演讲PPT:https://docs.google.com/presentation/d/1O09rAOu_wRLHVjukVbBeSlRkLeX-dcYZfsdjPiU4kGQ/。讲座视频:https://viteconf.org/2022/replay/vite_keynote。
