本文整理了一些 vue 开发中常用 vue-cli 配置,使用的 vue-cli 版本为 3.11.0,主要内容包括:

  1. 移除 preload 与 prefetch
  2. 使用 webpack-bundle-analyzer 做打包分析
  3. 使用 terser-webpack-plugin 清除 console.log
  4. 使用 compression-webpack-plugin 开启 gzip 压缩
  5. 配置使用 CDN 方式引入资源库
  6. 自定义打包的 css/js/图片 文件名和路径
  7. 压缩图片

文末给出了完整的 vue.config.js 配置。

1.移除 preload(预载) 与 prefetch (预取)

vue 脚手架默认开启了 preload 与 prefetch,当我们项目很大时,这个就成了首屏加载的最大元凶了。

先简单了解一下 preload 与 prefetch。

  • preload 与 prefetch 都是一种资源预加载机制;
  • preload 是预先加载资源,但并不执行,只有需要时才执行它;
  • prefetch 是意图预获取一些资源,以备下一个导航/页面使用;
  • preload 的优先级高于 prefetch。

更多请参考 MDN:通过rel="preload"进行内容预加载

看看关闭 preload 与 prefetch 之前的效果:

这里我标注了 4 个部分,

  • 1 代表当前页面的 css/js 资源;
  • 2 代表 UI 库等资源的 css 与 main.js 中自定义的 css
  • 3 代表 main.js 中自定的 js 与 UI 库等资源的 js
  • 4 代表其他页面的资源

其中,2 和 3 都使用了 preload,4 使用了 prefetch。当应用的页面非常多时,会导致 4 的部分增加,以至于首屏加载的速度降低。

关闭 preload 与 prefetch

  chainWebpack: config => {
    // 移除 preload(预载) 插件
    config.plugins.delete('preload')
    // 移除 prefetch(预取) 插件
    config.plugins.delete('prefetch')
  }

关闭后的效果:

关闭前的首屏速度 11s,关闭后 1~2 秒,速度加快 10 倍...

2.使用 webpack-bundle-analyzer 做打包分析

脚手架中默认就包含有 webpack-bundle-analyzer 插件,所以直接使用即可

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

module.exports = {
  chainWebpack: config => {
    // npm run analyzer 时才开启
    if (process.env.npm_config_report) {
      config
        .plugin('webpack-bundle-analyzer')
        .use(BundleAnalyzerPlugin)
    }
  }
}

然后再配置 package.json 

  "scripts": {
    "analyzer": "cross-env NODE_ENV=production npm_config_report=true npm run build"
  },

在 cmd 中执行

npm run analyzer

页面效果(这里只展示左侧侧边栏)

3.使用 terser-webpack-plugin 清除 console.log

开发过程中我们往往需要 console.log 进行调试,调试完后一般也会删除或注释掉,但难免有时会忘记,所以可以使用 terser-webpack-plugin 来清除 console.log。

先安装依赖

npm install terser-webpack-plugin --save-dev

然后配置

const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  configureWebpack: config => {
    // 生产环境下清除 console.log
    if (process.env.NODE_ENV === 'production') {
      return {
        optimization: {
          minimizer: [
            new TerserPlugin({
              sourceMap: false,
              terserOptions: {
                compress: {
                  drop_console: true
                }
              }
            })
          ]
        }
      }
    }
  }
}

4.使用 compression-webpack-plugin 开启 gzip 压缩

开启 gzip 压缩也能极大加快页面加载速度。

先安装依赖

npm install compression-webpack-plugin --save-dev

然后配置

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

module.exports = {
  configureWebpack: config => {
    config.plugins = [
      ...config.plugins,
      // 开启 gzip 压缩
      new CompressionPlugin({
        filename: '[path][base].gz',
        algorithm: 'gzip',
        test: /\.js$|\.css$|\.html$/,
        threshold: 10240,
        minRatio: 0.8
      })
    ]
  }
}

压缩后会生成相应的 gz 文件

可以看见,压缩效果还是很明显的。

只有前端配置 gzip 是不够的,如果你使用了 nginx,还需对其进行配置

