本文转载自微信公众号《秋风的手记》,作者:蓝秋风。转载本文请联系秋风笔记公众号。最近在B上看到这样一个问题,能简单介绍一下Vite是做什么用的吗?一开始觉得这个问题没什么意义,因为Vite这个话题已经有太多人讨论了。但是看了其他的回答,大部分都会从Vite的特性和ESModules说起,然后时不时和webpack对比一下。我仔细看了看题主的问题。我也陷入了沉思。是因为大家都渴望学习一些新知识吗?还是前端往往容易把一些简单的东西复杂化,形成娃娃似的知识?还是知识太分散了?,分不清哪些是相关的?为了探索Vite,我打开了Vite的官网。他的slogan是“下一代前端开发构建工具”,因为一般的slogan需要简洁的表达它的意思,所以我就用Minimal来概括(也是为了宣传)。我觉得没什么问题,但是对于一些新手来说,确实这句话看不懂,官网也没有足够清晰的图片。如果是不懂的人,确实很容易迷路。那么这句话是什么意思呢?我通俗的表达一下(可能不准确,仅代表个人理解):目前大部分浏览器已经支持ESM(ESModules)模块。所以我写了一个转换工具,可以让浏览器支持一些浏览器不支持的格式(.vue/.svelte/.ts)和不支持的语法(最新的es语法/特性),这会成为一种趋势。很多人会从ESModules、DevServer、Vue的集成度高、速度快来解释。更像是在谈论它的优点。我觉得有点神话,所以才会这么神秘(迷惑)?在我看来,Vite是一个转换器,而Webpack是一个模块+转换器。转换器的作用是将一些浏览器无法解析的文件转换成浏览器可以解析的js文件。这是Vite的核心。使用Vite之所以快,全在于浏览器本身。浏览器统一了模块化方案,Vite正好拿了一波浏览器性能红利。用一张图来描述(这里我盗用了Webpack的官方图片,改了下)Vite将所有资源转成js形式导入,因为浏览器只支持js文件的ESModles方式,毕竟ESModules都属于ECMAscript规范,当然只能应用于js。而整个模块化过程都是浏览器的功劳。这里先看看Webpack的整体流程图。如果你了解Webpack,或许可以加深印象,但如果你不了解Webpack,也没关系。由于Webpack需要自己的模块化方式,所有的资源都需要打包到一个js中。这张图非常形象地说明了Webpack的作用。(不懂Webpack没关系,懂Vite的图就够了)举个例子,或许能帮助你更清楚地了解Vite的真面目。//index.html//main.jsimport{element,text}from'./el.js';constcontainer=element('div');consth1=element('h1');constt=text('HelloESModules');h1.appendChild(t);container.appendChild(h1);document.body.appendChild(container);//el.jsexportfunctionelement(name){returndocument.createElement(name);}exportfunctiontext(data){returndocument.createTextNode(data);}在VSCode中安装一个LiveServer,然后启动这个html,然后我们随便改个东西,可以看到更新速度很快很快。也许你会说,我的文件数太少了,没关系,我们这次修改20个文件吧。constfs=require('fs');constLENGTH=20;newArray(LENGTH).fill(0).forEach((item,index)=>{fs.writeFileSync(`child-${index}.js`,`export{child}from'./child-${index+1}.js';`)})fs.writeFileSync(`child-${LENGTH}.js`,`import{element,text}from'../el.js';exportfunctionchild(){constc=element('div');constt=text('child');c.appendChild(t);document.body.appendChild(c);}`)所以我说,Vite本质上是一个转换器,没有webpack的模块化功能。但是浏览器虽然解决了模块化依赖,但是仍然存在两个问题:但是没有办法支持一些样式/文件(css/ttf/jpg...)的导入语法,资源不能支持.ts/.vue/。svelte等直接引用模板语法(或高级特性),所以我们可以看到Vite似乎做了很多事情,因为Vite可以加载.ts/.vue/.svelte等文件,而且集成了很多插件要做这些转换任务,将所有资源转换成浏览器可识别的js导入,将css文件打包成js文件,等等。剩下的就是原文件中的内容替换,因为类似第三方包里面的资源是不能直接导入的,需要一层替换,比如把代码改成这样。在编译的时候,我们需要替换掉我们实际写代码的地址,让浏览器去加载,然后为了不让浏览器加载太多的文件,需要将第三方包导入到一个模块中,然后是热更新功能(这个功能稍微复杂一些)。并且为了能够在生产环境打包(常规优化前的Treeshaking/compression等),使用了Rollup,它不仅提供了ESM打包方式,还提供了其他你需要的模块化方式(umd/amd/命令/生活)。因此,核心简单,但要让相关生态好用,却需要付出很大的精力。Vite团队在解决周边生态问题、各种插件的适配等方面也花了不少心思。第一个ESM和第一个使用浏览器原生ESM能力的工具不是Vite,而是一个叫做Snowpack的工具(见我的文章?snowpack,打包速度提升10倍。)。以前称为@pika/web,从1.x版本开始更名为Snowpack。Snowpack在其官网上是这样介绍自己的:“Snowpack是一款专为现代Web设计的快如闪电的前端构建工具。它是开发工作流程更重、更复杂的打包工具(如Webpack或Parcel)的替代品。Snowpack利用JavaScript的模块化方法(称为ESM)来避免不必要的工作并保持流畅的开发体验”。为此,鼠兔团队开发并维护了两个技术系统:相关的Snowpack和Skypack,以造福大众。其中,skypack上有很多以ESModules(如React等)的形式进行特殊处理的包,直接用于调用。由于那些包本来就不支持ESModules的形式,所以他们单独维护了ESModules的版本。看完了ESModules的现状和Vite的精髓,我们再来回顾一下模块化,这样整个时间线就完整了,我们的开发方式改变到现在,Web真的是下了很大的功夫。模块化简史回到2006年,那时“jQuery”刚刚诞生。虽然那时候还没有模块化,但是使用jQuery相对于传统的写法在速度上有了很大的提升。当然,虽然很方便,但是单一还是挡不住热爱学习的程序员。“CommonJS”诞生于2009年,但“CommonJS”一直未能扩展到浏览器,因为有两个重要的问题没有解决。(1.由于外层没有函数包,所以导出的变量会全局暴露。2.在服务端require一个模块时,只会有磁盘I/O,所以同步没有问题加载机制;但如果由浏览器加载,一是会产生比较昂贵的网络I/O,二是天生是异步的,会造成时序错误。)百家争鸣中间(“AMD、CMD、UMD”)一直持续到2016年5月,经过两年的讨论,ECMAScript6.0终于正式通过决议,成为国际标准。在这个标准中,首次引入了import和export两个JavaScript关键字,并提供了一种称为“ESModule”的模块化解决方案。在它的第21个年头,JavaScript终于有了自己的模块化解决方案。这期间如果想使用模块化,只能通过打包工具来解决。标准制定后,不可能马上让所有设备都支持“ESModule”,因为浏览器的推广是一个漫长的过程,不像服务器,升级的话只需要升级服务器即可,而浏览器的升级伴随着电脑/手机等一系列因素,这是非常不可控的,因为用户总是可以有多种选择。“ESModules(ESM)”是JavaScript的官方标准化模块系统,它在标准化的道路上花费了将近10年的时间。2018年5月Firefox60发布后,各大浏览器都支持“ESM”。直到现在,“ESModule”还不能真正在生产环境中使用,仍然需要转换成老方式(非ESM方式)。回答完这个问题写在最后,不禁想到在前端的开发过程中,会出现一些新瓶装旧酒,然后神话,然后让小白觉得高大上吓人,那老板就会觉得这东西很简单,不愿意拆。我们是不是需要换个思路,在讲的时候,去掉那些高深的词汇,做一些更通俗易懂的解释?我当然没有,这些新工具带来的便利和背后的努力,但是亲民也是一种方式,说不定会变得更好呢?本人无从知晓,本文仅是本人的反映,如有错误,请大家批评指正。参考https://segmentfault.com/a/1190000039370642
