@vue/cli 5.x的配置实战与优化

7,286 阅读7分钟

一、前言

  • 简单介绍

​ @vue/cli 5.x是一个交互式的项目脚手架,分为CLI、CLI服务、CLI插件三个独立部分。本文分别从@vue/cli5.x做了哪些工作?以及@vue/cli 5.x还可以做哪些优化?带你全面了解@vue/cli5.x的工程配置及优化。完整的配置放在GitHub上了,文末自取。

  • 开发环境:

​ Node@18.15.0;npm@9.5.0;vue@^3.2.13;@vue/cli 5.0.8

二、@vue/cli5.x做了哪些工作

1、启用Babel转译

  • 引入Babel转换ES代码,使用@vue/cli-plugin-babel/preset预设,默认将useBuildIns: 'usage'传递给babel/preset-env,这样它会根据代码中出现的语言特性自动按需引入polyfill

2、启用缓存

  • Vue/Babel/TypeScript编译默认开启cache-loader缓存在node-modules/.cache

3、启用多线程

  • 多核CPU的机器上默认为Babel/TypeScript转译开启thread-loader,即多线程

4、git hook

  • 默认安装yorkie,让我们在package.jsongitHooks字段中指定Git hook,通常配合lint-staged使用(pre: 需安装并配置)

5、自动注入preload、prefetch

  • 默认使用 @vue/preload-webpack-plugin对link资源preload、prefetch
    • preload: vue cli会为所有初始化渲染需要的资源文件在link标签上自动注入preload
    • prefetch: vue cli会为所有作为async chunk生成的js文件(通过动态import()按需code splitting的产物)自动注入prefetch

6、静态资源处理

  • 在JS、CSS、*.vue文件中通过相对路径被引用,这类引用会被webpack处理

    • 如果URL 是一个绝对路径 (例如 /images/foo.png),它将会被保留不变
    • 如果 URL 以 . 开头,它会作为一个相对模块请求被解释且基于你的文件系统中的目录结构进行解析
    • 如果 URL 以 ~ 开头,其后的任何内容都会作为一个模块请求被解析。这意味着你甚至可以引用 Node 模块中的资源
    • 如果 URL 以 @ 开头,它也会作为一个模块请求被解析。它的用处在于 Vue CLI 默认会设置一个指向 <projectRoot>/src 的别名 @(仅作用于模版中)
  • public文件夹

    • 任何放置在 public 文件夹的静态资源都会被简单的复制,而不经过 webpack。你需要通过绝对路径来引用它们

7、HTML模板构建

  • 默认使用html-webpack-plugin处理public/index.html模板,自动注入资源链接(preload/prefetch、manifest、js、css)

8、css及预处理器支持

  • CSS处理

    • 默认使用mini-css-extract-plugin提取css成单独文件
    • 默认使用css-minimizer-webpack-plugin压缩css代码(webpack在生产模式下自动压缩js、html)
  • PostCSS、CSS Modules以及预处理器支持

    • 默认支持PostCSS、CSS Modules和包含Sass、Less、Stylus在内的预处理器

    • PostCSS: 可以通过.postcssrc文件或vue.config.js中的css.loaderOptions.postcss配置

    • CSS Modules:scoped技术,给css限定作用域

    • CSS及预处理器相关,可以通过vue.config.js中的css.loaderOptions配置

9、图片资源处理

  • 默认小于8KIB的图片资源会被内联(base64),以减小HTTP请求的数量,同时也会使得文件略微变大(图片转base64后占据空间更大)

10、webpack配置

  • configureWebpack(Object | Function)
    • 会被webpack-merge合并入最终的webpack配置,通常用于修改一些基础配置、引入插件等
    • 一些基础值不能直接修改,如你应该修改 vue.config.js 中的 outputDir 选项而不是修改 output.path;你应该修改 vue.config.js 中的 publicPath 选项而不是修改 output.publicPath
  • chainWebpack(Function)
    • vue cli内部的webpack配置是通过webapck-chain维护的
    • 通常用于增加、删除、修改、替换loader,修改plugin选项等

11、模式和环境变量注入

  • 模式
    • development模式用于vue-cli-service serve
    • test模式用于vue-cli-service test:unit
    • production模式用于vue-cli-service buildvue-cli-service test:e2e
  • 环境变量
    • 始终可用,且可以再public/index.html中以HTML插值的方式使用
      • VUE_APP_*:可以在vue.config.js中被赋值
      • NODE_ENV:development|test|production,取决于模式
      • BASE_URL:等于vue.config.js中的publicPath
    • 仅vue.config.js中可用
      • 除以上三种外
    • 注意
      • 环境变量不能直接在template中以process.env.*使用,要先赋值给变量再使用(template不认识process)

12、代码热更新

13、自动清除上次构建内容

三、@vue/cli 5.x还可以做哪些优化?

1、分析工具

1)分析编译时长

  • 插件:speed-measure-webpack-plugin

  • 功能:测量构建速度,输出各个模板编译时长

  • 配置:

    npm install speed-measure-webpack-plugin --save-dev
    
    const { defineConfig } = require('@vue/cli-service');
    const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
    module.exports = defineConfig({
      ...,
      configureWebpack: (config) => {
          ...
          config.plugins.push(
            new SpeedMeasurePlugin(),
          );
        },
    });
    
  • 结果

    image-20230402160715575.png

2)分析模块大小

  • 插件:webpack-bundle-analyzer

  • 功能:可视化展示构建后各个包的大小

  • 配置:

    npm install webpack-bundle-analyzer --save-dev
    
    const { defineConfig } = require('@vue/cli-service');
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    module.exports = defineConfig({
      ...,
      configureWebpack: (config) => {
          ...
          config.plugins.push(
          	new BundleAnalyzerPlugin()
          );
        },
    });
    
  • 结果

    image-20230402161741215.png

2、构建优化

1)多线程优化

  • 插件:thread-loader

  • vue cli默认为Babel/TypeScript转译开启,不需要额外配置

  • 注:thread-loader的启用开销为只600ms左右,最好只针对耗时操作启用。

2)缓存优化

  • webpack缓存方式介绍

    • cache配置项(webpack5.x)

      const { defineConfig } = require('@vue/cli-service');
      module.exports = defineConfig({
        ...,
        configureWebpack: (config) => {
      	// 缓存生成的 webpack 模块和 chunk,来改善构建速度
          config.cache = {
          	type: 'filesystem',
          	allowCollectingMemory: true
          };
        }
      });
      
    • 下面几种缓存方式都有首次启动时的开销,即它们会让 "冷启动" 时间会更长,但是二次启动能够节省很多时间

      • cache-loader
      • hard-source-webpack-plugin(vue/cli使用的是webpack5,不可用)
      • babel-loadercacheDirectory选项
      • vue cli默认为vue、babel、js、eslint、splitChunks启用了缓存

3)构建进度条

  • ProgressPlugin

    • 配置

      const { ProgressPlugin } = require('webpack');
      module.exports = defineConfig({
          configureWebpack: config => {
            	const plugins = [
                new ProgressPlugin({
                  activeModules: true, // 默认false,显示活动模块计数和一个活动模块正在进行消息。
                  entries: true, // 默认true,显示正在进行的条目计数消息。
                  modules: true, // 默认true,显示正在进行的模块计数消息。
                  modulesCount: 5000, // 默认5000,开始时的最小模块数。PS:modules启用属性时生效。
                  profile: false, // 默认false,告诉ProgressPlugin为进度步骤收集配置文件数据。
                  dependencies: true, // 默认true,显示正在进行的依赖项计数消息。
                  dependenciesCount: 10000 // 默认10000,开始时的最小依赖项计数。PS:dependencies启用属性时生效
                })
              ];
              return {
                plugins
              };
          }
      });
      
    • webpackbar

