当前位置: 首页 > Web前端 > HTML

原来项目打包也有这样的技巧——说说TreeShaking机制

时间:2023-03-29 11:12:11 HTML

有梦想,有干货,微信搜索【大千世界】关注这位还在洗碗的洗碗智慧清晨。本文已收录到GitHubhttps://github.com/qq449245884/xiaozhi,里面有完整的测试站点、资料和我的一线厂商访谈系列文章。前言作为一名前端工程师,你或多或少听说过Webpack这个前端打包工具。为了让最终打包的文件不至于太大,Webpack做了很多努力,例如:使用CodeSplitting输出一个接一个的chunk,避免网页一次性加载一个大的JS包。不过,今天的文章不是讲CodeSplitting,而是讲一个更深入的原理:TreeShaking。什么是摇树?什么是摇树?TreeShaking直译为摇树。在Webpack的世界里,我们通常会设置一个EntryPoints来告诉Webpack从哪个文件开始打包其他文件。如果我们用Tree的概念,它就是很多分支上的骨干配置。DynamicLanguage&StaticLanguage接下来我会讲一个和TreeShaking无关的小知识,但是这个小想法可以帮助我们理解为什么在JavaScript上实现TreeShaking并不像我们想象的那么容易。接下来讲一个和TreeShaking相对无关的小知识,但是这个小概念可以帮助我们理解为什么TreeShaking是在JavaScript上实现的,在JavaScript中分为动态语言(DynamicLanguage)和静态语言(StaticLanguage)编程语言。,JavaScript,PHP,Python等比较常见的归类在动态语言中的语言并没有我们想象的那么容易。在编程语言中,有动态语言(DynamicLanguage)和静态语言(StaticLanguage)。JavaScript、PHP、Python等语言在动态语言中比较常见。至于静态语言中比较常见的语言有C++、Java等语言。在DynamicLanguage中,因为我们可以动态加载很多东西,比如function,object等等,对于TreeShaking来说就太难以捉摸了,这使得DynamicLanguage的TreeShaking非常困难。很难达到完美。死代码消除在开始讲TreeShaking的原理之前,必须了解一个技术:死代码消除(DeaCodeElimination)。在编译器领域,为了优化执行时间,编译器会在代码编译过程中删除不影响最终结果的代码,从而达到执行时间的优化。这个过程称为死代码消除。乍看之下,DeadCodeElimination所做的似乎就是TreeShaking要做的,也就是删除无用的代码,但两者之间还是有细微的差距。接下来说一下TreeShaking的原理。TreeShaking的原理TreeShaking实际上是一种新的DeadCodeElimination实现原理。上面DynamicLanguage的概念中提到的DynamicLanguage的特点就是可以动态加载任何东西,因为这个特点使得DeadCodeElimination相当难以实现,因为编译器永远不知道哪些代码不会影响最终结果。所以TreeShaking其实需要做的并不是像DeadCodeElimination那样死板的删除不会影响结果的代码,而是保留会用到的代码,这样也能达到类似DeadCodeElimination的效果效果,但是两者在原理上还是有一些区别的,这就是TreeShaking的原理。ES6modulev.scommonJS上面提到的TreeShaking原理主要是为了保留将要使用的代码,这在早期的JavaScript中其实是不可能的,但是在ES6诞生之后,有一个非常重要的概念叫做:ES6模块。由于ES6模块的诞生,我们可以在每个文件的最前面引用即将用到的东西,所以这些bunblers可以通过这些import文件快速知道哪些文件可以保留,进而达到TreeShaking的效果.这时,读者可能会有另一个问题。在ES6模块诞生之前,我们也可以使用commonJS来导入模块。为什么ES6模块可以做TreeShaking而commonJS不能?其实是因为ES6模块有很多特性,所以bundler可以对这些特性进行静态分析:模块必须在顶层引入。该模块自动定义为严格模式。模块名称不能动态更改。模块内容是不可变的,不能在其他文件中动态添加或删除。由于这些强限制,ES6模块可以启用bundler来达到TreeShaking的效果,但是commonJS无法做到这一点。完善导入导出方式我们都知道ES6模块的导出方式分为命名导出和默认导出。这两种方式适用于不同的使用场景,经过TreeShaking后的文件内容会有非常大的差异。defaultexportnamedexport乍看之下defaultexport和namedexport在写法上似乎没有太大区别(只是直接在project前面加export的方式不一样),最后就是需要使用一个对象来打包输出。但是两者经过TreeShaking后的结果却大相径庭,我们来看看TreeShaking后的结果吧!TreeShaking后默认导出的结果。上面两张图可以看到TreeShaking后namedexport的结果。虽然TreeShaking去掉了multiply的功能,但是defaultexport和namedexport相比还是有一些新的补充。处理函数参数的变量较少,不是完美的性能优化。因此,如果读者在开发的时候确定一个文件会需要同时导出很多项,无论是对象还是函数,建议此时使用具名的导出方式进行输出,以达到最佳性能优化。完善第三方组件的导入方式最后,我们来看看导入第三方组件的最佳方式。在前端开发的过程中,为了不重蹈覆辙,我们经常会使用大神开发的第三方组件来加快开发速度,但是第三方组件的导入方式其实会影响最终的bundle大小。接下来将使用antdesignUI库来进行说明。第一种是使用官方文档的描述来导入。其实antd本身就对其模块进行了TreeShaking的性能优化,所以原则上我们可以放心使用官方文档的教学来导入。接下来,我们使用webpack-bundle-analyzer进行文件分析。可以发现antd的文件大小高达842.15KB,其中有很多与Button无关的组件文件。这显然是一种糟糕的导入方法。没想到按照官方文档导入。没有办法达到最好的性能优化。但这其实不是antd的错。antd本身就有很好的treeshaking动作。详细说明可以参考antd的官方文档,但是这里的例子故意没有在项目的bundler配置文件中开启treeshaking功能,进而导致antd的TreeShaking失败。虽然bundler没有启用TreeShaking功能使整体bundle体积过大,但实际上我们可以手动完成。这时候只要我们改变单独从antd的es文件夹导入组件,最终的bundlesize可以相差很大,写法如下。然后我们也使用webpack-bundle-analyzer进行项目分析。可以发现整个antd的文件体积小了很多,只剩下74.8KB,其他与Button无关的组件也没有出现,所以同一个第三方组件的不同导入方式确实会影响整体性能差距非常大。这是导入第三方组件的更好方法。package.json中的sideEffects在Webpack的TreeShaking配置中。有一个副作用可以在package.json中配置。这个sideEffects的配置主要是让webpack等bundler知道这个项目是否可以进行TreeShaking动作。如果设置为false,则表示所有文件都可以进行TreeShaked。如果读者知道哪些文件不能进行TreeShaked,那么只要在sideEffects中用一个数组写出不能进行TreeShaked的文件路径即可。此时,bundler只会对这个数组之外的文件进行TreeShaking。Webpack中的UsedExports要在Webpack官方文件中实现TreeShaking的效果,除了在package.json中添加sideEffects外,还可以使用usedExports。官方文档中有这样的说法:如果sideEffects做的是去掉不能用于TreeShaking的分支,那么usedExports做的是去掉树枝上不用的叶子,所以usedExports实际上是在做真正的TreeShaking。useExports使用terser工具来检测项目的副作用。如果在打包过程中发现项目没有副作用,部分代码没有被引用,则在后续的uglify中将这些代码去掉,从而达到真正的TreeShaking效果。usedExports的设置方法也很简单,只要在webpack配置文件中的optimization中添加usedExports:true,即可开启usedExports的功能,写法如下:-端工程师,这个概念你可以不用懂。毕竟很多主流框架都已经先把bundler的相关配置写好了,但是了解这些工具在背后做了什么,也能对你的开发有帮助。有时候你可以想想如何改进你的代码,进而提高整体的打包性能。像上面提到的导入导出方式,在引用第三方组件时如何引用最小bundlesize,有了这些概念,在开发的时候就可以提升整体的性能,所以笔者也推荐目前正在学习web开发的读者们可以对TreeShaking的概念有一点了解。代码部署后,无法实时获知可能存在的BUG。事后为了解决这些bug,花费了大量的时间在日志调试上。顺便说一句,这里有一个有用的错误监控工具。资金错误。作者:AndyChen译者:前端小智来源:medium原文:https://medium.com/starbugs/%...每周更新交流文章,微信搜索“大千世界”即可阅读并第一时间提醒更多(比博客早一两篇),这篇文章的GitHubhttps://github.com/qq449245884/xiaozhi已经收录,整理了很多我的文档。欢迎明星和完美。面试复习可以参考考点,关注公众号,后台回复福利就可以看到福利,就知道了。