此章节承接上一篇文章:webpack v4.30.0(5)官方说明文档起步(tree shaking章节承接起始章节)

webpack v4.30.0(5)官方说明文档起步(tree shaking章节承接起始章节):

http://www.dianthink.com/article/detail/id/284.html

(一)、本文章开始:

(1)、添加一个通用模块
(2)、将文件标记为无副作用(side-effect-free)
(3)、压缩输出
(4)、结论

(二)、本栏目开始:
(1)、添加一个通用模块

在我们的项目中添加一个新的通用模块文件 src/math.js,此文件导出两个函数:

math.js:文件中代码如下:

export function square(x) {
  return x * x;
}
export function cube(x) {
  return x * x * x;
}

接着,更新入口脚本,使用其中一个新方法,并且为了简单,将 lodash 删除:
src/index.js:文件中代码如下:

import { cube } from './math.js';
function component() {
var element = document.createElement('pre');
// lodash 是由当前 script 脚本 import 导入进来的
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.innerHTML = [
'Hello webpack!',
'5 cubed is equal to ' + cube(5)
].join('nn');
return element;
}
document.body.appendChild(component());
注意,我们并未从 src/math.js 模块中 import 导入 square 方法。这个功能是所谓的“未引用代码(dead code)”,也就是说,应该删除掉未被引用的 export。现在让我们运行我们的npm 脚本 npm run build,并检查输出的 bundle:
dist/bundle.js (around lines 90 - 100)(请注意,练习中可能和文档中的有所出入)

/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* unused harmony export square */
/* harmony export (immutable) */ __webpack_exports__["a"] = cube;
function square(x) {
  return x * x;
}
function cube(x) {
  return x * x * x;
}

你在bundle.js不一定看到上面的代码,或者能看到压缩后的代码;

注意,上面的 unused harmony export square 注释。如果你看下面的代码,你会注意到 square 没有被导入,但是,它仍然被包含在 bundle 中。我们将在下一节中解决这个问题。

(2)、将文件标记为无副作用(side-effect-free)

在一个纯粹的 ESM 模块世界中,识别出哪些文件有副作用很简单。然而,我们的项目无法达到这种纯度,所以,此时有必要向 webpack 的 compiler 提供提示哪些代码是“纯粹部分”。
这种方式是通过 package.json 的 "sideEffects" 属性来实现的。
{
  "name": "your-project",
  "sideEffects": false
}
如同上面提到的,如果所有代码都不包含副作用,我们就可以简单地将该属性标记为 false,来告知 webpack,它可以安全地删除未用到的 export 导出。
「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。
如果你的代码确实有一些副作用,那么可以改为提供一个数组:

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js"
  ]
}
数组方式支持相关文件的相对路径、绝对路径和 glob 模式。它在内部使用 micromatch。
注意,任何导入的文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并导入 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}
最后,还可以在 module.rules 配置选项 中设置 "sideEffects"。

(3)、压缩输出
通过如上方式,我们已经可以通过 import 和 export 语法,找出那些需要删除的“未使用代码(dead code)”,然而,我们不只是要找出,还需要在 bundle 中删除它们。为此,我们将使用 -p(production) 这个 webpack 编译标记,来启用 uglifyjs 压缩插件。
注意,--optimize-minimize 标记也会在 webpack 内部调用 UglifyJsPlugin。
从 webpack 4 开始,也可以通过 "mode" 配置选项轻松切换到压缩输出,只需设置为 "production"。
webpack.config.js代码如下:

const path = require('path');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
},
mode: "production"
};
注意,也可以在命令行接口中使用 --optimize-minimize 标记,来使用 UglifyJSPlugin。
准备就绪后,然后运行另一个命令 npm run build,看看输出结果有没有发生改变。
你发现 dist/bundle.js 中的差异了吗?显然,现在整个 bundle 都已经被精简过,但是如果仔细观察,则不会看到 square 函数被引入,但会看到 cube 函数的修改版本(function r(e){return e*e*e}n.a=r)。现在,随着 tree shaking 和代码压缩,我们的 bundle 减小几个字节!虽然,在这个特定示例中,可能看起来没有减少很多,但是,在具有复杂的依赖树的大型应用程序上运行时,tree shaking 或许会对 bundle 产生显著的体积优化。
(4)、结论
为了学会使用 tree shaking,你必须……
使用 ES2015 模块语法(即 import 和 export)。
在项目 package.json 文件中,添加一个 "sideEffects" 入口。
引入一个能够删除未引用代码(dead code)的压缩工具(minifier)(例如 UglifyJSPlugin)。
你可以将应用程序想象成一棵树。绿色表示实际用到的源码和 library,是树上活的树叶。灰色表示无用的代码,是秋天树上枯萎的树叶。为了除去死去的树叶,你必须摇动这棵树,使它们落下。
如果你对优化输出很感兴趣的话,请进入到下一个指南,来了解生产环境中进行构建的详细细节。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部