We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
1. lodash在webpack上的各种优化尝试
想象一个场景,两个前端项目组 A 和 B 同时上线2个项目,比如 A 上线的项目叫做”牛云聊“,B 上线的项目叫做”牛外卖“。结果上线当天,A 只用了1个小时实现打包上线,而 B 却用了一天时间打包上线。这时候我们可以想象一下B项目经理脸上的表情。
实际上,在上线前我们是需要对webpack打包进行一定优化的,那么我们该从哪些方向来进行优化呢?请继续往下看。
如果你们项目组正在使用 webpack4.x 的版本,那你应该或多或少了解到 4.x 版本的webpack在生产环境下会对代码做自动的tree shaking。但是,可能当你读完这篇文章你的Tree-Shaking并没什么卵用之后,你会有不一样的看法,你的Tree-Shaking不一定真的有用!
总结一下tree-shaking的原理就是:
我们都知道,函数式编程的副作用就是,一个函数可能会对函数外部的变量产生影响,而这个影响就是函数的副作用。举个例子吧:
function goBack() { window.location.href = '/home'; }
可以看到,goBack()修改了全局变量,结果时为了让浏览器进行跳转,而修改全局变量的这个行为就可能会引发一些副作用。 所以,针对这个问题,国内外各路大神提出了很多解决办法,比如说Webpack 中的 sideEffects 到底该怎么用?;"sideEffects": false没有使打包后的bundle减少
比如说,一个项目中有个lib目录下放着自己编写的函数,分析之后发现它被重复打包到了业务代码的js文件中。这种情况该如何优化呢?
splitChunks: { chunks: 'all', automaticNameDelimiter: '.', name: undefined, cacheGroups: { default: false, vendors: false, common: { test: function (module, chunks) { // 这里通过配置规则只将 common lib moment公共依赖打包进入common中 if (/src\/common\//.test(module.context) || /src\/lib/.test(module.context) || /cube-ui/.test(module.context) || /better-scroll/.test(module.context)) { return true; } }, chunks: 'all', name: 'common', // 这里的minchunks 非常重要,控制moment使用的组件被超过几个chunk引用之后才打包进入common中,否则不打包进去 minChunks: 2, priority: 20 }, vendor: { chunks: 'all', test: (module, chunks) => { // 将node_modules 目录下的依赖统一打包进入vendor中 if (/node_modules/.test(module.context)) { return true; } }, name: 'vendor', minChunks: 2, // 配置chunk的打包优先级,这里的数值决定了node_modules下的 moment不会被打包到 vendor 中 priority: 10, enforce: true } } }
为了避免影响打包速度,在项目代码中就是不要将使用频率低,体积大的组件引入到这个文件中。类似于datepicker这种大型的组件,就在对应需要使用的页面中引入即可。然后再webpack配置中,通过设置minChunk来指定当这些较大的组件引用超过多少次之后才能打包到common中,否则就单独打包到对应页面的js中。
因此,优化对于第三方依赖组件的加载方式,以减少不必要的加载和执行时间的损耗。
webpack4.x会根据以下条件自动分割代码块:
splitChunks: { // 默认:用于异步chunk,值为all // initial模式下会分开优化打包异步和非异步模块。all会把异步和非异步模块同时进行优化,也就是意味着module1在index1中 // 异步引入,index2中同步引入,initial下module1会出现在两个打包块中,而all只会出现一个。 // all所有chunk代码(同步加载和异步加载模块都可以使用)的公共部分分离出来成为一个单独的文件 // async将异步模块代码公共部分抽离出来成为一个单独的文件 chunks: async, minSize: 30000, // 默认值是30kb,当文件体积>=minSize时将会被拆分为2个文件,否则不生成新的chunk minChunks: 1, // 共享该module的最小chunk数(当>=minChunks时才会被拆分为新的chunk) maxAsyncRequests: 5, // 最多有5个异步加载请求该module maxInitialRequests: 3, // 初始会话时最多有3个请求该module automaticNameDelimiter: '~', // 名字中间的间隔符 name: true, // 打包后的名称,如果设置为true默认时chunk的名字通过分隔符(默认时~)分隔开,如vendor~也可以自己手动 // 指定。 cacheGroups: { // 设置缓存组用来抽取满足不同规则的chunk,切割成的每一个新的chunk就是一个cache group common: { name: 'common', // 抽取的chunk名字 chunks: 'all', // 同外层的参数配置,覆盖外层的chunks,以chunk为维度进行抽取 // 1. 可以为字符串,正则表达式,函数,以module为维度进行抽取; // 2. 只要是满足条件的module都会被抽取到该common的chunk下,为函数的第一个参数; // 3. 遍历到的每一个模块,第二个参数是每一个引用到该模块的chunks数组 test(module, chunks) { // module.context: 当前文件模块所属的目录,该目录下包含多个文件 // module.resource: 当前模块文件的绝对路径 if (/datepicker/.test(module.context)) { let chunkName = ''; // 引用该chunk的模块名字 chunks.forEach(item => { chunkName += item.name + ','; }); console.log(`module-datePicker`, module.context, chunkName, chunks.length); } }, // 优先级,一个chunk很可能满足多个缓存组,会被抽取到优先级高的缓存组中,数值高的优先被选择 priority: 10, minChunks: 2, // 最少被几个chunk引用 reuseExistingChunk: true, // 如果该chunk中引用了已经被抽取的chunk,直接引用该chunk,不会重复打包代码(当module未 // 发生变化时是否使用之前的mudule) enforce: true, // 如果cacheGroup中没有设置minSize,据此判断是否使用上层的minSize,当为true时则使用0;为false时则使 // 用上层的minSize }, }, },
这种情况一般会因为检查遗漏导致引入。举个例子:最开始写代码的时候,由于业务上的需要,导致要引入datepicker,但是设计突然更改了原型图,不需要选择日期了,这时候你注释掉了js里面对日期的各种操作,但是却遗漏了在import部分的引入。在webpack打包的时候,仍然会将datepicker打进去。
好的一点是,现在大部分的编辑器都会将这种不需要的引入进行提示,一般是颜色变灰。
lodash这个js库是我们日常开发中非常依赖的一个前端库,非常好用,但是好用的同时也存在一定的缺陷,就是全量引入后打包的体积较大。那我们能不能按需引入lodash呢?
答案是肯定的。我们可以在npm库上搜索lodash-es这个模块,通过阅读它的文档,我们可以将lodash导出为es6 modules,然后就可以通过import的方式单独导入某个函数来使用。
到底有没有必要优化lodash,其实这个存在一定的争议,可以参考lodash在webpack中的各项优化的尝试。其实优化就是根据自身的业务需求做出各种权衡后的妥协。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
参考文章
1. lodash在webpack上的各种优化尝试
前言
想象一个场景,两个前端项目组 A 和 B 同时上线2个项目,比如 A 上线的项目叫做”牛云聊“,B 上线的项目叫做”牛外卖“。结果上线当天,A 只用了1个小时实现打包上线,而 B 却用了一天时间打包上线。这时候我们可以想象一下B项目经理脸上的表情。
实际上,在上线前我们是需要对webpack打包进行一定优化的,那么我们该从哪些方向来进行优化呢?请继续往下看。
如果你们项目组正在使用 webpack4.x 的版本,那你应该或多或少了解到 4.x 版本的webpack在生产环境下会对代码做自动的tree shaking。但是,可能当你读完这篇文章你的Tree-Shaking并没什么卵用之后,你会有不一样的看法,你的Tree-Shaking不一定真的有用!
Tree-Shaking的原理
总结一下tree-shaking的原理就是:
更多的原理请参考:Tree-Shaking性能优化实践-百度外卖大前端
那为什么说tree shaking不一定真的有用呢?这都是函数副作用引起的。
函数副作用
我们都知道,函数式编程的副作用就是,一个函数可能会对函数外部的变量产生影响,而这个影响就是函数的副作用。举个例子吧:
可以看到,goBack()修改了全局变量,结果时为了让浏览器进行跳转,而修改全局变量的这个行为就可能会引发一些副作用。
所以,针对这个问题,国内外各路大神提出了很多解决办法,比如说Webpack 中的 sideEffects 到底该怎么用?;"sideEffects": false没有使打包后的bundle减少
1. 优化代码重复打包
比如说,一个项目中有个lib目录下放着自己编写的函数,分析之后发现它被重复打包到了业务代码的js文件中。这种情况该如何优化呢?
那拆包该如何在webpack中配置呢?
为了避免影响打包速度,在项目代码中就是不要将使用频率低,体积大的组件引入到这个文件中。类似于datepicker这种大型的组件,就在对应需要使用的页面中引入即可。然后再webpack配置中,通过设置minChunk来指定当这些较大的组件引用超过多少次之后才能打包到common中,否则就单独打包到对应页面的js中。
因此,优化对于第三方依赖组件的加载方式,以减少不必要的加载和执行时间的损耗。
splitChunks详解
webpack4.x会根据以下条件自动分割代码块:
2. 尽可能的去掉非必要的import
这种情况一般会因为检查遗漏导致引入。举个例子:最开始写代码的时候,由于业务上的需要,导致要引入datepicker,但是设计突然更改了原型图,不需要选择日期了,这时候你注释掉了js里面对日期的各种操作,但是却遗漏了在import部分的引入。在webpack打包的时候,仍然会将datepicker打进去。
好的一点是,现在大部分的编辑器都会将这种不需要的引入进行提示,一般是颜色变灰。
3. lodash优化
lodash这个js库是我们日常开发中非常依赖的一个前端库,非常好用,但是好用的同时也存在一定的缺陷,就是全量引入后打包的体积较大。那我们能不能按需引入lodash呢?
答案是肯定的。我们可以在npm库上搜索lodash-es这个模块,通过阅读它的文档,我们可以将lodash导出为es6 modules,然后就可以通过import的方式单独导入某个函数来使用。
到底有没有必要优化lodash,其实这个存在一定的争议,可以参考lodash在webpack中的各项优化的尝试。其实优化就是根据自身的业务需求做出各种权衡后的妥协。
The text was updated successfully, but these errors were encountered: