webpack 学习笔记之webpack5

138 阅读5分钟

webpack5 在 2020-10-10 正式发布。

webpack5 发布以及更新日志:webpack.docschina.org/blog/2020-1…

1. webpack5 新特性

1.1 最小 Node.js 版本:10.13.0

最低支持的 Node.js 版本从 6 增加到 10.13.0

1.2 功能清除

  • 所有在 webpack4 里面被废弃的能力都被清除,因此需要确保 webpack4 没有打印警告。
  • require.includes 语法已经被废弃(可以通过 Rule.parser.requireInclude 将行为改为允许、废弃或禁用)

require.includes的作用:是 webpack 自身实现的一个语法,作用是实现一个模块预加载。

  • 不再为 Node.js 模块引入 polyfill

之前的版本是:如果某个模块依赖 Node.js 里面的核心模块,那么这个模块被引入的时候会把 Node.js 整个 polyfill 顺带引入。

webpack4:里面利用 node-libs-browser 这个实现 polyfill 的。

1.3 长期缓存:确定的模块 ld、chunk 和导出名称

在生产模式下,默认的 chunklds: "deterministic", modulelds:“deterministic"。设置成 deterministic 时默认最小3位数字会被使用。

image.png

image.png

例子:

image.png

webpack4:1,2,3... 递增的方式

image.png

webpack5:数字是确定的,比如多个 import 模块时,不会因为一个变化了而产生变化。

image.png

image.png

1.4 持久化缓存

在 webpack4 里面,可以使用 cache-loader 将编译结果写入硬盘缓存,还可以使用 babel-loader,设置 option.cacheDirectory 将 babel-loader 编译的结果写进磁盘。

webpack5缓存策略

  • 默认开启缓存,缓存默认是在内存里。可以对 cache 进行设置。
  • 缓存淘汰策略:文件缓存存储在 node_ modules/.cache/webpack,最大 500 MB, 缓存时常两个星期,旧的缓存先淘汰

image.png

1.5 构建优化

Tree Shaking 优化 — 嵌套的 Tree shaking

例子:module.js 里使用了 inner.js,然后 user.js 里使用了 module.js 文件

image.png

image.png

Tree Shaking 优化 — 内部模块 Tree shaking

例子:usingSomething 里使用了 something,test 里使用了 usingSomething,但是 test 未被使用。

image.png

webpack4 会打包进去

image.png

webpack5 里可以分析模块之间的关系(内部通过一个 innerGraph 算法去实现),上面不会打包

image.png

1.6 代码生成:支持生成 ES6 代码

webpack4 之前只生成 ES5 的代码。

webpack5 则现在既可以生成 ES5 又可以生成 ES6/ES2015 代码。

两种设置方式:5 =< ecmaVersion <= 11 或 2009 =< ecmaVersion <= 2020

比如:写 2015 也是可以的

image.png

1.7 开创性的特性:模块联邦

发明者:Zack Jackson

模块联邦可以实现微前端。

基本解释:使一个 JavaScript 应用在运行过程中可以动态加载另一个应用的代码, 并支持共享依赖(CDN)。不再需要本地安装 Npm 包。

Remote:被依赖方,服务提供方,被 Host 消费的 Webpack 构建 Host:依赖方,消费其他 Remote 的 Webpack 构建

一个应用可以是 Host,也可以是 Remote,也可以同时是 Host 和 Remote。

ModuleFederationPlugin 介绍

Webpack 内部通过 ModuleFederationPlugin 插件将多个应用结合起来。

  • name:必须,唯一 ID, 作为输出的模块名,使用的时通过 name/{name}/{expose} 的方式使用
  • library:必须,其中这里的 name 为作为 umd 的 name;
  • remotes:可选,表示作为 Host 时,去消费哪些 Remote;
  • shared:可选,优先用 Host 的依赖,如果 Host 没有,再用自己的;
  • main.js:应用主文件
  • remoteEntry.js:作为 remote 时被引的文件

webpack5 相对于 webpack4 ,构建速度更快,构建体积也更小,但是在开发阶段并不能明显感受到。

模块联邦使用案例

应用一 (host):要去消费 app2,端口号 3002

image.png

应用二 (remote):提供了 Button 组件

image.png

浏览器的效果

app1 应用使用了 app2 的 Button 组件端口为 3001。

