认识
一、认识
Webpack
是一种用于构建 JavaScript
应用程序的静态模块打包器,它能够以一种相对一致且开放的处理方式,加载应用中的所有资源文件(图片、CSS
、视频、字体文件等),并将其合并打包成浏览器兼容的 Web
资源文件。
Webpack
则忽略具体资源类型之间的差异,将所有代码/非代码文件都统一看作 Module
—— 模块对象,以相同的加载、解析、依赖管理、优化、合并流程实现打包,并借助 Loader
、Plugin
两种开放接口将资源差异处理逻辑转交由社区实现,实现统一资源构建模型,这种设计有很多优点:
-
所有资源都是
Module
: 所以可以用同一套代码实现诸多特性,包括:代码压缩、Hot Module Replacement
、缓存等 -
打包时,资源与资源之间非常容易实现信息互换,例如可以轻易在
HTML
插入Base64
格式的图片 -
借助
Loader
,Webpack
几乎可以用任意方式处理任意类型的资源,例如可以用Less
、Stylus
、Sass
等预编译CSS
代码
现如今的 Webpack
已经非常非常成熟,在基础构建能力之外还提供了诸多锦上添花的工程化工具,包括:
-
基于
Module Federation
的微前端方案 -
基于
webpack-dev-server
的Hot Module Replacement
-
基于
Terser
、Tree-shaking
、SplitChunks
等工具的JavaScript
代码压缩、优化、混淆方案 -
基于
lazyCompilation
的延迟编译功能 -
有利于提升应用性能的异步模块加载能力
-
有利于提升构建性能的持久化缓存能力
-
内置
JavaScript
、JSON
、二进制资源解析、生成能力
二、特点
三、问题
3.1 Vite、Rollup、Webpack、RsPack 各自优势、特点?
Vite
: 采用双引擎架构, 开发阶段使用 Esbuild
+ no-bundle
服务,生产环境用 Rollup
编译构建。Vite
在开发阶段, Vite
项目的启动可以分为两步。第一步是 依赖预构建, 借助 Esbuild
超快的编译速度来将不同规范的代码转换为 ES Module
格式, 方便浏览器直接加载, 此外, 预构建还会将第三方库分散的文件合并打包到一起, 减少 HTTP
请求数量; 第二步是 Dev Server
的启动, 基于浏览器原生 ESModule
的支持实现了 no-bundle
服务,实现开发阶段的 Dev Server
, 进行模块的按需加载, 可以直接在浏览器中运行源码, 无需事先打包。当浏览器请求一个模块时, Vite
会即时地编译和执行对应的代码, 会经历一系列的编译流程, 然后 Vite
会将编译结果响应给浏览器。Vite
生产环境借助 Rollup
, 从 AST
解析的功能开始, 完成代码的词法分析(tokenize
)和语义分析(parse
), 实现模块依赖图和作用域链的搭建, 并完成 Tree Shaking
、循环依赖检测及 Bundle
代码生成。 在 HMR
方面, Vite
的热更新则只会针对改动的模块进行更新,提高了更新速度。当开发者修改了一个模块的代码, Vite
可以在几毫秒内完成热更新, 将更新后的模块发送到浏览器中, 让开发者能够更快地看到代码修改后的效果。
Rollup
是一款基于 ES Module
模块规范实现的 JavaScript
打包工具。通过静态分析构建模块依赖图, 并进行 Tree Shaking
, 剔除未使用的代码。Rollup
可以直接处理 Es Modules
, 对于 CommonJs
需要通过插件来转换。Rollup
本身不提供开发服务器、HMR
等功能,主要定位于生产构建。
Webpack
: 无论开发环境还是生产环境, Webpack
会扫描整个项目的所有文件, 将所有模块进行静态分析,
分析它们之间的依赖关系, 形成依赖树, 然后一次性编译生成文件, 生成最终代码前, 根据模块中出现的特性依赖, 补充相应运行时代码, 比如立即表达式 IIFE
、Webpack
runtime
运行时代码, 生成最终产物。Webpack
实现了一套自己的 CommonJS
规范, 在 Webpack
中, 每个模块都被包装在一个函数中, 这个函数接受一个对象, 这个对象有 exports
、require
、module
等属性, 通过这种方式实现了模块的隔离, 每个模块都有自己的作用域, 不会污染全局作用域。在 HMR
方面, Webpack
的热更新需要整个模块链重新打包和替换,对于大型项目可能会有延迟。在热更新过程中, Webpack
会检测到模块的变化,然后重新编译整个模块链,最后将更新后的模块替换到浏览器中。这个过程相对复杂,可能会导致一定的延迟。另外, Webpack 5.x
内置了更加完善、更智能、更强大的 TreeShaking
、代码分割、作用域提升 等。Webpack 5.x
新特性: 1. 模块联邦(Module Federation
), 模块联邦是 Webpack 5
中最引人注目的新特性之一, 它允许不同独立构建的应用在运行时共享彼此的模块,而无需事先打包到同一个 bundle
里; 2. 持久化缓存(Persistent Caching
), Webpack 5
引入了持久化缓存功能,将中间构建结果保存到磁盘上,这样在二次构建时可以复用已有结果; 3. 更高效的 Tree Shaking
与代码优化: 使生成的产物更精简,提升浏览器缓存效果; 4. 删除 Node.js
核心模块的自动 Polyfill
, 以前 Webpack
会自动为浏览器端补充 Node.js
核心模块(例如 Buffer
、process
、crypto
等)的 polyfill
, Webpack 5
默认不再提供这些 polyfill
, 要求开发者根据项目需要手动添加或调整代码逻辑; 5. 内置资源模块(Asset Modules
), 在 Webpack 4
及之前版本中,处理静态资源(如图片、字体等)通常依赖于第三方 Loader
(如 file-loader
、url-loader
、raw-loader
等), Webpack 5
内置了资源模块,开发者可以直接在代码中 import
资源, 无需额外安装 Loader
。
RsPack
是一个基于 Rust
编写的高性能 JavaScript
打包工具, 它提供对 Webpack
生态良好的兼容性,能够无缝替换 Webpack
, 并提供闪电般的构建速度。1. Rust
语言优势: Rspack
使用 Rust
语言编写, 得益于 Rust
的高性能编译器支持, Rust
编译生成的 Native Code
通常比 JavaScript
性能更为高效; 2. 高度并行的架构: Webpack
受限于 JavaScript
对多线程的羸弱支持,导致其很难进行高度的并行化计算,而得益于 Rust
语言的并行化的良好支持, Rspack
采用了高度并行化的架构,如模块图生成,代码生成等阶段,都是采用多线程并行执行,这使得其编译性能随着 CPU
核心数的增长而增长,充分挖掘 CPU
的多核优势; 3. 内置大部分的功能: 事实上 Webpack
本身的性能足够高效,但是因为 Webpack
本身内置了较少的功能,这使得我们在使用 Webpack
做现代 Web App
开发时,通常需要配合很多的 plugin
和 loader
进行使用,而这些 loader
和 plugin
往往是性能的瓶颈,而 Rspack
虽然支持 loader
和 plugin
,但是保证绝大部分常用功能都内置在 Rspack
内,从而减小 JS plugin | loader
导致的低性能和通信开销问题; 4. 增量编译: 尽管 Rspack
的全量编译足够高效,但是当项目庞大时,全量的编译仍然难以满足 HMR
的性能要求,因此在 HMR
阶段,我们采用的是更为高效的增量编译策略,从而保证,无论你的项目多大,其 HMR
的开销总是控制在合理范围内。但是, RsPack
与 Webpack
对构建产物体积的优化方面, TreeShaking
、代码分割、作用域提升 做的不是那么完善。
扩展知识
bundle
、chunk
、**vendor
**这些构建领域的专业概念,这里给大家提前解释一下:
-
bundle
指的是整体的打包产物,包含JS
和各种静态资源。 -
chunk
指的是打包后的JS
文件,是bundle
的子集。 -
vendor
是指第三方包的打包产物,是一种特殊的chunk
。