3

前言

最近发现公司前端项目打包后生成的单个文件都超过4Mb了,导致页面打开的时候非常慢,于是着手优化打包,目标是实现单个文件大小低于1Mb。

准备

在优化之前我们先提出两个优化思路,如下所示:
1、使用CDN引入包文件
2、使用npm引入的第三方包文件进行拆包
3、将项目文件的公共部分进行拆包,如src/components和src/views文件夹

有了思路之后,接下来我们就开干。注意:下面我是用vue项目做为演示

使用CDN引入包文件

适用的场景:

公共的框架或者库单独引入,防止nodejs打包引入,如:vue.js、vuex、vue-router和elementui。

实现:

我们可以使用第三方CDN库复制链接放入public/index.html文件中,如下所示 :

image.png
image.png

虽然我们引入了,但是我们还要配置webpack不要把nodejs引入的包进行打包。

修改vue.config.js文件,如下所示:

configureWebpack: {
    name: name,
    externals: {
      // 包名: '引入名'
      vue: 'Vue',
      vuex: 'Vuex',
      'vue-router': 'VueRouter',
      'element-ui': 'Element',
      moment: 'moment',
      dayjs: 'dayjs',
      axios: 'axios',
      clipboard: 'ClipboardJS',
      echarts: 'echarts',
      html2canvas: 'html2canvas',
      'js-beautify': 'beautifier',
      'js-cookie': 'Cookies',
      lodash: '_',
      qrcode: 'QRCode',
      screenfull: 'screenfull',
      'vue-clipboard2': 'VueClipboard',
      'vue-i18n': 'VueI18n'
    }

上面externals中key是包名,value是引入名,大家按照这个参考设置就好。这样就完成了第1步的操作。

使用npm引入的第三方包文件进行拆包

接下来我们使用webpack-bundle-analyzer这个包来分析一下前端项目打包后的报告,分析文件大小情况,根据这个报告我们来判断是否要分包,如下所示。

修改vue.config.js文件

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

 configureWebpack: {
    name: name,
    externals: {
      // 包名: '引入名'
      vue: 'Vue',
      vuex: 'Vuex',
      'vue-router': 'VueRouter',
      'element-ui': 'Element',
      moment: 'moment',
      dayjs: 'dayjs',
      axios: 'axios',
      clipboard: 'ClipboardJS',
      echarts: 'echarts',
      html2canvas: 'html2canvas',
      'js-beautify': 'beautifier',
      'js-cookie': 'Cookies',
      lodash: '_',
      qrcode: 'QRCode',
      screenfull: 'screenfull',
      'vue-clipboard2': 'VueClipboard',
      'vue-i18n': 'VueI18n'
    },
    resolve: {
      alias: {
        '@': resolve('src'),
        '@@': resolve('src/x7')
      }
    }
    plugins: [
       new BundleAnalyzerPlugin()
     ]
}

修改package.json文件

"scripts": {
    "build:report": "vue-cli-service build --report"
},

运行命令:

pnpm run build:report

如下所示,当前文件打包情况:

image.png

image.png

通过分析可以知道,chunk文件和app文件比较大,我们再看下图表看看能不能把里面大的包拆分出来,如下所示:

image.png

通过图表可以看出来,这些包都可以拆分出来,于是我们改下vue.config.js把上面的包全部拆分出来,如下所示:

config.optimization.splitChunks({
              chunks: 'all',
              minSize: 20000,
              maxSize: 0,
              minChunks: 1,
              maxAsyncRequests: 30,
              maxInitialRequests: 30,
              automaticNameDelimiter: '\~',
              enforceSizeThreshold: 50000,
              cacheGroups: {
                libs: {
                  name: 'chunk-libs',
                  test: /[\\/]node_modules[\\/]/,
                  priority: 120,
                  chunks: 'initial' // only package third parties that are initially dependent
                },
                corejs: {
                  name: 'chunk-corejs', // split elementUI into a single package
                  priority: 141, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?core-js(.*)/ // in order to adapt to cnpm
                },
                graphic: {
                  name: 'chunk-zrender', // split elementUI into a single package
                  priority: 142, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?zrender(.*)/ // in order to adapt to cnpm
                },
                viewerjs: {
                  name: 'chunk-viewerjs', // split elementUI into a single package
                  priority: 143, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?viewerjs(.*)/ // in order to adapt to cnpm
                },
                hotFormulaParser: {
                  name: 'chunk-hotFormulaParser', // split elementUI into a single package
                  priority: 144, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?hot-formula-parser(.*)/ // in order to adapt to cnpm
                },
                elementUI: {
                  name: 'chunk-elementUI', // split elementUI into a single package
                  priority: 130, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
                },
                einUI: {
                  name: 'chunk-einUI', // split elementUI into a single package
                  priority: 125, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?ein-ui(.*)/ // in order to adapt to cnpm
                },
                echarts: {
                  name: 'chunk-echarts', // split elementUI into a single package
                  priority: 122, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?echarts(.*)/ // in order to adapt to cnpm
                },
                handsontable: {
                  name: 'chunk-handsontable', // split elementUI into a single package
                  priority: 123, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?handsontable(.*)/ // in order to adapt to cnpm
                },
                codemirror: {
                  name: 'chunk-codemirror',
                  test: /[\\/]node_modules[\\/]_?codemirror(.*)/, // in order to adapt to cnpm
                  minChunks: 1, //  minimum common number
                  priority: 140,
                  reuseExistingChunk: true
                }
              }
            })

我们把想要拆分的包都放到cacheGroups中,但是这里要注意一下如下的代码:

 libs: {
  name: 'chunk-libs',
  test: /[\\/]node_modules[\\/]/,
  priority: 120,
  chunks: 'initial' // only package third parties that are initially dependent
},
corejs: {
  name: 'chunk-corejs', // split elementUI into a single package
  priority: 141, // the weight needs to be larger than libs and app or it will be packaged into libs or app
  test: /[\\/]node_modules[\\/]_?core-js(.*)/ // in order to adapt to cnpm
},

这里的chunk-libs包含所有的node-Modules包,而chunk-corejsnode_modules其中的一个包,我们设置chunk-libspriority=120chunk-corejs=141这里的priority的意思是打包优先级,意思就是说,我们先打包chunk-corejs,然后再打包chunk-libs,这样就会把chunk-corejs单独从node_modules中提取出来单独打包,否则 如果我们设置priority大小相反,会出现chunk-corejs打包不生效问题,所以这里要注意一下打包优先级。

将项目文件的公共部分进行拆包,如src/components和src/views文件夹

通过上面的报告分析可知,还有一些如src/componentssrc/views里面的文件也非常大,如下所示:

image.png

所以我们也可以拆分,跟上面一样,代码如下所示:

commons: {
  name: 'chunk-commons',
  test: resolve('src/components'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 5,
  reuseExistingChunk: true
},
viewsSystem: {
  name: 'chunk-viewsSystem',
  test: resolve('src/views/system'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 6,
  reuseExistingChunk: true
},
viewsSalary: {
  name: 'chunk-viewsSalary',
  test: resolve('src/views/salary'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 24,
  reuseExistingChunk: true
},
viewsTool: {
  name: 'chunk-viewsTool',
  test: resolve('src/views/tool'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 25,
  reuseExistingChunk: true
},
viewsEvaluationCenter: {
  name: 'chunk-viewsEvaluationCenter',
  test: resolve('src/views/evaluationCenter'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 26,
  reuseExistingChunk: true
},
viewsPayroll: {
  name: 'chunk-viewsPayroll',
  test: resolve('src/views/payroll'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 27,
  reuseExistingChunk: true
},
viewsPayrollCenter: {
  name: 'chunk-viewsPayrollCenter',
  test: resolve('src/views/payrollCenter'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 28,
  reuseExistingChunk: true
},
viewsSupervise: {
  name: 'chunk-viewsSupervise',
  test: resolve('src/views/supervise'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 29,
  reuseExistingChunk: true
},
viewsJobSchedulingResources: {
  name: 'chunk-viewsJobSchedulingResources',
  test: resolve('src/views/jobScheduling/schedulingResources'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 7,
  reuseExistingChunk: true
},
viewsJobSchedulingTaskManage: {
  name: 'chunk-viewsJobSchedulingTaskManage',
  test: resolve('src/views/jobScheduling/taskManage'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 14,
  reuseExistingChunk: true
},
viewsJobSchedulingTaskScheduling: {
  name: 'chunk-viewsJobSchedulingTaskScheduling',
  test: resolve('src/views/jobScheduling/taskScheduling'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 20,
  reuseExistingChunk: true
},
viewsJobSchedulingQualityTaskCenter: {
  name: 'chunk-viewsJobSchedulingQualityTaskCenter',
  test: resolve('src/views/jobScheduling/qualityTaskCenter'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 21,
  reuseExistingChunk: true
},
viewsJobSchedulingTaskGen: {
  name: 'chunk-viewsJobSchedulingTaskGen',
  test: resolve('src/views/jobScheduling/taskGen'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 22,
  reuseExistingChunk: true
},
viewsJobSchedulingWorkManage: {
  name: 'chunk-viewsJobSchedulingWorkManage',
  test: resolve('src/views/jobScheduling/workManage'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 23,
  reuseExistingChunk: true
},
viewsAttendance: {
  name: 'chunk-viewsAttendance',
  test: resolve('src/views/attendance'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 8,
  reuseExistingChunk: true
},
viewsBase: {
  name: 'chunk-viewsBase',
  test: resolve('src/views/base'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 9,
  reuseExistingChunk: true
},
viewsBasicData: {
  name: 'chunk-viewsBasicData',
  test: resolve('src/views/basicData'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 10,
  reuseExistingChunk: true
},
viewsCitySvc: {
  name: 'chunk-viewsCitySvc',
  test: resolve('src/views/citysvc'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 11,
  reuseExistingChunk: true
},
viewsPlatformManage: {
  name: 'chunk-viewsPlatformManage',
  test: resolve('src/views/platformManage'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 12,
  reuseExistingChunk: true
},
viewsUc: {
  name: 'chunk-viewsUc',
  test: resolve('src/views/uc'), // can customize your rules
  minChunks: 1, //  minimum common number
  priority: 13,
  reuseExistingChunk: true
},

这样就完成了包的分割了,下面就是优化后执行的最终效果:

image.png

image.png

如果你觉得1Mb还是太大了,按照我上面的步骤继续拆包即可。

总结

1、在webpack的splitChunks配置中,priority属性用于确定当模块可能被多个缓存组匹配时,应该优先分配给哪个缓存组。

priority的值是一个数字,数字越大,优先级越高。例如,如果一个模块同时匹配了两个缓存组,一个的priority为10,另一个的priority为20,那么这个模块将被分配给priority为20的缓存组。

这个属性可以帮助你更精细地控制代码分割的行为。例如,你可能希望将所有的第三方模块分割到一个单独的块中,但是对于特定的重要模块,你希望将它们分割到自己的块中。在这种情况下,你可以为这些重要模块的缓存组设置一个更高的priority值。


Awbeci
3.1k 声望213 粉丝

Awbeci