webpack学习笔记(10)
学习笔记
Tree shaking
tree shaking 在计算机中表示消除死代码(dead code).
JavaScript 的 Tree shaking 源自于 rollup, 依赖 ES Module 的静态语法分析.
webpack4 正式扩展了这个能力, 分为usedExports
和sideEffects
两种:
usedExports
optimization.usedExports
, production模式下默认为 true. 该配置会配合TerserPlugin使用, 方便演示, 以下默认mode
为development.
示例入口文件:
1 |
|
模块文件:
1 |
|
先开启optimization.usedExports
, 关闭TerserPlugin插件, 查看打包产物:
可以看到对于没有引用的函数, usedExports
会在上方标明注释, 提供给TerserPlugin进行加工删除.
现在开启TerserPlugin插件, 查看打包产物:
会发现打包产物中mul函数没有被打包进去.
此时如果再将作用域提升webpack.optimize.ModuleConcatenationPlugin插件打开, 打包产物就会只显示 sum 函数, 连引入标识, IIFE 等信息一并删除, 就想上一篇末尾提到的那样.
sideEffects
sideEffects
主要用于第三方库文件, 在 npm 包的package.json中配置sideEffects, 用于告知 webpack compiler 哪些模块是有副作用的.
什么是副作用? 即模块内可能存在影响到全局环境的逻辑; 比如说某个模块并不是只含有纯函数, 而是存在
1 |
|
这样的逻辑, 这就表示该模块是有副作用的, 随意删除模块代码可能会影响运行.
所以sideEffects
默认为 true. 也就是默认情况下, 直接使用
1 |
|
webpack 是不会将 math 模块的代码删除的.
可以配置数组, 指定模块中那些文件是含有副作用的; 当然推荐编写不含有副作用的模块, 但是对于 css 文件而言, 一定是有副作用的, 所以如果项目中引入了模块中的 css 文件, 有以下两种解决方式:
sideEffects
中添加 css 文件, 如"sideEffects": ["**/*.css"]
- 在
module.rules
对处理 css 文件时配置sideEffects
1 |
|
下面也举个简单例子, 本地创建个 npm 包, 包含两个文件:
index.js:
1 |
|
style.css:
1 |
|
通过yarn link
在 demo 中引入, demo 入口文件添加以下代码:
1 |
|
现将 npm 包中sideEffects
置为 false, 打包页面浏览器打开:
可以看到color样式没有生效, window.app也没有赋值.
然后将sideEffects
配置为**[“**/*.css”]**或者配置rules.sideEffects
都可以; 打包页面打开浏览器:
说明 css 文件参与打包, js 文件被删除了.
最后将sideEffects
置为 true, 可以看到有副作用的文件都参与打包.
总结一下
如何在生产环境对 JavaScript 代码进行 tree shaking 呢?
- 设置
optimization.usedExports
为 true, 帮助TerserPlugin进行优化 - package.json中配置
sideEffects
, 直接对模块进行优化.
Tree-shaking in Css
早期 webpack 使用purifyCss插件对 css 文件进行 tree shaking, 但是该库已不再维护, 最新的提交也是 4 年前, 目前使用purgeCss来完成 css 的 tree shaking.
安装: yarn add -D purgecss-webpack-plugin
如果想要正常使用purgeCss还需要安装mini-css-extract-plugin生成单独 css 文件插件, 如果之前没安装过也需要安装.
使用示例, purgeCss版本更新后需要解构引入:
1 |
|
purgeCss会识别 html 和 js 中用到的 class 或 className 等, 经测试:
- 即使 js 中注释 className 逻辑, 打包产物仍然会存在对应类名
- 不会去除对 body, html 标签设置的 css
- 有可能会额外删除 代码中实际会用到的 css, 导致样式错乱(在博主 Vue 项目中有出现过)
抛开上述问题, purgeCss打包效果是非常优秀的. 第三点可以通过配置safeList解决
1 |
|
Compress
这个属于了解知识. 一般性能优化也不会到这种地步(笑)
Http 压缩
如今绝大部分浏览器都已经支持 Http 压缩, 支持的浏览器在向服务器发送请求时, 会告知服务器自己支持哪些压缩格式, 例如Accept: Encoding: gzip, deflate
, 服务器中如果存在浏览器支持压缩格式的压缩文件就会, 就会直接返回对应的压缩后文件, 并在响应头重告知浏览器, 例如Content-Encoding: gzip
, 浏览器会完成解压操作, 无需我们关注.
webpack 中依赖compression-webpack-plugin
插件来指定打包产物生成对应的压缩文件.
webpack 配置:
1 |
|
需要注意的是, threshold 即使设置的很小或 0, CompressionPlugin也不是会对所有匹配到的文件都进行压缩的, 插件内部设置了最小的阈值.
所以这里实例代码中引入了lodash包, 可以看到打包产物存在 js 和压缩后的 gz 文件
Html 压缩
html-webpack-plugin除了设置 html 模板同时默认也压缩了 html 代码, minify: 'auto'
表示默认配置, 也可以自己配置.
1 |
|
InlineChunkHtmlPlugin
这是react-dev-utils提供的一个插件用于关联HtmlWebpackPlugin, 将匹配到的文件插入 html 文件内联 js 形式执行, 减少打包产物的文件数量.达到文件体积和Http 请求数的平衡.
安装: yarn add -D react-dev-utils
配置, 这里以动态导入生成的 runtime 文件举例子, 将 runtime 逻辑 inline 到 html 中:
1 |
|
可以看到 runtime 文件的代码被 inline 到 html 中了, 截取了部分代码, 完整例子可以查看示例代码 p4.
这里可能会有一个问题:
- InlineChunkHtmlPlugin不会删除 inline 后的文件, 需要手动删除
npm package using webpack
webpack 同样可以用于打包代码作为第三方库文件, 只需要对添加少量配置. 虽然一般都是使用 rollup 打包
1 |
|
可以看到只是对output增加了三个属性:
- libraryTarget: 打包产物遵守哪种模块导入规则, 一般都是
umd
, 即universal module defination支持esm | amd | cmd | commonjs
所有规则导入. - library: 挂载在全局对象的对象名, 这里举例 math, 浏览器中就可通过
window.math
访问. globalObject
: 一般都用this
, this 默认根据不同环境表示不同的全局变量 window 或 global, 也可以设置成 document.
这里简单将两个函数打包为 npm 包:
1 |
|
打包为 umd 文件后, 各种环境下不同规则引用的允许情况:
浏览器:
commonjs:
esm:
可以看到都能够正常执行.
最后看下 umd 形式打包产物是如何适配不同模块导入规则的; 文件开头就能看到会通过判断不同模块规则中特有的标量如module
, define
等来判断是哪种导入规则, 从而将入口文件挂载到对应的对象上.
1 |
|
示例代码
https://github.com/Mariana-Yui/fe-learn-code/tree/main/learn-webpack/day10