webpack 使用外部的库_吊打面试官系列之Webpack的Tree Shaking实战解密

天下武功,唯快不破!最新版的 antd 以及 vue 都对 Tree Shaking 提供了支持。我们内部的组件在支持这部分功能时,也专门梳理了相关的特性。这是四月份写的文章了,长时间不用就会忘,复习一下!

JS 文件绝大多数需要通过网络进行加载,然后执行。DCE(dead code elimination)可以使得加载文件的大小更小,整体执行时间更短。tree shaking 就是通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块语法的 静态结构 特性,例如 importexport

原理

ESM

  • import 只能作为模块顶层的语句出现
  • import 的模块名只能是字符串常量
  • import binding 是 immutable 的

这就是区别于CMJ,ESM 独有的静态分析特性。等等,那什么是静态分析呢,就是不执行代码。CMJ 中的 require,只有执行以后才知道引用的是什么模块。

保证了依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析。静态分析会在绘制依赖图时做DCE,减少打包体积。
ESM 也支持动态引入,类似于下面这种引入方式是不支持Tree Shacking的。

if (false) {
    
  import('./a.js').then(() => { // ...})
} else {
  // ...
}
// antd.js
var emptyObject = {};

if (true) {
  Object.freeze(emptyObject);
}
module.exports = emptyObject;

Dead Code

Dead Code 通常是指:

  • 代码不会被执行
  • 代码执行的结果不会被用到
  • 代码只会影响死变量(只写不读)
// 导入并赋值给 JavaScript 对象,但在接下来的代码里没有用到
// 这就会被当做“死”代码,会被 tree-shaking
import Stuff from './stuff';
doSomething();


// 导入但没有赋值给 JavaScript 对象,也没有在代码里用到
// 这会被当做“死”代码,会被 tree-shaking
import './stuff';
doSomething();

// 全部导入 (不支持 tree-shaking)
import _ from 'lodash';
// 具名导入(支持 tree-shaking)
import { debounce } from 'lodash';
// 直接导入具体的模块 (支持 tree-shaking)
import debounce from 'lodash/lib/debounce';
// 导入并赋值给 JavaScript 对象,然后在下面的代码中被用到
// 这会被看作“活”代码,不会做 tree-shaking
import Stuff from './stuff';
doSomething(Stuff);

// 导入整个库,但是没有赋值给 JavaScript 对象,也没有在代码里用到
// 非常奇怪,这竟然被当做“活”代码,因为 Webpack 对库的导入和本地代码导入的处理方式不同。
import 'my-lib';
export { default as Title } from './Title';
export { default as Options } from './Options';
export { default as AddonArea } from './AddonArea';
export { default as Answer } from './AddonArea/Answer';
export { default as Analysis } from './AddonArea/Analysis';
export { default as OriginalText } from './AddonArea/OriginalText';
export { default as Labels } from './AddonArea/Labels';

这样的文件结构是无法进行 tree-shaking 的, 因为没有 import?!

自执行的模块 import
自执行模块我们通常会使用 import 'xxx' 来进行模块引用,而不进行显式的调用。因此模块本身就有副作用。

import 'utils/refresh'

对于这种模块可以这样处理:

  • 在 sideEffects 中通过数组声明,使其在 Tree Shaking 的范围之外
  • 模块改造,暴露成员支持显式调用

unused harmony export
如果该模块被标识为 unused harmony export,则说明没有外部引用使用到该成员,webpack 认为是可以安全去除的。harmony export
部分被标识为 harmony export 的模块也会被去除。这个是跟 UglifyJS 的机制有关系。没有提供导出成员的模块

// ./src/modules/edu-discount/seckill/index.ts

import * as SeckillTypes from './types';
export { SeckillTypes };

对于只有暴露的成员,但是没有被引用的成员,这种模块会被直接删除。

  • [x] exports provided
  • [ ] exports used

配置

babel的配置文件

{
    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值