Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

The Vue project is optimized from 2.5M to 200kb


May 31, 2021 Article blog


Table of contents


This article comes from the public number: Front-end development community, author: gun brother

A vue cli3.0 project was recently optimized, from package volume 2.5M to 272k with a speed increase of 2/3 Here's how to optimize:

A new vue.config.js needs to be created (this file name is fixed) in the same level of directory as package.json

BundleAnalyzer

Role: To display packaged graphical information, will open an html page to help themselves analyze which files are too large, can be optimized by needles, before online 注释掉

Install webpack-bundle-analyzer

  npm install webpack-bundle-analyzer --save-dev

at vue.config.js: Inside:

// 引入
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;


// 展示图形化信息
chainWebpack: config => {
  config
      .plugin('webpack-bundle-analyzer')
      .use(BundleAnalyzerPlugin)
}

Pull out css supports on-demand loading

Install mini-css-extract-plugin plug-in

 npm install mini-css-extract-plugin -D

Inside vue.config.js

chainWebpack: config => {
  let miniCssExtractPlugin = new MiniCssExtractPlugin({
    filename: 'assets/[name].[hash:8].css',
    chunkFilename: 'assets/[name].[hash:8].css'
  })
  config.plugin('extract-css').use(miniCssExtractPlugin)
}

Pictures load on demand

Install image-webpack-loader

 npm install image-webpack-loader -D

Inside vue.config.js

config.module.rule('images')
    .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
    .use('image-webpack-loader')
    .loader('image-webpack-loader')
    .options({
      bypassOnDebug: true
    })
    .end()

Picture compression can be done in batches at: https://tinypng.com/

gzip compression code

Install compression-webpack-plugin plug-in

 npm install compression-webpack-plugin -D

Inside vue.config.js

const CompressionWebpackPlugin = require('compression-webpack-plugin');


// 开启gzip压缩
  config.plugins.push(
    new CompressionWebpackPlugin(
      {
        filename: info => {
          return `${info.path}.gz${info.query}`
        },
        algorithm: 'gzip',
        threshold: 10240, // 只有大小大于该值的资源会被处理 10240
        test: new RegExp('\\.(' + ['js'].join('|') + ')$'
        ),
        minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
        deleteOriginalAssets: false // 删除原文件
      }
    )
  )

The common code is drawn away

Inside vue.config.js

// 开启gzip压缩


configureWebpack: config => {
  config.plugins.push(
    new CompressionWebpackPlugin(
      {
        filename: info => {
          return `${info.path}.gz${info.query}`
        },
        algorithm: 'gzip',
        threshold: 10240, // 只有大小大于该值的资源会被处理 10240
        test: new RegExp('\\.(' + ['js'].join('|') + ')$'
        ),
        minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
        deleteOriginalAssets: false // 删除原文件
      }
    )
  )
}

Element-ui loads on demand

Install the babel-plugin-component plug-in

 npm install babel-plugin-component --save-dev

Inside babel.config.js

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

echarts load on demand:

Install babel-plugin-equire

npm install babel-plugin-equire -D

Create echarts.js in your project :

// eslint-disable-next-line
  const echarts = equire([
    // 写上你需要的 echarts api
    "tooltip",
    "line"
  ]);


  export default echarts;

Inside babel.config.js

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

Specific page applications:

 // 直接引用
 import echarts from '@/lib/util/echarts.js' 

 
 this.myChart = echarts.init(this.$refs.chart) 

Lodash loads on demand:

Install lodash-webpack-plugin plug-in

 npm install lodash-webpack-plugin --save-dev

Inside babel.config.js

module.exports = {
  presets: [
    '@vue/app'
  ],
  plugins: [
    [
      "component",
      {
        libraryName: "element-ui",
        styleLibraryName: "theme-chalk"
      }
    ],
    "lodash",
    "equire"
  ]
}

Inside vue.config.js

const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");


chainWebpack: config => {
    config
    .plugin("loadshReplace")
    .use(new LodashModuleReplacementPlugin());
}

prefetch and preload

Remove useless plug-ins and avoid loading extra resources (if not, useless js files are loaded in index .html)

chainWebpack: config => {
    // 移除prefetch插件,避免加载多余的资源
    config.plugins.delete('prefetch')
    / 移除 preload 插件,避免加载多余的资源
    config.plugins.delete('preload');
}

Full code:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");


module.exports = {
  productionSourceMap: false, // 关闭生产环境的 source map
  lintOnSave: false,
  publicPath: process.env.VUE_APP_PUBLIC_PATH,
  devServer: {
    host: "localhost",
    port: 3002,
    proxy: {
      '/api': {
        target: "https://tapi.quanziapp.com/api/",
        ws: true,
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      },
    }
  },


  chainWebpack: config => {


    // 移除 prefetch 插件
    config.plugins.delete('prefetch');
    // 移除 preload 插件,避免加载多余的资源
    config.plugins.delete('preload');

 
    config.optimization.minimize(true);


    config.optimization.splitChunks({
      chunks: 'all'
    })


    config
      .plugin('webpack-bundle-analyzer')
      .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)


    if (process.env.NODE_ENV !== 'development') {


      let miniCssExtractPlugin = new MiniCssExtractPlugin({
        filename: 'assets/[name].[hash:8].css',
        chunkFilename: 'assets/[name].[hash:8].css'
      })
      config.plugin('extract-css').use(miniCssExtractPlugin)
      config.plugin("loadshReplace").use(new LodashModuleReplacementPlugin());


      config.module.rule('images')
        .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
        .use('image-webpack-loader')
        .loader('image-webpack-loader')
        .options({
          bypassOnDebug: true
        })
        .end()
        .use('url-loader')
        .loader('file-loader')
        .options({
          name: 'assets/[name].[hash:8].[ext]'
        }).end()
      config.module.rule('svg')
        .test(/\.(svg)(\?.*)?$/)
        .use('file-loader')
        .loader('file-loader')
        .options({
          name: 'assets/[name].[hash:8].[ext]'
        })
    }
  },
  configureWebpack: config => {
    // config.plugins.push(["equire"]);


    if (process.env.NODE_ENV !== 'development') {
      config.output.filename = 'assets/[name].[hash:8].js'
      config.output.chunkFilename = 'assets/[name].[hash:8].js'
    }
    // 公共代码抽离
    config.optimization = {
      // 分割代码块
      splitChunks: {
        cacheGroups: {
          //公用模块抽离
          common: {
            chunks: 'initial',
            minSize: 0, //大于0个字节
            minChunks: 2, //抽离公共代码时,这个代码块最小被引用的次数
          },
          //第三方库抽离
          vendor: {
            priority: 1, //权重
            test: /node_modules/,
            chunks: 'initial',
            minSize: 0, //大于0个字节
            minChunks: 2, //在分割之前,这个代码块最小应该被引用的次数
          },
        },
      }
    }
    // 开启gzip压缩
    config.plugins.push(
      new CompressionWebpackPlugin(
        {
          filename: info => {
            return `${info.path}.gz${info.query}`
          },
          algorithm: 'gzip',
          threshold: 10240, // 只有大小大于该值的资源会被处理 10240
          test: new RegExp('\\.(' + ['js'].join('|') + ')$'
          ),
          minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
          deleteOriginalAssets: false // 删除原文件
        }
      )
    )
  },
  css: {
    extract: true,
    sourceMap: false,
    loaderOptions: {
      sass: {
      },
    },
  },
}

The above is W3Cschool编程狮 about the Vue project from 2.5M optimization to 200kb of the whole process of the introduction, I hope to help you.