webpack 现在依然不能自动支持 tree-shaking,来优化引入的包么?

2021-10-29 14:42:16 +08:00
 yazoox

https://www.jianshu.com/p/7994b1fc6dfe

读到一篇文章,提到了,webpack 如果想在引入一个包的时候,编译只引入的那部分代码,需要 babel 的支持。而且,只对自己的代码有效。如果是第三方的包,还不行,得写一个插件,实现转换。比如,

import { x } from 'module1';

转换成

import { x } from 'module1/a/bc';

要这么麻烦才能够实现 tree-shaking 啊!

当然这是 3 年前的文章了,现在的 webpack 也进化到了 5.0 的版本了吧?现在还是这样的么?

1184 次点击
所在节点    webpack
5 条回复
noe132
2021-10-29 15:05:31 +08:00
你这篇文章基本已经过时了。比如现在 webpack 用的不是 uglyfy plugin ,而是 terser plugin 。

只要你用到的库是 esm 而且 sideEffects: false ,tree shaking 就会正常工作。参考 material-ui ,代码结构就是这个文章所说的那种格式,不需要任何配置就支持 tree shaking 。

那种 babel 转换插件是 webpack 支持 tree shaking 之前存在的优化技巧,现在完全不需要这样的东西。

只有没有提供 esm 的库不支持 tree shaking ,比如 lodash 。这种情况你就必须手动 import 相应函数比如 'lodash/map',或者使用 babel-plugin-lodash ,更好的方法是使用 webpack alias 替换成 lodash-es 等支持 esm 的库。

推荐阅读最新版本的官方文档
https://webpack.js.org/guides/tree-shaking/
wszgrcy
2021-10-29 15:31:00 +08:00
楼上基本上都说了.然后我记得还有作用域提升,应该也算摇树的一种吧.
yyfearth
2021-10-29 15:59:00 +08:00
一楼说的很全了 像 lodash 这种 如果你不用 lodash-es 那就需要用 plugin
如果 package 提供了 esm 并且提供了 sideEffect flag 的话 就都可以自动 tree-shaking 了
而且 webpack5 连非纯 esm 的 bundle 都可以做一定的 tree-shaking 了

但是你用自己内部做的包 很可能就不能自动 tree-shaking (除非特别处理)
这也是我经历过抱怨和误解最多的时候
因为要支持 tree-shaking 必须提供 esm 和 sideEffect 的信息
很多人做内部的包很喜欢把所有的东西用 index 全部导出来 但是有不知道怎么声明 sideEffect
或者用 webpack 或者其他 bundle 打包成了一个文件 cjs/umd 或者 单个 esm (就是把所有文件合并后导出成一个 esm ) 结果都没办法 tree-shaking 导致整个包全部被 webpack 打包

作为 library 想支持 tree-shaking
1. package.json 要提供 module 或者 browser 的 esm 入口 或者 exports
2. 不打包成一个文件 最好只做 babel 或者 tsc 就够了 最多用 rollup 分组件打包
3. 声明 sideEffect false 或者 指定需要 sideEffect 的文件
在使用 library 的时候 webpack 需要用 mode: production 并且启动了 minimize 和 TerserPlugin 才能充分使用 tree-shaking

虽然现在 webpack 和 esm 已经出来很久了
但是浏览器和 nodejs 的支持还是不是很完美
这个只能自己花时间 或者培训团队了
yyfearth
2021-10-29 16:00:26 +08:00
@wszgrcy 我记得作用域提升 貌似不是为了 tree-shaking 而是为了 dedup
另外还有一个很强的功能就是 esm 的 concat 功能 不过和 tree-shaking 没有直接关系
wszgrcy
2021-10-29 16:43:49 +08:00
@yyfearth 对了我突然想到一个东西,但是不知道在哪里遇到过,就是打包为 fesm,也就是单文件 esm,然后如果里面有一个直接的语句,比如 console.log()这样,这句肯定没法被引用,然后再我的记忆中,这种语句如果设置无副作用的话应该是会被抛弃的(记忆中感觉遇到过一次),但是实际上并没有,不知道是不是我记错了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/811530

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX