webpack中文网(三)tree shaking(副作用、压缩输出)、生产环境构建(webpack-merge、指定环境)、代码分离(防止重复、动态导入)
总结:
tree shaking
- 通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)
- 通过
package.json
的"sideEffects"
属性作为标记,向 compiler (编译程序)提供提示,表明项目中的哪些文件是 “pure(纯的 ES2015 模块)”,由此可以安全地删除文件中未使用的部分。
- [副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。
- 注意,任何导入的文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似
css-loader
并导入 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除- 压缩输出
- 引入一个能够删除未引用代码(dead code)的压缩工具(minifier)(例如
UglifyJSPlugin
)。- 从 webpack 4 开始,也可以通过
"mode"
配置选项轻松切换到压缩输出,只需设置为"production"
。生产环境构建
配置
由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
为了将这些配置合并在一起,我们将使用一个名为
webpack-merge
的工具。
在
webpack.common.js
中,我们设置了entry
和output
配置,并且在其中引入这两个环境公用的全部插件。在
webpack.dev.js
中,我们为此环境添加了推荐的devtool
(强大的 source map)和简单的devServer
配置。(npm scripts 中 start:实时重新加载功能)"start": "webpack-dev-server --open --config webpack.dev.js",
最后,在
webpack.prod.js
中,我们引入了之前在 tree shaking 指南中介绍过的UglifyJSPlugin
。(npm scripts 中 build:压缩打包功能)"build": "webpack --config webpack.prod.js"
source map
- 避免在生产中使用
inline-***
和eval-***
,因为它们可以增加 bundle 大小,并降低整体性能。指定环境
- 许多 library 将通过与
process.env.NODE_ENV
环境变量关联,以决定 library 中应该引用哪些内容。- 当使用
process.env.NODE_ENV === 'production'
时,一些 library 可能针对具体用户的环境进行代码优化,从而删除或添加一些重要代码- 我们可以使用 webpack 内置的
DefinePlugin
为所有的依赖定义这个变量代码分离
- 代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
- 三种方法
- 入口起点:使用
entry
配置手动地分离代码。
- 如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中。
- 这种方法不够灵活,并且不能将核心应用程序逻辑进行动态拆分代码。
- 防止重复:使用
CommonsChunkPlugin
去重和分离 chunk。下面是一些对代码分离有帮助的插件和loader:
ExtractTextPlugin
: 用于将 CSS 从主应用程序中分离。bundle-loader
: 用于分离代码和延迟加载生成的 bundle。promise-loader
: 类似于bundle-loader
,但是使用的是 promises。- 动态导入(await import.then):通过模块的内联函数调用来分离代码。
chunkFilename
,它决定非入口 chunk 的名称- 不再使用静态导入
lodash
,而是通过使用动态导入(import)来分离一个 chunk- 由于
import()
会返回一个 promise,因此它可以和async
函数一起使用。
1. tree shaking
tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import
和 export
。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup。
新的 webpack 4 正式版本,扩展了这个检测能力,通过 package.json
的 "sideEffects"
属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 “pure(纯的 ES2015 模块)”,由此可以安全地删除文件中未使用的部分。
本指南的继承自起步指南。如果你尚未阅读该指南,请先行阅读。
添加一个通用模块
在我们的项目中添加一个新的通用模块文件 src/math.js
,此文件导出两个函数:
project
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
|- index.js
+ |- math.js
|- /node_modules
src/math.js
export function square(x) {
return x * x;
}
export function cube(x) {
return x * x * x;
}
接着,更新入口脚本,使用其中一个新方法,并且为了简单,将 lodash
删除:
src/index.js
- import _ from 'lodash';
+ import { cube } from './math.js';
function component() {
- var element = document.createElement('div');
+ 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('\n\n');
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;
}
注意,上面的 unused