接续前篇多页应用改造,优化改造后的项目打包效果。

效果对比

阶段磁盘占用空间打包时间备注
原始9.9M-5.20版
架构改造(SPA->MPA)7.1M-5.27版
样式整合7.0M-5.30版
公共组件&工具类整合6.9M-6.4版
图片压缩6.0M20.767s-
UglifyJs5.9M23.391s-
合并小文件5.3M55.469s-
代码分割splitChunks5.1M73.730s-
gzip6.3M89.204s-

优化前

优化后

优化过程

压缩图片

chainWebpack: config => {  config.module    .rule("image-webpack-loader")    .test(/\.(gif|png|jpe?g|svg)$/i)    .use("file-loader")    .loader("image-webpack-loader")    .tap(() => ({      disable: process.env.NODE_ENV !== "production"    }))    .end()};

添加UglifyJs,移除console

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')configureWebpack: config => {    if (process.env.NODE_ENV === 'production') {      const plugins = []      plugins.push(        new UglifyJsPlugin({          uglifyOptions: {            compress: {              drop_console: true,              drop_debugger: true            }          },          cache: true, // 启用文件缓存          parallel: true // 使用多进程并行运行来提高构建速度          // sourceMap: false // 映射错误信息到模块        })      )      config.plugins = [        ...config.plugins,        ...plugins      ]    }  }

动态导入合并小文件webpackChunkName

原来打包出来的文件,快上百个了,还有好些0.29KB的,需要合并下。此处使用webpackChunkName

首先按照业务含义合并,以service为例

import Vue from 'vue'import Router from 'vue-router'Vue.use(Router)const routes = [  {    path: '/service',    component: () => import(/* webpackChunkName: "service-index" */ '@service/components/page-layout/TwoColLayout.vue'),    redirect: { name: 'Detail' },    children: [      {        path: 'detail',        name: 'Detail',        component: () => import(/* webpackChunkName: "service-index" */ '@service/views/detail/index.vue')      },      /**       * 接口申请(指标)       */      {        path: 'api-apply',        name: 'ApiApply',        component: () => import(/* webpackChunkName: "service-api-apply" */ '@service/views/detail/views/apply-api/index.vue')      },      {        path: 'api-apply-form',        name: 'ApiApplyForm',        component: () => import(/* webpackChunkName: "service-api-apply" */ '@service/views/detail/views/apply-api/api-apply-form.vue')      },      /**       * 接口管理       */      {        path: 'manage',        name: 'Manage',        component: () => import(/* webpackChunkName: "service-manage" */ '@service/views/manage/index.vue')      },      { // 接口管理 - 新建/修改        path: 'manage/upsert',        name: 'ManageUpsert',        component: () => import(/* webpackChunkName: "service-manage" */ '@service/views/manage/module/upsert/index.vue')      }]  },  {    path: '*',    redirect: '/service'  }]const router = new Router({ mode: 'history', routes })export default router


看起来都比较小,太小的独立文件单占连接数不是很合适。那就service-manage保留(业务上此处只有管理员能访问的管理页会调用,一般人看不到,不用和其他逻辑一起加载,还是保持独立),
其他的再统一合并成service-main。这里合并的宗旨是文件不超过250K。

...
此处省略处理各个产品打包合并过程。

代码分割splitChunks


从打包目录看,chunk-vendors-xxx.js已达1.7M,需要拆分。

参考文章: 一步一步的了解webpack4的splitChunk插件

这里根据实际情况优化,具体大家可通过vue-cli-service build --report生成 report.html分析包内容

首先拆出公用的element-ui

  configureWebpack: config => {    if (IS_PROD) {      config.optimization = {        splitChunks: {          cacheGroups: {            element: {              name: 'vendors-element-ui',              test: /[\\/]node_modules[\\/]element-ui[\\/]/,              chunks: 'initial',              reuseExistingChunk: true,              enforce: true,              priority: 3            },          }        }      }    }  }

然后把所有node_modlues下的引用合并到vendors

...cacheGroups: {        vendors: {          name: 'vendors',          test: /[\\/]node_modules[\\/]/,          chunks: 'all',          priority: 2        }}...

再将所有模块中被不同的 chunk 引入超过 1 次的抽取为 common

...cacheGroups: {        common: {          name: 'common',          chunks: 'initial',          minChunks: 2,          maxInitialRequests: 5,          priority: 1        }}...

启用gzip

const CompressionWebpackPlugin = require('compression-webpack-plugin')  configureWebpack: config => {    if (IS_PROD) {      const plugins = []      plugins.push(        new CompressionWebpackPlugin({          filename: '[path].gz[query]',          algorithm: 'gzip',          test: /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i,          threshold: 10240,          minRatio: 0.8        })      )      config.plugins = [        ...config.plugins,        ...plugins      ]    }  }

css根据入口文件打包


到这里,打包出来的css文件都很小,单独放到一个资源文件去请求挺浪费连接数的,所以尝试合并css。

参考:Extracting CSS based on entry

目前暂未成功,可能与上述webpackChunkName方式冲突,合并后的css正常,但根据webpackChunkName之后的css依旧会打包出来,暂时没找到更好的解决办法。待更新~

警告处理

[mini-css-extract-plugin] Conflicting

参考issue reported on Github

两种解决方法:

  1. 调整import顺序
  2. 配置忽略警告

选用方法1解决。