专栏首页Young Dreamerwebpack中tree-shaking技术介绍

webpack中tree-shaking技术介绍

之前介绍过webpack3的新特性,里面提到webpack2支持了ES6的import和export,不需要将ES6的模块先转成CommonJS模块,然后再进行打包处理。正基于此,webpack2引入了tree-shaking技术,能够在模块的层面上做到打包后的代码只包含被引用并被执行的模块,而不被引用或不被执行的模块被删除掉,以起到减包的效果。

webpack的tree-shaking案例

下面结合实际代码来解释webpack2是如何实现tree-shaking的,示例代码可到github进行下载

示例代码结构如图:src中index.js为入口文件,module.js是测试的模块文件,dist中是产出的文件。

根据webpack官网的提示,webpack支持tree-shaking,需要修改配置文件,指定babel处理js文件时不要将ES6模块转成CommonJS模块,具体做法就是:

在.babelrc设置babel-preset-es2015的modules为fasle,表示不对ES6模块进行处理。

// .babelrc文件
{
  "presets": [
    ["es2015", { "modules": false }] 
  ],
  "comments": false
}

在webpack.config.js中设置babel-preset-es2015的modules为fasle,表示不对ES6模块进行处理。  

// webpack.config.js
...
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        ["es2015", { "modules": false }]
                    ]
                }
            }
        ]
...  

然后在module.js文件中创建三个模块sayHello,sayBye,sayHi,并在index.js引用sayHello,sayHi;

// module.js
export const sayHello = name => `Hello ${name}!`;
export const sayBye = name => `Bye ${name}!`;
export const sayHi = name => `Hi ${name}!`;
// index.js
import { sayHello } from './module';
import { sayHi } from './module';
const element = document.createElement('h1');
element.innerHTML = sayHello('World') + sayHi('my friend');
document.body.appendChild(element);

然后在当前目录执行 webpack 命令后,产出bundle.js的代码如下

/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return sayHello; });
/* unused harmony export sayBye */
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return sayHi; });


var sayHello = function sayHello(name) {
  return "Hello " + name + "!";
};
var sayBye = function sayBye(name) {
  return "Bye " + name + "!";
};

var sayHi = function sayHi(name) {
  return "Hi " + name + "!";
};

/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__module__ = __webpack_require__(0);



var element = document.createElement('h1');
element.innerHTML = Object(__WEBPACK_IMPORTED_MODULE_0__module__["a" /* sayHello */])('World') + Object(__WEBPACK_IMPORTED_MODULE_0__module__["b" /* sayHi */])(' to meet you');
document.body.appendChild(element);

/***/ })

从上面可以知道,sayBye模块被打上了unused harmony export标签,sayHello和sayHi被设置为__webpack_exports__的属性,在入口文件中通过读取__webpack_exports__的属性取出。

bundle.js文件虽然对多余的模块进行了标记,但是并没有删除,这是因为webpack还没有执行压缩混淆操作,可以通过webpack -p命令对产出进行压缩处理,这时候会把打了unused harmony export 标签的模块删除掉。

webpack的tree-shaking的局限性

(1)只能是静态声明和引用的ES6模块,不能是动态引入和声明的;

在打包阶段对冗余代码进行删除,就需要webpack需要在打包阶段确定模块文件的内部结构,而ES模块的引用和输出必须出现在文件结构的第一级('import' and 'export' may only appear at the top level),否则会报错。

// webpack编译时会报错
if (condition) {
  import module1 from './module1';
} else {
  import module2 from './module2';
}

而CommonJS模块支持动态结构的,所以不能对CommonJS模块进行tree-shaking处理。

(2)只能处理模块级别,不能处理函数级别的冗余;

 因为webpack的tree-shaking是基于模块间的依赖关系,所以并不能对模块内部自身的无用代码进行删除。

(3)只能处理JS相关冗余代码,不能处理CSS冗余代码。

目前webpack只对JS文件的依赖进行了处理,CSS的冗余并没有给出很好的工具。最近听了一个讲座,提到了webpack-css-treeshaking-plugin,该插件基于AST对CSS冗余代码进行了很好的处理。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • webpack3新特性简介

    6月20号webpack推出了3.0版本,官方也发布了公告。根据公告介绍,webpack团队将未来版本的改动聚焦在社区提出的功能需求,同时将保持一个快速、稳定的...

    用户1217459
  • webpack务虚扫盲

    打包工具的角色 所谓打包工具在web开发中主要解决的问题是: (1)文件依赖管理。毕竟现在都是模块化开发,打包工具首先就是要梳理文件之间的依赖关系。 (2)资源...

    用户1217459
  • 基于Webkit的浏览器关键渲染路径介绍

    关键渲染路径概念 浏览器是如何将HTML、JS、CSS、image等资源渲染成可视化的页面的呢?本文简单介绍一下渲染过程中涉及到的关键步骤。 该过程分为四步:模...

    用户1217459
  • 分割、检测与定位,高分辨率网络显神威!这会是席卷深度学习的通用结构吗?

    52CV曾经第一时间报道过CVPR2019 | 微软、中科大开源基于深度高分辨表示学习的姿态估计算法,此后该文引起不少媒体的关注。

    CV君
  • 微纳机器人之父福田敏男与中国不得不说的故事

    作为全球首位提倡微纳操作机器人的开拓者、领军者,“培养更好的科学家,踏实从事科研的人”,是福田敏男来到中国,除了科研之外,正在努力的事。 在电影《神奇的旅程》...

    机器人网
  • SpringMVC中出现的线程安全问题分析

    (ps:前几个星期发生的事情)之前同事跟我说不要使用@Autowired方式注入HttpServletRequest(ps:我们的代码之前用的是第2种方式)。同...

    用户2032165
  • 波音推出的太阳能自动驾驶飞机终于要启航了!

    昨天波音公司旗下极光飞行服务公司宣布了一项重大消息,它们推出的名为奥德修斯(Odysseus)的高空伪卫星要在2019年春天开始第一次飞行计划!

    镁客网
  • WCF的Binding模型之四:信道工厂(Channel Factory)

    由于信道管理器在客户端和服务端所起的不同作用,分为信道监听器和信道工厂。和服务端的信道监听其相比,处于客户端的信道工厂显得简单。从名称就可以看得出来,信道工厂的...

    蒋金楠
  • 【逻辑】什么是前端开发中的业务逻辑?

    业务逻辑?呵呵,许多前端新人很困惑这个话题。当他们在面试当中被问到“这个业务逻辑你是如何处理的”的时候,他们经常会不知如何回答。

    web前端教室
  • 逻辑代数

    mathor

扫码关注云+社区

领取腾讯云代金券