使用 webpack 开启 tree shaking
作者:Seiya
时间:2019年07月10日
tree shaking
概念
一个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到 bundle 里⾯去,tree shaking 就是只把用到的方法打入 bundle ,没用到的方法会在 uglify 阶段被擦除掉。
DCE(Dead code elimination)
也就是把没用用到的 dead code 擦除掉,dead code 的含义具体来讲就是:
代码不会被执行,不可到大;
代码执行的结果不会被用到;
代码只会影响到死变量(只写不读);
tree shaking 原理
tree shaking 本质上就是对模块代码进行静态的分析,在编译阶段确定代码是否被运行,对代码进行注释,并在 uglify 阶段删除无用的代码。
tree shaking 利用了 ES6 模块的以下特点:
只能作为模块顶层的语句出现;
import
的模块名只能是字符串常量;import binding
是immutable
的(不可修改);
注意:
tree shaking 利用的是 es 的模块系统,所以要实现第三方库的 tree shaking,需要安装库对应的模块系统即可。
JS tree shaking
使用
在 webpack v4 中,不再需要配置 UglifyjsWebpackPlugin,只需要配置mode为"production",即可显式激活 UglifyjsWebpackPlugin 插件。具体配置如下:
const path = require("path");
module.exports = {
entry: {
app: "./src/app.js"
},
output: {
publicPath: __dirname + "/dist/",
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js"
},
mode: "production"
};
接下来,我们新增一个 util.js 文件,并输入一下内容:
export function a() {
return 'this is function "a"';
}
export function b() {
return 'this is function "b"';
}
export function c() {
return 'this is function "c"';
}
然后,我们在 app.js 文件中引入 util.js 中的部分函数,如下所示:
import { a } from "./vendor/util";
console.log(a());
最后,我们执行打包命令,可以发现,只有 a() 函数的内容被打包进来了,其它函数并没有被打包进来,说明 tree shaking 配置成功。
处理第三方库
对于经常使用的第三方库(例如 jQuery、lodash 等等),如何实现Tree Shaking?下面以 lodash.js 为例,进行介绍。
首先,我们在 app.js 文件中引入
import { chunk } from "lodash";
console.log(chunk([1, 2, 3], 2));
然后,我们安装 lodash 库的 ES 写法版本:npm install -D lodash-es。
接下来,我们修改 app.js 文件,如下所示:
import { chunk } from "lodash-es";
console.log(chunk([1, 2, 3], 2));
提示:
在一些对加载速度敏感的项目中使用第三方库,请注意库的写法是否符合 es 模板系统规范,以方便 webpack 进行 tree shaking
css tree shaking
随着 webpack 的兴起,css 也可以进行 Tree Shaking: 以去除项目代码中用不到的 CSS 样式,仅保留被使用的样式代码。要实现 css tree shaking,需要借助几个插件:
PurifyCSS
:仅保留被使用的 css 样式代码glob-all
:帮助 PurifyCSS 进行路径处理,定位要做 Tree Shaking 的路径文件
接下来,我们结合 extract-text-webpack-plugin 的配置编写 webpack 配置文件:
const path = require("path");
const PurifyCSS = require("purifycss-webpack");
const glob = require("glob-all");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
let extractTextPlugin = new ExtractTextPlugin({
filename: "[name].min.css",
allChunks: false
});
let purifyCSS = new PurifyCSS({
paths: glob.sync([
/* 要做CSS Tree Shaking的路径文件 */
path.resolve(__dirname, "./*.html"), // 请注意,我们同样需要对 html 文件进行 tree shaking
path.resolve(__dirname, "./src/*.js")
])
});
module.exports = {
entry: {
app: "./src/app.js"
},
output: {
publicPath: __dirname + "/dist/",
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js",
chunkFilename: "[name].chunk.js"
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: {
loader: "style-loader",
options: {
singleton: true
}
},
use: {
loader: "css-loader",
options: {
minimize: true
}
}
})
}
]
},
plugins: [extractTextPlugin, purifyCSS]
};