http {

    gzip on; # 开启 gzip 压缩
    gzip_static on; # 若存在静态 gz 文件,则使用该文件
    gzip_min_length 10k; # 设置允许压缩的页面最小字节数
    gzip_buffers 16 8k; # 设置用于处理请求压缩的缓冲区数量和大小
    gzip_comp_level 1; # 设置压缩级别 1-9,数字越大,压缩后的大小越小,也越占用CPU,花费时间越长
	# 对特定的 MIME 类型生效, 其中'text/html’被系统强制启用
    gzip_types application/javascript text/css font/ttf font/x-woff;
    gzip_vary on; # 是否在 http header中 添加 Vary:Accept-Encoding, on | off
    gzip_http_version 1.1; # 在 http/1.1 的协议下不开启压缩

}

gzip 相关配置说明可参考:Nginx gzip参数详解及常见问题

如果资源响应头中出现 Content-Encoding: gzip 则代表配置成功

同时,也能通过比较资源的实际大小和请求大小是否一致来判断是否开启了压缩。

5.配置使用 CDN 方式引入资源库

先完成配置:

  configureWebpack: config => {
    config.resolve = {
      // 使用 CDN 的包不用打包到文件中
      externals: {
        // 这里的 element-ui 是 import xx from yy 中的 yy 包名。ELEMENT 是文件导出的全局变量名字
        'element-ui': 'ELEMENT',
      },
    },
  },
  chainWebpack: config => {
    // 添加 CDN 参数到 htmlWebpackPlugin 配置中
    config.plugin('html').tap(args => {
      args[0].cdn = {
        js: [
          'https://xx.com/CDN/js/index-element-ui@2.13.0.js',
        ],
        css: [
          'https://xx.com/CDN/css/element-ui2.13.0/index.css',
        ],
      };
      return args;
    });
  },

然后在 index.html 中挂载 CDN:

<!DOCTYPE html>
<html lang="zh">
  <head>
    <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style">
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
    <% } %>
    <!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
    <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>" type="text/javascript"></script>
    <% } %>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

如果公司没有自己的 CDN,这里推荐两个比较好的:BootCDN 与 cdnjs 。

当然,使用他人的 CDN 你就要考虑安全和稳定性了,要是 CDN 突然挂了(可能性比较小)就很伤。

6.自定义打包的 css/js/图片 文件名和路径

如果你想自定义打包文件名的话,可以考虑进行以下配置。

const appVersion = require('./package.json').version;
const timestamp = new Date().getTime(); // 时间戳

module.exports = {
  css: {
    extract: {
      // 自定义打包的 css 文件名和路径
      chunkFilename: `assets/css/[name].[${appVersion}-${timestamp}].css`
    },
  },
  chainWebpack: config => {
    // 修改图片打包配置
    config.module
      .rule('images')
      .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
      .use('url-loader')
      .loader('url-loader')
      .tap(options => {
        // 修改它的选项...
        options.fallback.options.name = `assets/img/[name].[${appVersion}-${timestamp}].[ext]`; // 修改文件名
        // 这是字节(Byte)限制,1KB = 1024Byte,当图片的大小小于4KB(默认值),则会被转为base64格式,打包进js文件,
        // 大于4KB,则会被打包进 img 文件夹,供链接请求获取。 
        options.limit = 1024 * 4;
        return options
      })
  },
  configureWebpack: config => {
    // 自定义打包的 js 文件名和路径
    config.output.chunkFilename = `assets/js/[name].[${appVersion}-${timestamp}].js`
  }
}

注:[name] 就是默认的 webpackChunkName。

大致效果如下:

7.压缩图片

如果需要对图片进行压缩的话可以使用以下配置。

先安装依赖

npm install image-webpack-loader --save-dev

然后配置

  chainWebpack: config => {
    // 压缩图片
    config.module
      .rule('images')
      .use('imageWebpackLoader')
      .loader('image-webpack-loader')
      .options({
        disable: process.env.NODE_ENV === 'development', // 开发环境下禁止压缩
        gifsicle: {
          interlaced: false
        }
      })
  }

但我一般不用这个压缩,这里推荐一个在线压缩网站:TinyPNG – Compress WebP, PNG and JPEG images intelligently

结尾:完整的 vue.config.js 配置

const path = require('path');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');

