关于前端:原来项目打包也有这么技巧-浅谈-Tree-Shaking-机制

48次阅读

共计 4745 个字符,预计需要花费 12 分钟才能阅读完成。

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

前言

身为一位前端工程师或多或少都有听过 Webpack 这套前端打包工具吧,为了让最终打包的档案不会过于宏大,Webpack 可是下了十分多的苦功,例如:利用 Code Splitting 产出一个又一个的 chunk 让网页不会一次载入一份很大 JS 包。

然而明天的文章其实不是要讲 Code Splitting,而是要讲一个比拟深刻的原理:Tree Shaking。

什么是 Tree Shaking?

什么是 Tree Shaking?Tree Shaking 就字面上翻译来看就是摇摆树木,在 Webpack 的世界中咱们通常都会设定一个 Entry Points 来通知 webpack 要从哪个文件开始往其余文件进行打包,如果用 Tree 的概念来看就是一个骨干配上很多的树枝。

Dynamic Language & Static Language

接下来讲个跟 Tree Shaking 比拟无关的小常识,但这个小观点能够帮忙咱们理解为何要在 JavaScript 上执行 Tree Shaking 并不是咱们想像中的那麽容易。

接下来讲个跟 Tree Shaking 比拟无关的小常识,但这个小观点能够帮忙咱们理解为何要在 JavaScript 上执行 Tree Shaking 并在程式语言中有分为 动静语言(Dynamic Language) 以及 动态语言(Static Language),被归类在 Dynamic Language 中比拟常见的有 JavaScript、PHP、Python 等语不是咱们想像中的那么容易。

在编程语言中有分为 动静语言 (Dynamic Language) 以及 动态语言(Static Language),被归类在 Dynamic Language 中比拟常见的有 JavaScript、PHP、Python 等语言,至于被归类在 Static Language 比拟常见的有 C++、Java 等语言。

在 Dynamic Language 中因为咱们能够动静的载入十分多货色,例如 function、object 等,对于 Tree Shaking 来说这种会动静载入的货色切实是太难捉摸了,这也让 Dynamic Language 的 Tree Shaking 很难达到最完满。

Dead Code Elimination

在开始讲 Tree Shaking 原理之前必须要理解一个技术:死码删除(Dea 诶 Code Elimination)。

compiler 的畛域中,为了达到执行工夫的优化,在代码编译的过程中 compiler 会将对于最终后果没有影响到的代码删除,进而达到执行工夫的优化,这段过程称之为 Dead Code Elimination

乍看之下 Dead Code Elimination 在做的事件如同就是 Tree Shaking 要做到的事件,就是要删除无用的代码,但两者其实还是有著些微的差距,接下来就要讲讲 Tree Shaking 的原理。

Tree Shaking 原理

Tree Shaking 其实是 Dead Code Elimination 的一种新的实现原理,在下面的 Dynamic Language 的观点中提到 Dynamic Language 的个性就是能够动静载入任何货色,因为这个个性让 Dead Code Elimination 相当难实现,因为 complier 永远不晓得到底哪些程代码是对最终后果不会有影响的。

所以 Tree Shaking 其实要做到的不会像 Dead Code Elimination 那样死板板的要删除对后果不会有影响的程式码,而是要保留会须要用到的代码,这样也能够达到相似 Dead Code Elimination 的成果,只是两者的原理还是有一些差别,而这就是 Tree Shaking 的原理。

ES6 module v.s commonJS

下面提到 Tree Shaking 的原理最次要的目标就是要保留会须要用到的代码,而这点在晚期的 JavaScript 其实是无奈实现的,然而在 ES6 诞生后有一个十分重要的概念叫:ES6 modules

因为 ES6 modules 的诞生,咱们能够在每个文件的最上方先援用行将会须要用到的货色,所以这些 bunbler 就能够藉由这些 import file 很疾速的晓得能够保留哪些文件,进而达到 Tree Shaking 的成果。

这时候读者可能会有另一个问题了,在 ES6 module 还没诞生以前咱们也能够利用 commonJS 来进行 module 的导入,为什麽 ES6 module 能够做到 Tree Shaking 可是 commonJS 无奈呢?

其实是因为 ES6 module 有著十分多的个性,让 bundler 能够针对这些个性来进行动态的剖析:

  • module 必须要在顶层被 import。
  • module 外部会主动被定义为 strict mode。
  • module name 不能动静扭转。
  • module 内容为 immutable 无奈在其余文件中被动静新增或删除内容。

因为这些强限度在,所以 ES6 module 就能够让 bundler 做到 Tree Shaking 的成果,而 commonJS 则无奈达到此点。

改善 import 与 export 形式

咱们都晓得 ES6 modules 的 export 形式有分 named export 以及 default export,这两种办法实用于不同的应用场景,也会对 Tree Shaking 后的文件内容有著十分大的差异。

default export

named export

乍看之下 default export named export 在写法上如同没什麽太大的差异(除了间接在我的项目后面加上 export 的写法比拟不一样外),最终都是须要用一个物件来包装输入,但两者在 Tree Shaking 后的后果可是有著蛮大的差异,接下来就看来一下 Tree Shaking 过后的后果吧!