image.png

app2 应用端口为 3002

image.png

app1 怎么找到 app2 的?

通过 remoteEntry.js 找到生产者的模块。

image.png

image.png

app2 提供了 button

image.png

app1 使用 button

image.png

这样就达到了组件的共享。

打包构建之后,可以看到 remoteEntry.js 里面有 moduleMap,并且提供了get 方法。

image.png

2. bundle 和 bundless 的差异

vite 发布 2.0 版本
vitejs.cn/
Vite 是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:

  • 一个开发服务器,它基于 原生 ES 模块 提供了 丰富的内建功能,如速度快到惊人的 模块热更新(HMR)。
  • 一套构建指令,它使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。

image.png

2.1 更早实践 bundless 的工具:Snowpack

www.snowpack.dev/

Snowpack 是一个闪电般快速的前端构建工具,专为现代网络而设计。 它是开发工作流程中更重、更复杂的打包工具(如 webpack 或 Parcel)的替代品。 Snowpack 利用 JavaScript 的本机模块系统(称为 ESM)来避免不必要的工作并保持快速,无论您的项目有多大。

2.2 浏览器对ESM的支持情况

caniuse.com/?search=jav…

image.png

2.3 HTTP/1.1 的请求数限制

打包会合并文件,减少请求数

image.png

各浏览器在HTTP/1.1 协议下的最大请求数限制:chrome为6个,IE11为11个,Firefoc为9个 Safari 13为6个。 但是在 http2中就已经没有请求数限制了。

2.4 HTTP/2 越来越多的应用在主流网站

现在,国内很多应用已经开始使用 HTTP/2 了,比如 抖音、掘金等等。

image.png

2.5 资源加载差异

  • bundle 浏览器最开始会加载一个 bundle.js 文件
  • bundless:浏览器请求多个文件

image.png

bundle: 浏览器最开始会加载一个构建好的 bundle.js 文件,如下图:

image.png

bundless: 直接加载原文件,不是加载构建好的,如下图:

image.png

2.6 打包速度的对比

  • bundless 的冷启动时间大大缩短
  • bundless 的 HMR 速度不受整个项目体积影响
  • bundless 的单文件粒度的缓存更优

image.png

2.7 开发体验的对比

以 webpack 里面的 sourcemap 类型举例

bundle 依赖 sourcemap,并且类型很多,bundless 直接打 debugger 就行,调试起来相对简单。

image.png

3. Vite 的构建原理

3.1 Vite 构建速度快的原因

预构建使用 ESBuild (冷启动快的原因) :​ ​github.com/evanw/esbui…

因为 esbuild 里面使用的是 Golang 语言去进行打包,它是静态语言。
如图,esbuild 打包用时 0.33s。

image.png

3.2 Vite 打包流程

创建构建服务

image.png

静态文件托管服务

image.png

重写模块路径

image.png

image.png

  • 对于 bare import,把模块名替换为这个模块的 entry path,并在 path 的开头补上一个 /@modules 的标识符。如: import React from "/@modules/@pika/react/source.development.js"

  • 相对路径转绝对路径,方便浏览器请求。

  • 补齐文件扩展名和经常被省略的 index.xxx,如:import a from '/src/a/index.js'

  • 给非 js 类型( js 类型:如 js(x)/ts(x)/vue)的文件地址加上一个叫 "import" 的 query 参数。

  • hmr 相关的请求地址添加时间戳,避免缓存。如: import '/src/App.jsx?t=1599124870589'

静态资源打包策略

浏览器不支持 JS 中直接写 import CSS、图片、JSON 等语法。.

回顾一下webpack loader 的处理策略:

  • CSS:转换成 js 的模块,执行模块会在 DOM 中创建 <style> 标签并且插入 CSS 内容
  • 图片:转换成图片路径
  • JSON:转化成 js 模块, default export = json

vue 脚本打包策略: image.png

CSS 资源打包策略:

image.png

image.png

模板打包策略:

image.png

总结

到底选择哪一种构建工具,需要看场景,

  • 如果是很复杂的场景,选择 webpack 作为构建工具,因为 webpack 的生态是比较强大的;
  • 对于不复杂的场景,而且 vite 的生态也能满足的场景,可以去使用 vite。
  • 也可以尝试结合两种构建工具的优势进行开发。