// 是否是开发环境 development | production
const isDevlopment = process.env.NODE_ENV === 'development';
// const appVersion = require('./package.json').version;
// const timestamp = new Date().getTime();
function resolve (dir) {
  return path.join(__dirname,  dir)
}

module.exports = {
  publicPath: './', // 根路径
  outputDir: 'dist', // 构建输出目录
  assetsDir: 'assets', // 静态资源目录
  lintOnSave: false, // 是否开启eslint保存检测,有效值:true || false || 'error'
  devServer: {
    open: false, // 项目运行后是否自动打开浏览器
    host: '0.0.0.0', // 既可localhost,也可ip访问
    port: 8081,
    https: false,
    hotOnly: false, // 热更新
  },
  productionSourceMap: false, // 生产环境下关闭 SourceMap
  css: {
    // extract: {
    //   // 自定义打包的 css 文件名和路径
    //   chunkFilename: `assets/css/[name].[${appVersion}-${timestamp}].css`
    // },
    sourceMap: isDevlopment // 开发环境下开启方便调试样式
  },
  chainWebpack: config => {
    // 移除 preload(预载) 插件
    config.plugins.delete('preload')
    // 移除 prefetch(预取) 插件
    config.plugins.delete('prefetch')
    // npm run analyzer 时才开启
    if (process.env.npm_config_report) {
      config
        .plugin('webpack-bundle-analyzer')
        .use(BundleAnalyzerPlugin) // 分析项目文件大小的插件
    }
    // 添加 CDN 参数到 htmlWebpackPlugin 配置中
    config.plugin('html').tap(args => {
      args[0].cdn = {
        js: [
          'https://xx.com/CDN/js/index-element-ui@2.13.0.js',
        ],
        css: [
          'https://xx.com/CDN/css/element-ui2.13.0/index.css',
        ],
      }
      return args
    })
    // 压缩图片
    // config.module
    //   .rule('images')
    //   .use('imageWebpackLoader')
    //   .loader('image-webpack-loader')
    //   .options({
    //     disable: isDevlopment, // 开发环境下禁止压缩
    //     gifsicle: {
    //       interlaced: false
    //     }
    //   })
    // 修改图片打包配置
    // config.module
    //   .rule('images')
    //   .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
    //   .use('url-loader')
    //   .loader('url-loader')
    //   .tap(options => {
    //     // 修改它的选项...
    //     options.fallback.options.name = `assets/img/[name].[${appVersion}-${timestamp}].[ext]`; // 修改文件名
    //     // 这是字节(Byte)限制,1KB = 1024Byte,当图片的大小小于4KB(默认值),则会被转为base64格式,打包进js文件,
    //     // 大于4KB,则会被打包进 img 文件夹,供链接请求获取。 
    //     options.limit = 1024 * 4;
    //     return options
    //   })
  },
  configureWebpack: config => {
    // 自定义打包的 js 文件名和路径
    // config.output.chunkFilename = `assets/js/[name].[${appVersion}-${timestamp}].js`
    config.resolve = {
      extensions: ['.js', '.vue', '.json', '.css'],
      // 配置路径别名
      alias: {
        'vue$': 'vue/dist/vue.esm.js',
        '@': resolve('src'),
        'api': resolve('src/api'),
        'css': resolve('src/assets/css')
      },
      // 使用 CDN 的包不用打包到文件中
      externals: {
        // 这里的 element-ui 是 import xx from yy 中的 yy 包名。ELEMENT 是文件导出的全局变量名字
        'element-ui': 'ELEMENT',
      },
    },
    config.plugins = [
      ...config.plugins,
      // 开启 gzip 压缩
      new CompressionPlugin({
        filename: '[path][base].gz',
        algorithm: 'gzip',
        test: /\.js$|\.css$|\.html$/,
        threshold: 10240,
        minRatio: 0.8
      })
    ]
    // 生产环境下
    if (!isDevlopment) {
      return {
        optimization: {
          minimizer: [
            new TerserPlugin({
              sourceMap: false,
              terserOptions: {
                compress: {
                  drop_console: true // 生产环境下清除 console.log
                }
              }
            })
          ]
        }
      }
    }
  }
};

Logo

前往低代码交流专区

更多推荐