Rich Harris的模块打包机 Rollup 提出了JavaScript世界的一个新特性:Tree-Shaking,为打包文件去掉不必要的导出内容。Rollup依赖 ES6模块的静态结构 (讲解了imports内容和exports内容在JavaScript执行时是不变的)检测来决定哪个导出是不必要的。
webpack 2的Tree-Shaking还在beta阶段。这篇文章讲解了它是如何工作的。也可以先看个demo: tree-shaking-demo
webpack的新beta版本webpack 2通过下面两步来排除无用的导出:
如果模块系统有静态结构,无用的导出将在打包的时候被检测出来。所以,webpack 2可以分析理解所有的ES6代码并且只在检测到是ES6模块时才使用tree-shaking。然而,只有import导入和export导出的模块才会被编译为ES5,如果你希望所有的打包文件都编译为ES5,你需要使用一个转译器来处理剩下来的文件。这篇文章中,我们将使用babel 6。
样例代码含有两个ES6 模块 helpers.js
和 main.js
。
// helpers.js export function foo() { return 'foo'; } export function bar() { return 'bar'; }
// main.js import {foo} from './helpers'; let elem = document.getElementById('output'); elem.innerHTML = `Output: ${foo()}`;
注意下导出的 heplers
的 bar
模块是没有在任何地方用到的。
正常使用Babel 6来转换的方式是这样的:
{ presets: ['es2015'], }
然而这种方式使用的 transform-es2015-modules-commonjs
插件意味着Babel会将ES 6模块通过commonJs模块转换输出,然后webpack 2就不能进行tree-shaking分析了。
function(module, exports) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.foo = foo; exports.bar = bar; function foo() { return 'foo'; } function bar() { return 'bar'; } }
你会看到 bar
成了导出的一部分,这样就成为无用代码存在于打包后文件中,而且不能被辨认出来。
我们想要的是用Babel编译ES6,但不是使用 transform-es2015-modules-commonjs
。这时,唯一个可行的方法是在我们的配置文件中列出所有要处理的文件,当然除去那些我们不需要处理的,所以我们的做法是这样的:( demo )
{ plugins: [ 'transform-es2015-template-literals', 'transform-es2015-literals', 'transform-es2015-function-name', 'transform-es2015-arrow-functions', 'transform-es2015-block-scoped-functions', 'transform-es2015-classes', 'transform-es2015-object-super', 'transform-es2015-shorthand-properties', 'transform-es2015-computed-properties', 'transform-es2015-for-of', 'transform-es2015-sticky-regex', 'transform-es2015-unicode-regex', 'check-es2015-constants', 'transform-es2015-spread', 'transform-es2015-parameters', 'transform-es2015-destructuring', 'transform-es2015-block-scoping', 'transform-es2015-typeof-symbol', ['transform-regenerator', { async: false, asyncGenerators: false }], ], }
如果我们构建这个项目, helper
模块就是这样的:
function(module, exports, __webpack_require__) { /* harmony export */ exports["foo"] = foo; /* unused harmony export bar */; function foo() { return 'foo'; } function bar() { return 'bar'; } }
现在只导出 foo
了,但是 bar
仍然在那里。通过minified之后就可以了:
function (t, n, r) { function e() { return "foo" } n.foo = e }
OK,再也没有多余的东西了。这里一个值的注意的地方是,webpack 2的tree-shaking只分析含有导入导出的ES6模块,而且使用其它的编译插件时一定需要注意下。
原文作者:Dr. Axel Rauschmayer
原译:ouven
原文地址: http://www.2ality.com/2015/12/webpack-tree-shaking.html