3、生产优化

1)关闭生产环境sourcemap

const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
	...,
	productionSourceMap: false
})

2)减少js代码体积

  • 删除console、debugger、注释

    const { defineConfig } = require('@vue/cli-service');
    module.exports = defineConfig({
    	...,
    	chainWebpack: config => {
        	if (process.env.NODE_ENV === 'production') { // 生产
                // 删除console、debugger、注释
                const terser = config.optimization.minimizer('terser');
                terser.tap(args => {
                  const { terserOptions } = args[0];
                  Object.assign(
                    terserOptions,
                    {
                      compress: {
                        ...terserOptions.compress,
                        drop_console: true,
                        drop_debugger: true
                      },
                      format: {
                        comments: /@license/i
                      }
                    }
                  );
                  return args;
                });
    		}
        }
    });
    

3)压缩图片资源

  • image-minimizer-webpack-plugin

    • 配置

      npm install image-minimizer-webpack-plugin imagemin @squoosh/lib --save-dev
      npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
      
      const { defineConfig } = require('@vue/cli-service');
      const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
      module.exports = defineConfig({
          ...,
          chainWebpack: config => {
          	if (process.env.NODE_ENV === 'production') { // 生产
                  const optimization = config.optimization;
                  // 压缩图片
                  const imageMinizer = optimization.minimizer('image-minizer');
                  imageMinizer.use(ImageMinimizerPlugin, [{
                    minimizer: {
                      implementation: ImageMinimizerPlugin.imageminMinify,
                      options: {
                        // Lossless optimization with custom option
                        // Feel free to experiment with options for better result for you
                        plugins: [
                          ["gifsicle", { interlaced: true }],
                          ["jpegtran", { progressive: true }],
                          ["optipng", { optimizationLevel: 5 }],
                          // Svgo configuration here https://github.com/svg/svgo#configuration
                          [
                            "svgo",
                            {
                              plugins: [
                                {
                                  name: "preset-default",
                                  params: {
                                    overrides: {
                                      removeViewBox: false,
                                      addAttributesToSVGElement: {
                                        params: {
                                          attributes: [
                                            { xmlns: "http://www.w3.org/2000/svg" }
                                          ]
                                        }
                                      }
                                    }
                                  }
                                }
                              ]
                            }
                          ]
                        ]
                      }
                    }
                  }]);
      		}
      	}
      });
      
    • 注:webpack5官网配置有误,上面是该依赖的git仓库提供的配置

4)动态链接库dll

5)启用gzip压缩文件

  • 配置

    vue.config.js开启gzip静态压缩

    const CompressionPlugin = require("compression-webpack-plugin");
    module.exports = defineConfig({
        configureWebpack: config => {
            const plugins = [];
          	if (process.env.NODE_ENV === 'production') { // 生产
              plugins.push(
                // new SpeedMeasurePlugin(),
                // new BundleAnalyzerPlugin(),
                new CompressionPlugin({
                  test: /\.(js|css|json|html)(\?.*)?$/i,
                  filename: '[path].gz[query]', // 压缩后的文件名
                  algorithm: 'gzip',
                  threshold: 10240, // 仅处理大于此大小的资产(以字节为单位)
                  minRatio: 0.8, // 仅压缩比该比率更好的资产(minRatio = Compressed Size / Original Size)
                  deleteOriginalAssets: false // 是否删除原始文件
                })
              );
            }
            return {
              plugins
            };
        }
    });
    

    nginx.conf文件配置

    server{
    	...
    	# 开启Gzip压缩:若没有找到.gz,会动态压缩,因此建议前端打包成.gz文件
        gzip on;
        gzip_min_length 1k;
        gzip_buffers 4 16k;
        gzip_comp_level 5;
        gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
        gzip_http_version 1.1;
        gzip_vary on;
        gzip_disable "MSIE [1-6]\.";
    }
    

四、结语

​ 最后附上完整配置链接:github.com/Orange-001/…