default export 经由 Tree Shaking 后的后果

named export 经由 Tree Shaking 后的后果

能够看到下面两张图,尽管 Tree Shaking 都有把 multiply 这个 function 移除了,可是 default export 相较于 named export 还是新增了不少变量来解决 function parameter,这样就不是一个完满的性能优化。

所以如果读者在开发时确定一个文件会须要同时输入很多我的项目,不论是对象也好函数也罢,这时候都倡议用 named export 的形式进行输入这样能力达到最好的性能优化。

改善第三方组件的 import 形式

最初再来看一下 import 第三方组件的最佳形式,在前端开发的过程中为了不要反复照轮子很多时候都会应用大神所开发好的第三方组件来减速开发,但第三方组件的 import 形式其实也会影响到最终的 bundle size

接下将以 ant design 这套 UI library 来进行阐明。

首先是利用官网文档的阐明来进行 import,其实 antd 自身就有针对其 module 进行 Tree Shaking 的性能优化,所以咱们原则上是能够释怀的应用官网文档的教学进行 import 的,接下来咱们利用 webpack-bundle-analyzer 来进行档案剖析。

能够发现 antd 的文件大小高达 842.15KB,而且裡面还跑出了许多跟 Button 无关的 component 文件,这显然是一个不好的 import 形式,没想到照著官文档的形式进行 import 也没方法达到最好的性能优化。

但这其实也不是 antd 的错,antd 自身就有做好 Tree Shaking 的动作,具体的阐明能够参考 antd 的官网文件,然而这边的事例成心没有在我的项目的 bundler 设定档中开启 Tree Shaking 的性能,进而导致 antd 的 Tree Shaking 生效。

尽管 bundler 没有开启 Tree Shaking 性能让整体的 bundle size 过大,但咱们其实也能够本人手动做这件事,这时候只有咱们改成从 antd 的 es folder 进行元件的独自 import 就能够让最终的 bundle size 差十分多,写法如下。

接著咱们一样应用 webpack-bundle-analyzer 来进行项目分析。

能够发现整个 antd 的文件大小少了十分多,只剩下 74.8KB 而且与 Button 无关的其余 component 都没呈现了,所以同一种第三方组件不同的 import 形式真的会让整体的性能差距十分大,这个就是比拟好的第三方组件 import 形式。

package.json 中的 sideEffects

在 Webpack 的 Tree Shaking 配置中,有一个能够在 package.json 中配置的叫 sideEffects,这个 sideEffects 的配置次要是让 Webpack 这种 bundler 晓得此我的项目是否能够做 Tree Shaking 的动作。

如果设定为 false 就代表能够将所有的文件进行 Tree Shaking,若读者晓得有哪些档案是不能做 Tree Shaking 的,这时候只有在 sideEffects 内用一个数组将不能做 Tree Shaking 的文件门路写上去,这时候 bundler 就只会针对这个数组以外的文件进行 Tree Shaking。

Webpack 中的 usedExports

在 Webpack 的官网文件中要达到 Tree Shaking 的成果除了在 package.json 中加上 sideEffects 外,还能够应用 usedExports

在官网文件中有這麼一段說明:

如果说 sideEffects 在做的事件是把不能做 Tree Shaking 的树枝移除,那 usedExports 在做的事件就是把树枝上没有用到的树叶移除,所以 usedExports 其实才是在做真正的 Tree Shaking。

useExports 利用 terser 这套工具进行我的项目的 side effects 侦测,如果打包过程中发现此弎既没有 side effects 且某些代码又没有被援用到,则该代码就会在之后的 uglify 被移除,藉此达到真正的 Tree Shaking 成果。

而 usedExports 的设定形式也非常简单,只有在 Webpack 的配置文件中,在 optimization 内加上 usedExports: true 这时候就能够将 usedExports 的性能关上,写法如下:

小結

明天介绍了 Tree Shaking 的相干根本观点,尽管说身为一位前端工程师不肯定要懂这个概念,毕竟当初很多支流的框架都曾经先把 bundler 的相干 config 都写好了,但理解这些工具背地在做的事件也能帮忙到本人在开发时能够略微省思一下要如何改进本人的代码,进而晋升整体的打包后的性能。

像是下面提到的 importexport 形式,援用第三方组件时能够如何援用达到最小的 bundle size,有了这些概念在开发时就能够晋升整体的性能,所以笔者也倡议目前正在学习网页开发的读者都能够略微理解一下 Tree Shaking 的概念喔


代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

作者:Andy Chen 译者:前端小智 起源:medium

原文:https://medium.com/starbugs/%…

交换

文章每周继续更新,能够微信搜寻「大迁世界」第一工夫浏览和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 曾经收录,整顿了很多我的文档,欢送 Star 和欠缺,大家面试能够参照考点温习,另外关注公众号,后盾回复 福利,即可看到福利,你懂的。

正文完
 0