某天,实施人员,让我修复了一个小问题,并需要快速的发布到正式环境上,我三下五除二修改了问题;开始了打包发布,以前并没有怎么注意到启动的问题,然而这次比较急,想在用户看到之前发布替换掉内容,于是等啊等,三四分钟过去了,才打包好了;于是就开始了优化webpack构建打包,但效果有点差强人意,于是就碰到Vite,在一番实践之下,直呼"webpack麻烦你不要靠的那么近,我怕vite误会"
问:Webpack为什么启动慢?Vite为什么启动快?
答:Vite它借助了浏览器对ESM
规范的支持,采取了与Webpack
完全不同的unbundle
机制。
ESM
规范ES modules 是 JavaScript 官方的标准化模块系统。相比于 CommonJS 和 AMD 等模块规范,最新浏览器原生支持模块功能,不再需要额外打包处理。*bundle
机制将项目中各种类型的源文件转化供浏览器识别的js、css、img
等文件,建立源文件之间的依赖关系,并将数量庞大的源文件合并为少量的几个输出文件。bundle工作机制的核心部分分为两块* 构建模块依赖图 -module graph
* 将module graph
分解为最终供浏览器使用的几个输出文件。强大的 bundle 机制,也引发了构建速度缓慢的问题,而且项目规模越大,构建速度越是缓慢。其主要原因是构建module graph
的过程中,涉及到大量的文件 IO、文件 transfrom、文件 parse 操作;以及分解module graph
的过程中,需要遍历module graph
、文件 transform、文件 IO 等。这些操作,往往需要消耗大量的时间,导致构建速度变得缓慢。开发模式下,dev server 需要 Webpack 完成整个工作链路才可以启动成功,这就导致构建过程耗时越久,dev server 启动越久。为了加快构建速度,Webpack 也做了大量的优化,如 loader 的缓存功能、webpack5 的持久化缓存等,但这些都治标不治本,只要 Webpack 的核心工作机制不变,那dev server启动优化,基本上永远都达不到Vite那样的效果。*unbundle
机制顾名思义,不需要做 bundle 操作,即不需要构建、分解module graph
,源文件之间的依赖关系完全通过浏览器对 ESM 规范的支持来解析。这就使得 dev server 在启动过程中只需做一些初始化的工作,剩下的完全由浏览器支持。那有的同学就会问,源文件的resolve、load、transform、parse什么时候做呢 ? 答案是浏览器发起请求以后,dev server 端会通过 middlewares 对请求做拦截,然后对源文件做 resolve、load、transform、parse 操作,然后再将转换以后的内容发送给浏览器。unbundle
机制核心* 模块之间的依赖关系的解析由浏览器实现(ESM规范)* 文件的转换由dev server
的middlewares
实现并做缓存* 不对源文件做合并捆绑操作webpack
是基于nodejs
构建,js
是以毫秒计数。vite
是基于esbulid
预构建依赖,esbulid
是采用go
语言编写的,go
语言是纳秒级别的;所以vite
比webpack
打包器快10-100倍。问:Vite的热更新为什么这么快,都到了毫秒级别了?
答:由于Vite采用unbundle
机制,所以dev sever
在监听到文件变化之后,只需要通过ws连接通知浏览器去重新加载变化的文件,剩下的工作就交给浏览器去做了
而webpack在监听源文件变化后,会重新编译打包;由于我们只修改了一个文件,所以只需要对这个文件做resolve
、load
、transform
、parse
操作,其他文件直接使用缓存,也因此dev server
响应很快,等dev server
重新编译打包好,会通过ws连接通知浏览器去获取新的打包文件,然后对页面做局部的更新;
问:webpack和vite打包过程有什么不同;
webpack:
1.分析各模块之间的依赖
2.编译打包
3.启动服务器
vite:
1.启动服务器
2.请求模块时按需动态编译显示
问:Vite有什么缺点?极致的快,消耗的代价是什么?
unbundle
机制给Vite
在dev server
方面获得巨大的性能提升,但也带来了一些代价,那就是首屏和懒加载的性能下降
首屏问题
由于unbundle
机制,首屏期间需要额外做一些工作
1.不对源文件做合并捆绑操作,导致大量的http
请求
2.dev server
运行期间对源文件做resolve、load、transform、parse
操作
3.预构建、二次预构建操作也会阻塞首屏请求,直到预构建完成为止
相对比于webpack,Vite把需要在dev server
启动过程中完成的工作,转移到dev server
响应浏览器请求的过程中,所以不可避免的导致首屏性能下降;不过首屏性能差只发生在dev server
启动以后第一次加载页面时发生;之后reload
页面时,首屏的性能会好很多,因为dev server
会将之前已经完成转换的内容缓存起来
懒加载
由于 unbundle
机制,动态加载的文件,需要做 resolve、load、transform、parse
操作,并且还有大量的 http
请求,导致懒加载性能也受到影响
问:resolve、load、transform、parse
操作是什么?
答:Vite
中源文件的转换是在 dev server
启动以后通过 middlewares
实现的。
当浏览器发起请求以后,dev sever
会通过相应的 middlewares
对请求做处理,然后将处理以后的内容返回给浏览器。
middlewares
对源文件的处理,分为 resolve
、load
、transform
、parser
四个过程:
resolve
- 解析url
,找到源文件的绝对路径;load
- 加载源文件。如果是第三方依赖,直接将预构建内容返回给浏览器;如果是业务代码,继续transform
、parser
。transfrom
- 对源文件内容做转换,即ts
->js
,less
->css
等。转换完成的内容可以直接返回给浏览器了。parser
- 对转换以后的内容做分析,找到依赖模块,对依赖模块做预转换 -pre transform
操作,即重复1
-4
。pre transform
是Vite
做的一个优化点。预转换的内容会先做缓存,等浏览器发起请求以后,如果已经完成转换,直接将缓存的内容返回给浏览器。
Vite
在处理步骤 3
时,是通过 esbuild.transform
实现的,对比 Webpack
使用各个 loader
处理源文件,那是非常简单、快捷的。
最后
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享