Webpack 中的高级特性
自从webpack4以后,官方帮我们集成了很多特性,比如在生产模式下代码压缩自动开启等,这篇文章我们一起来探讨一下webpack给我们提供的高级特性助力开发。
探索 webpack 的高级特性
特性:treeShaking
顾名思义treeShaking,就是摇树,那么体现在代码模块里面就是摇掉那些没有被外部成员引用的代码,指的注意的是在生产环境下treeShaking会自动开启。
treeShaking 初体验
比如我们在代码中引入lodash库,我们只用到了once方法,那关于lodash其他的功能模块,在生产环境下打包,并不会输出到bundle.js文件里面,比如我们在bundle.js里面去找lodash的一个方法debounce,他是完全可以找得到的。
delelopment 模式下打包的 bundle.js
production 模式下打包的 bundle.js
在这里你可能会说了production模式下会开启n多插件,处理打包结果,怎么就能说明是treeShaking做的呢,确实这种做法不能说明是treeShaking做的,我们可以把mode设置为none再试一下,不过这里需要我们手动去开启treeShaking,开启的方式如下。
none 模式下打包的 bundle.js
所以none模式下,打包的结果依然如此。
扩展
因为treeShaking是依赖于ESM的,如果项目中有配合使用babel-loader那么treeShaking是不是会失效呢?我们可以在配置文件里面添加babel-loader来辅以测试。
文件效果
我们可以看到没有使用的代码,依然是被移除掉了。
原因分析
因为babel-loader禁用了对ESM转化插件,所以经过babel-loader处理生成的依旧是ESM代码,如果你想使用代码转换功能,那你就需要像下面这样配置,只不过这样treeShaking就会失效了。
那么treeShaking失效了,应该怎么办?不要怕,即使失效了还会有其他插件提供了类似treeShaking功能,比如代码压缩。
特性: sideEffect
sideEffect表示的意思就是副作用,理解起来并不难,比如外部成员引用了当前模块,那么当前模块肯定是不会被treeShaking的,如果在当前模块里面写了冗余的代码,那么sideEffect就是去除这些冗余代码的,以达到更高的提效能力。
sideEffect 的基础实践
这里我们应该在webpack.config.js里面开启sideEffect,在package.json里面指定具有副作用的模块。
特性: CodeSplitting 分包策略
CodeSplitting分包策略旨在解决单入口打包导致bundle.js文件过大,从而导致浏览器http加载速度过慢造成页面短暂白屏情况,分包策略具有三种常见实施方式。
根据项目背景,多入口打包。
结合
ESM的Dynamic import特性,按需加载模块。对第三方包使用拆包策略。
多入口打包的具体实践
多入口打包体现在多页应用,每一个页面依赖于一个打包文件,对于模块中的公共代码进行提取到公共结果中。
比如在index.js、add.js里面抖音用到了once方法,webpack就会提取公共的lodash到单的文件里面,在两个页面里面会通过script引入。
Dynamic import 的按需加载实践
在选项卡切换场景下,在应用程序运行的过程中,只有当用户点击某个模块,才会对应去加载某个模块,大大的减少了启动时需要加载模块的体积,降低了浏览器网路的带宽的占用,提高了应用的响应率。
按需加载确实不需要在首屏的时候一次性把文件全部加载完毕,因为首屏并不需要所有模块,加载了也是浪费。
第三方包拆包策略
所谓三方包,在在多入口里面也提到过optimization.splitChunks只是一种提取三方包的方式,我们现在要讲的是插件层面的DllPlugin和DllReferencePlugin,这个插件的意义更为广阔一点,比如类似vue,react等三方包,配合着我们的项目代码,只需要初次构建一次,再次构建webpack就会跳过这些依赖包,只要我们不手动升级依赖包,那将会是永久性的缓存。
使用步骤
新建
webpck.dll.config.js文件,写上如下内容。
在 package.json 里面新增命令 =>
"dll": "webpack --config webpack.dll.config.js"并执行,生成文件。
引入文件的依赖关系
特性: 魔法注释
在分包或者定义其他模块的时候,我们想给模块定义一个名称,那就可以使用如下方式。
探索 webpack 带来的前端性能优化
在前几篇文章里面我们就知道了webpack通过mode来提供了none、development、production三种预设配置。每一种配置都会选择性的加载某些插件来优化项目的构建,但是作为一个开发者我们应当去关注非自动的功能配置,下面我们来一起探索一下在开发中使用到的配置能带来一定的性能优化。
为什么要进行性能优化
性能优化是前端开发的永久性话题,高性能应用的开发这是我们的目标,但是目标总就是目标,具体实施还是要一步一块板砖,webpack在实践如此多的新特性的同时,会给我们的打包结果带来具有影响的内容,比如sourceMap,上有政策下有对策,那么我们的种种可优化的点就是解决问题的对策。
具体对策
那么我们应该怎么样来提高构建速度与打包结果呢?实际的开发中你总会见到我们会对不同的环境配置不同的文件,根据env的不同来启用不同的配置。
DefinePlugin定义全局变量,可用作baseUrl。MiniCssExtractplugin用来从 js 代码中提取 css 代码。
optimizeCssAssetsWebpackPlugin,用来压缩css代码。webpack中所谓压缩就是压缩js文件的,而css文件,需要我们单独处理。
terser-webpack-plugin用于压缩js代码。如果在
optimization选项中开启了minimizer属性,则会覆盖掉webpack本身的压缩功能,所以我们需要手动添加压缩插件。
当然还有一些其他的配置呀,比如。
splitChunks的一些配置呀,也就是按你的需求拆包呀。
cdn的引入三方包呀。
多线程打包的开启呀,比如happyPack。happyPack的工作原理就是把loader加载分配多个线程去处理,最后在统一调度起来,处理完成之后通知webpack进行chunks的组合,输出bundle.js。 注意:并不是说多进程打包就一定好,因为创建多线程的时候也会有性能开销,所以还是斟酌而行。使用
include避免webpack处理不需要处理的模块文件,提高编译效率。webpack5 提供了 webpack 资源模块,来代替一般的
loader处理文件,好处是能够处理不同类型的文件并且不再需要针对性的配置loader。
resolve 模块一般被人们忘掉了,不过在 vue/react 的脚手架中还是看见过它的身影,一般用于告诉 webpack 以什么样的形式去处理文件,比如。
别名:
alias文件类型:
extensions解析的模块范围:
modules
写在最后
因为上面的一些优化手段涵盖了webpack5以及webpack5以前的特性,那么在这里提及一下webapck5中开箱即用的特性以及不再维护的老版本的特性吧。
持久化缓存,使用
cache之后我们便不需要使用dll拆包、cache-loader了,而且是webpack5中提供的功能。
thread-loader开启多线程打包,上述代码中提到了happypack,不过在webpack5当中,已经不再去维护happypack了,我们就应该使用thread-loader来加快构建进程。
总结
上述讲解的内容均是在开发环境下的的配置的一步步实现,当然在mode:"production"下webpack会自动帮我们做,所以在不依赖别人的情况下,还是自己配比较好玩。下一章我们就一起来探索一下各大成熟框架是怎么配置webpack的









评论