Vue2+elementui项目的打包优化

1,448 阅读4分钟

优化前需要安装的两个分析工具

1. webpack-bundle-analyzer: 用于分析打包后包大小
2. speed-measure-webpack-plugin: 可以输出各个模块的编译时长,可以帮助我们更好的找到耗时较大的模块

vue脚手架的两个配置方式

1. configureWebpack: 修改已有的webpack配置,通过对象/函数的方式进行配置,方便快捷
2. chainWepack: 这是一种较为灵活的配置方式,可以对webpack配置进行修改,可以利用提供的api进行更加精细的颗粒度配置(api看得懂就行,可以联合inspect生成的配置进行搭配使用)

生成配置文件,提供参考学习

package.json:
"inspect": "vue inspect > webpack.config.production.js --mode production"
npm install inspect可以在根目录生成webpack.config.production.js

image.png 该配置中就有链式调用的相关代码

1-进入正题,使用webpack-bundle-analyzer和speed-measure-webpack-plugin
  1. 使用configWebpack 函数方式(对象更简单,这里只是我试用一下) ``
configureWebpack: config => {
    if (process.env.NODE_ENV == 'production') {
      config.plugins.push(
        // 依赖分析
        new BundleAnalyzerPlugin({
          analyzerPort: 8880 // 端口号
        }),
        new SpeedMeasurePlugin()
      )
    }
  }
-----也可以,但是不推荐,简单的添加插件,就直接放在configureWebpack-----
chainWebpack: config => {
  config
    .plugin('speed-measure-plugin')
      .use(new SpeedMeasurePlugin())
  config
    .plugin('webpack-bundle-analyzer')
      .use(new BundleAnalyzerPlugin({
        analyzerPort: 8880
      }))
}
  1. 按需加载Element

依赖npm install babel-plugin-component -D

babel.config.js

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

  1. 打包后的文件大小

image.png

2. 使用CDN
vue.config.js

const cdn = {
  externals: {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    axios: 'axios',
  },
  js: [
    'http://lib.baomitu.com/vue/2.6.14/vue.min.js',
    'http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js',
    'https://lib.baomitu.com/axios/1.3.4/axios.min.js'
  ]
}

productionSourceMap: false // 去掉map
configureWebpack: config => {
    config.externals = cdn.externals
}
// 颗粒度配置放在chainWebpack
chainWebpack: config => {
    // 注入变量,方便在html模板中使用
  config
    .plugin('html')
      .tap((args) => {
        args[0].mode = 'prod'
        args[0].cdn = cdn
        return args
      })
}

index.html
// 判断是否生产模式,也可以直接用process.env.NODE_ENV
<% if (htmlWebpackPlugin.options.mode === 'prod') { %>
  <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
  <% } %>
<% } %>

体积变小了,打包速度也更快了 image.png

注意:

  1. 线上项目不推荐使用公共CDN,因为不稳定,可以放在自家公司购买的cdn服务上
  2. 把资源拆除去用cdn加载,完全不走treeshaking
3. thread-loader 开启多线程优化

vuecli5的配置parallel:是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建,默认为false,以下是开启后的耗时

image.png

根据speed-measure-webpack-plugin的分析,可以针对某些耗时长的模块使用thread-loader

const oneOfsMap = config.module.rule('scss').oneOfs.store
oneOfsMap.forEach(item => {
item
  .use('thread-loader')
  .before('mini-css-extract-plugin')
  .loader('thread-loader')
  .options({
    workers: require('os').cpus().length - 1
  })
  .end()
})

image.png
根据图可以见,并不是一味加thread-loader就可以减少打包时间,因为开启多进程打包也是有消耗的,所以这个需要看自己的项目再决定使不使用,因为我这文件模块比较小,也就耗时2秒多,没什么必要开启,单纯做演示
这里是其他版本的vuecli配置方式,本文用的vuecli5

4. 使用缓存优化

cache-loader
hard-source-webpack-plugin
babel-loader的cacheDirectory标志
以上这些缓存方式都有首次启动时的开销,即它们会让 "冷启动" 时间会更长,但是二次启动能够节省很多时间. 而 vue-cli 已经内置了 cache-loaderbabel-loader 的 cacheDirectory 标志,其中对应的配置如下:(vue-cli5版本没发现内置cache-loader)

image.png
这里cache-loader hard-source-webpack-plugin 就不做演示了~因为项目不大,效果看不太出来

5. 去掉console,减少代码体积

webpack v5 开箱即带有最新版本的 terser-webpack-plugin,vuecli5就是基于webpack5的
也可以通过 uglifyjs-webpack-plugin 插件(webpack5不推荐使用,推荐用terser-webpack-plugin)来删除注释和压缩 js 代码

chainWebpack: config => {
  // 去除console
  config
    .optimization
      .minimizer('terser')
        .use(require('terser-webpack-plugin'), [{
          terserOptions: {
            compress: {
              drop_console: true
            },
            output: {
              comments: false
            }
          }
        }])
}
6. 图片压缩

所需依赖image-webpack-loader

chainWebpack: config => {
  // 压缩图片
  config
    .module
      .rule('images')
        .use('image-webpack-loader')
          .loader('image-webpack-loader')
          .options({
            mozjpeg: {
              progressive: true,
              quality: 65
            },
            optipng: {
              enabled: false
            },
            pngquant: {
              quality: [0.65, 0.90],
              speed: 4
            },
            gifsicle: {
              interlaced: false
            },
            webp: {
              quality: 75
            }
          })
}

7. gzip压缩

两种gzip压缩的方式:

1、打包的时候通过webpack配置生成对应的 .gz 文件,浏览器请求xx.js/css等文件时,服务器返回对应的xxx.js.gz文件;

2、浏览器请求xx.js文件时,服务器对xx.js文件进行gzip压缩后传输给浏览器。

这里介绍第二种 安装依赖compression-webpack-plugin
npm install compression-webpack-plugin --save-dev

const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: config => {
    config.plugins.push(
        new CompressionPlugin({
          algorithm: 'gzip', // 使用gzip压缩
          test: /\.js$|\.html$|\.css$/, // 匹配文件名
          filename: '[path].gz[query]', // 压缩后的文件名(保持原文件名,后缀加.gz)
          minRatio: 1, // 压缩率小于1才会压缩
          threshold: 10240, // 对超过10k的数据压缩
          deleteOriginalAssets: false, // 是否删除未压缩的源文件,谨慎设置,如果希望提供非gzip的资源,可不设置或者设置为false(比如删除打包后的gz后还可以加载到原始资源文件)
      })
    )
}

具体可以看本篇