原因是 webpack Tree Shaking 的实现原理 中提到的, 由于ddddddddd is declared but its value is never read.被 ts-loader 给删除了,我们篡改下 ts-loader 的代码,使得它保留 import { ddddddddd } from "./ddd" 这行代码
// react-app-polyfill/ie11
'use strict';
if (typeof Promise === 'undefined') {
// Rejection tracking prevents a common issue where React gets into an
// inconsistent state due to an error, but it gets swallowed by a Promise,
// and the user has no idea what causes React's erratic future behavior.
require('promise/lib/rejection-tracking').enable();
self.Promise = require('promise/lib/es6-extensions.js');
}
// Make sure we're in a Browser-like environment before importing polyfills
// This prevents `fetch()` from being imported in a Node test environment
if (typeof window !== 'undefined') {
// fetch() polyfill for making API calls.
require('whatwg-fetch');
}
// Object.assign() is commonly used with React.
// It will use the native implementation if it's present and isn't buggy.
Object.assign = require('object-assign');
// Support for...of (a commonly used syntax feature that requires Symbols)
require('core-js/features/symbol');
// Support iterable spread (...Set, ...Map)
require('core-js/features/array/from');
例子 🌰
下面以一个业务项目为例, 我们添加了若干文件来验证测试
src/views/act-choose-goods/index.ts
aaa.ts
与ddd.ts
都会被删除aaa.ts
还存在,只有ddd.ts
被删除了,那么 webpack 为什么没有删除aaa.ts
?原因是 webpack Tree Shaking 的实现原理 中提到的, 由于
ddddddddd is declared but its value is never read.
被 ts-loader 给删除了,我们篡改下 ts-loader 的代码,使得它保留import { ddddddddd } from "./ddd"
这行代码现在我们发现打包后
ddd.ts
也被保留了下来...原因分析
为什么 webpack 没有删除未使用到的
aaa.ts
与ddd.ts
模块?原因是 webpack 无法确认
aaa.ts
与ddd.ts
是否有副作用。比如我们常在代码中这样去 import 一个 polyfill 来兼容低版本浏览器, 在这种情况下我们虽然没有使用 react-app-polyfill 的导出, 但是不能删除import 'react-app-polyfill/ie11'
这行代码因为
react-app-polyfill/ie11
直接修改了 window、Object 等全局对象, 这段代码有副作用, 即使没有用到其导出也应该被保留下来又比如当你没用 CSS Modules 时, 通常只需
import 'antd/dist/reset.css';
, 此时也不会用到 .css 模块的导出, 说明 .css 模块也有副作用不能轻易被删除对于这种情况, 我们可以在项目的
package.json
中可以通过 sideEffects 字段声明哪些文件是有副作用, 如下表示仅 *.css 模块有副作用当确认了 *.ts 没有副作用后, 再看一下结果发现
aaa.ts
与ddd.ts
最终被成功删除了实现原理
当我们没有在
package.json
中声明 sideEffects 字段时, 可以看到对于 aaa.ts 模块的 hasSideEffects 为 true, 即是有副作用的, 那么对于 .ts 模块的factoryMeta.sideEffectFree
的值都将为默认的 undefined 当我们声明 sideEffects 字段后, 那么某个模块的文件后缀会与 sideEffects 进行类似正则匹配, 对于 .ts 模块没有被 *.css 表达式匹配上则 hasSideEffects 为 false,factoryMeta.sideEffectFree
被赋值为 true即 sideEffects 字段决定
factoryMeta.sideEffectFree
的值, 而factoryMeta.sideEffectFree
的值将决定该模块是否被 Tree Shaking下面讲一下 HarmonyImportSideEffectDependency, 如上图 iteratorDependency 函数中当 ref 存在 && ref.module 也存在等条件成立时也会被添加到 blockInfoModules 中(可以认为没有添加到 blockInfoModules 中的模块是不会生成到打包后的代码中)。
那么最关键的因素就是
this._module.factoryMeta.sideEffectFree
的值, 如果值为 true, 那么 getDependencyReference 函数返回值为 null, ref 为 null 就结束了factoryMeta.sideEffectFree
的值其实我们上面已经讨论过了factoryMeta.sideEffectFree
的值为 undefined, 继续调用 super.getReference() 将会返回一个有值的 reffactoryMeta.sideEffectFree
的值为 true, ref 即为 null, 自此被引用了但未实际用到其导出的aaa.ts
、ddd.ts
、bbb.ts
等模块都不会添加到 blockInfoModules 中,即不会出现在打包后的文件中小结