Vite是什么
一种前端构建工具,由两部分组成:
rollup 、webpack、vite的区别
为什么选 Vite
webpack:分析各个模块之间的依赖,然后进行编译,打包后的代码在本地服务器渲染。随着模块增多,打包的体积变大,造成热更新速度变慢,文件修改后的效果也需要几秒钟甚至更长时间才能在浏览器中反映出来。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和幸福感。
vite:vite启动的时候不需要分析各个模块之间的依赖关系、不需要打包编译。vite可按需动态编译缩减时间。当项目越复杂、模块越多的情况下,vite明显优于webpack。
webpack是基于nodejs构建,js是以毫秒计数。
vite是基于esbulid预构建依赖,可提高页面加载速度,esbulid是采用go语言编写的,go语言是纳秒级别的。
Vite采用了ES模块来实现模块的加载。目前基于web标准的ES模块已经覆盖了超过90%的浏览器。
Tree-shaking
tree shaking 是一个术语。通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。这个概念早在 1990 年就已经被提出,但直到ES6规范被提出之后,才被应用起来,因为它依赖于 ES6 模块语法的静态结构特性,例如 import和export,它会在运行过程中静态分析模块之间的导入导出,确定 ESM 模块中哪些导出值未曾被其它模块使用,并将其删除,以此实现打包产物的优化。
如下所示的代码是不被允许的:
if(condition) { import foo from "foo" } else { import bar from "bar" }
相反,我们必须在任何条件之外定义全局范围内的所有导入。
import foo from "foo" import bar from "bar" if(condition) { // foo() } else { // bar() }
这种语法可以确定导入后使用的任何代码,而无需先运行这些代码。(可以有效的 Tree Shaking)
为什么需要 Tree Shaking
当今的 Web 应用越来越大,浏览器处理 JavasSript 是非常耗费资源(耗时)的,如果我们能将其中的无用代码去掉,仅提供有效代码给浏览器处理,无疑会减少浏览器的负担,而 Tree Shaking 正是解决了这一痛点。
从这个角度看,Tree Shaking 属于性能优化的范畴。
通过减少 Javascript 中的无用代码,来减少文件体积,浏览器加载资源的时间就会降低,进而减少用户打开页面所需的等待时间(增强用户体验)
在 Webpack 中,启动 Tree Shaking 功能必须同时满足三个条件:
// webpack.config.js module.exports = { entry: "./src/index", mode: "production", devtool: false, optimization: { usedExports: true, }, };
webpack5已经自带了这个功能,当打包环境为production时,默认开启tree-shaking功能。
热更新时webpack做了什么
总的来说,webpack的热更新就是,当我们对代码做修改并保存后,webpack会对修改的代码块以及该模块的依赖重新编译打包,并将新的模块发送至浏览器端,浏览器用新的模块代替旧的模块,从而实现了在不刷新浏览器的前提下更新页面。相比起直接刷新页面的方案,HMR的优点是可以保存应用的状态。当然,随着项目体积的增长,热更新的速度也会随之下降。
其中,使用webpack冷启动项目的流程是1 -> 2 -> A -> B,热更新的流程是1 -> 2 -> 3 -> 4 -> 5。热更新的大致流程如下:
热更新时vite做了什么
热更新主要与项目编写的源码有关。前面提到,对于源码,vite使用原生esm方式去处理,在浏览器请求源码文件时,对文件进行处理后返回转换后的源码。vite对于热更新的实现,大致可以分为三步:
a. 监听文件变动
b. 读取文件内容
c. 通知浏览器做相应的更新
vite热更新的实现原理
总结:vite为什么比webpack快
构建速度快:Webpack 会先将代码打包,然后启动开发服务器,请求服务器时返回打包后的结果;而 Vite 是直接启动开发服务器,请求哪个模块再对该模块进行实时编译,省去了打包的过程。
热更新快:相比起webpack会对修改的模块以及该模块的依赖重新编译,vite会让浏览器帮忙做更多的事情。vite 采用立即编译当前修改文件的办法,当改动了一个模块后,仅需让浏览器重新请求该模块即可。同时 vite 还会使用缓存机制( http 缓存、 vite 内置缓存 ),加载更新后的文件内容。
Esbuild
Esbuild 是一个非常新的模块打包工具,它提供了与 Webpack、Rollup、Parcel 等工具相似的资源打包能力,却有着高的离谱的性能优势:
从上到下,耗时逐步上升达到数百倍的差异,这个巨大的性能优势使得 Esbuild 在一众基于 Node 的构建工具中迅速蹿红,特别是 Vite 2.0 宣布使用 Esbuild 预构建依赖后,前端社区关于它的讨论热度逐渐上升。
esbuild 重点提到的就是构建速度方面,为什么会比 webpack 快呢?而且不在同一个数量级。
关键因素:
语言优势
JavaScript 本质上依然是一门解释型语言,JavaScript 程序每次执行都需要先由解释器一边将源码翻译成机器语言,一边调度执行;而 Go 是一种编译型语言,在编译阶段就已经将源码转译为机器码,启动时只需要直接执行这些机器码即可。也就意味着,Go 语言编写的程序比 JavaScript 少了一个动态解释的过程。
多线程优势
Go 天生具有多线程运行能力,而 JavaScript 本质上是一门单线程语言,直到引入 WebWorker 规范之后才有可能在浏览器、Node 中实现多线程操作。
它的实现算法经过非常精心的设计,尽可能饱和地使用各个 CPU 核,特别是打包过程的解析、代码生成阶段已经实现完全并行处理。
除了 CPU 指令运行层面的并行外,Go 语言多个线程之间还能共享相同的内存空间,而 JavaScript 的每个线程都有自己独有的内存堆。这意味着 Go 中有多个处理单元,例如解析资源 A 的线程,可以直接读取资源 B 线程的运行结果,而在 JavaScript 中相同的操作需要调用通讯接口 woker.postMessage 在线程间复制数据,所以在运行时层面,Go 拥有天然的多线程能力,更高效的内存使用率,也就意味着更高的运行性能。
节制
对,没错,节制!
Esbuild 并不是另一个 Webpack,它仅仅提供了构建一个现代 Web 应用所需的最小功能集合,未来也不会大规模加入我们业已熟悉的各类构建特性。最新版本 Esbuild 的主要功能特性有:
可以看到,这份列表中支持的资源类型、工程化特性非常少,甚至并不足以支撑一个大型项目的开发需求。在这之外,官网明确声明未来没有计划支持如下特性:
而且,Esbuild 所设计的插件系统也无意覆盖以上这些场景,这就意味着第三方开发者无法通过插件这种无侵入的方式实现上述功能,可以预见未来可能会出现很多魔改版本。
Esbuild 只解决一部分问题,所以它的架构复杂度相对较小,相对地编码复杂度也会小很多,相对于 Webpack、Rollup 等大一统的工具,也自然更容易把性能做到极致。节制的功能设计还能带来另外一个好处:完全为性能定制的各种附加工具。
定制
回顾一下,在 Webpack、Rollup 这类工具中,我们不得不使用很多额外的第三方插件来解决各种工程需求,比如:
Esbuild 选择完全重写整套编译流程所需要用到的所有工具!这意味着它需要重写 js、ts、jsx、json 等资源文件的加载、解析、链接、代码生成逻辑。
开发成本很高,而且可能被动陷入封闭的风险,但收益也是巨大的,它可以一路贯彻原则,以性能为最高优先级定制编译的各个阶段,比如说:
这种深度定制一方面降低了设计成本,能够保持编译链条的架构一致性;一方面能够贯彻性能第一的原则,确保每个环节以及环节之间交互性能的最优。虽然伴随着功能、可读性、可维护性层面的的牺牲,但在编译性能方面几乎做到了极致。
结构一致性
Esbuild 重写包括 js、ts、jsx、css 等语言在内的转译工具,所以它更能保证源代码在编译步骤之间的结构一致性,比如在 Webpack 中使用 babel-loader 处理 JavaScript 代码时,可能需要经过多次数据转换:
源码需要经历 string => AST => AST => string => AST => string ,在字符串与 AST 之间反复横跳。
而 Esbuild 重写大多数转译工具之后,能够在多个编译阶段共用相似的 AST 结构,尽可能减少字符串到 AST 的结构转换,提升内存使用效率。
总结
单纯从编译性能的维度看,Esbuild 确实完胜世面上所有打包框架,差距甚至能在百倍之大:
耗时 |
性能差异 |
速度 |
产物大小 |
|
Esbuild |
0.11s |
1x |
1198.5 kloc/s |
0.97mb |
Esbuild (1 thread) |
0.40s |
4x |
329.6 kloc/s |
0.97mb |
webpack 4 |
19.14s |
174x |
6.9 kloc/s |
1.26mb |
parcel 1 |
22.41s |
204x |
5.9 kloc/s |
1.56mb |
webpack 5 |
25.61s |
233x |
5.1 kloc/s |
1.26mb |
parcel 2 |
31.39s |
285x |
4.2 kloc/s |
0.97mb |
Vite3新特性
左边是Vite3.0,右边是Vite2.0,在视觉上明显3.0比2.0要好看。
除了外观之外,我们可以看到默认的端口号也发生了变化,从3000变成了5173;Local的地址从localhost变成了127.0.0.1。
查看vscode扩展加载时间
ctrl+shift+p
注:学习笔记,纯分享
引用链接