Webpack principles and manual practice implementation webPack will be supplemented later.

In vue/ CLI 3, webpack is integrated in THE CLI to reduce the complex configuration items of webpack, and vue.config.js file is provided to allow users to configure.

To cover most of the configuration requirements for vuE-CLI development, the following detailed and comprehensive summary of vuE-CLI3 configuration information is provided.

1. Configure multiple environment variables

Specify –mode in package.json to configure command items for different environments;

Only variables starting with VUE_APP are statically embedded in client-side packages by webpack.defineplugin and are accessible in code through process.env.vue_app_base_API

NODE_ENV and BASE_URL are two special variables that are always available in code;

Environment variables can be accessed through process

 console.log("BASE_URL", process.env.BASE_URL);
 console.log("VUE_APP_API", process.env.VUE_APP_API);
Copy the code

Configuration:

Create a new environment variables file (.env,.env.production,.env.analyz, etc.) in the root directory of your project.

  • .env
 NPM Run serve is the default local development environment configuration
NODE_ENV = "development"
BASE_URL = ". /"
VUE_APP_PUBLIC_PATH = '/'
VUE_APP_API = "https://development.com/api"  // Development environment domain name
Copy the code
  • .env.production

    // that is: build default environment configuration
    NODE_ENV = 'production'
    BASE_URL = 'https://production.com/'
    VUE_APP_PUBLIC_PATH = 'https://production/blog'
    VUE_APP_API = 'https://production/api'
    
    ACCESS_KEY_ID = 'xxxxxxxxxxxxx'
    ACCESS_KEY_SECRET = 'xxxxxxxxxxxxx'
    Copy the code
  • .env.analyz

    // That is, custom build environment configuration
    NODE_ENV = 'production'
    BASE_URL = 'https://production.com/'
    VUE_APP_PUBLIC_PATH = https://production.com/blog'
    VUE_APP_API = 'https://production.com/api'
    
    ACCESS_KEY_ID = 'xxxxxxxxxxxxx'
    ACCESS_KEY_SECRET = 'xxxxxxxxxxxxx'
    
    IS_ANALYZE = true
    Copy the code

Modify package.json file:

"scripts": {
    "serve": "vue-cli-service serve"."build": "vue-cli-service build"."analyz": "vue-cli-service build --mode analyz"."lint": "vue-cli-service lint"
 },
Copy the code

2. Configure basic vue.config.js

Distinguish between development and production environments, and configure them accordingly (other configurations will be improved step by step)

const IS_PROD = ['production'.'prod'].includes(process.env.NODE_ENV)

module.exports = {
  publicPath: IS_PROD ? process.env.VUE_APP_PUBLIC_PATH : '/'.// The default '/', the base URL for deploying the application package
  / / outputDir: process. The env. OutputDir | | 'dist' / / 'dist, build file directory of the production environment, can be configured in the environment variable
  // assetsDir: "", // Static resources (js, CSS, img, fonts) directory relative to outputDir
  lintOnSave: false.runtimeCompiler: true.// Whether to use the Vue build with the runtime compiler
  productionSourceMap: !IS_PROD, // Source map of production environment, development on, production off
  parallel: require('os').cpus().length > 1.pwa: {}}Copy the code

3. Configure the proxy

Configuration agents can be used to solve cross-domain problems in development.

Devserver. proxy can be a string pointing to the development environment API server, or it can use a path: options pair of objects;

module.exports = {
  devServer: {
    // HTTPS: true, // If proxy is HTTPS, you need to enable it
    proxy: 'http://localhost:4000'}}Copy the code

Path :options

module.exports = {
  devServer: {
    // overlay: {// Make browser overlay display warnings and errors at the same time
    // warnings: true,
    // errors: true
    // },
    // open: false, // Whether to open the browser
    // host: "localhost",
    // port: "8080", // the proxy is disconnected
    // https: false,
    // hotOnly: false, // Hot update
    proxy: {
      '/api': {
        target:
          'https://www.easy-mock.com/mock/5bc75b55dc36971c160cad1b/sheets'.// Address of the destination proxy interface
        secure: false.changeOrigin: true.// Enable the proxy to create a virtual server locally
        // ws: true, // Whether webSockets are enabled
        pathRewrite: {
          '^/api': '/'
        }
      }
    }
  }
}
Copy the code

4. Configure the alias

Configure the alias of the project to facilitate the import of files, especially custom files

const path = require('path')
const resolve = dir= > path.join(__dirname, dir)
const IS_PROD = ['production'.'prod'].includes(process.env.NODE_ENV)

module.exports = {
  chainWebpack: config= > {
    // Add an alias
    config.resolve.alias
      .set('vue$'.'vue/dist/vue.esm.js')
      .set(The '@', resolve('src'))
      .set('@assets', resolve('src/assets'))
      .set('@scss', resolve('src/assets/scss'))
      .set('@components', resolve('src/components'))
      .set('@plugins', resolve('src/plugins'))
      .set('@views', resolve('src/views'))
      .set('@router', resolve('src/router'))
      .set('@store', resolve('src/store'))
      .set('@layouts', resolve('src/layouts'))
      .set('@static', resolve('src/static'))}}Copy the code

5. Packaging of pictures

For the default URL-loader of Vue/CLI 3, base64 conversion is performed for images smaller than 4096 bytes by default. For large images, image-webpack-loader is used for compression.

// Add image compression loader
npm i -D image-webpack-loader
Copy the code

Note: If the NPM installation fails, an error is reported, such as:

Module build failed (from ./node_modules/image-webpack-loader/index.js): 
Error: Cannot find module 'gifsicle'
Copy the code

Speculation may be network reasons, using Taobao image for installation:

/ / uninstall first
npm uninstall image-webpack-loader
// Add a Taobao image
npm install cnpm -g --registry=https://registry.npm.taobao.org
// Install again
cnpm install --save-dev  image-webpack-loader 
Copy the code

In vue. Config. Add configuration: js configuration information about the image – webpack – loader can view the website: www.npmjs.com/package/ima… Information about chainWebpack can be viewed at chainWebpack

module.exports = {
  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.9].speed: 4 },
        gifsicle: { interlaced: false },
        webp: { quality: 75}}}})Copy the code

6. Automatically generate Sprite images

By default, SRC/Assets/ICONS store the PNG files for Sprite images to be generated. Running NPM run serve/build for the first time generates Sprite images and an icons.json file in the root directory. When you run the command again, the matching relationship between the files in the ICONS directory and icons.json is compared to determine whether the webpack-spritesmith plug-in needs to be executed again.

/ / add the plugin
npm i -D webpack-spritesmith
Copy the code

Modify the configuration file: vue.config.js

const SpritesmithPlugin = require('webpack-spritesmith')
const path = require('path')
const fs = require('fs')

let has_sprite = true;
let files = [];
const icons = {};

try {
  fs.statSync(resolve("./src/assets/icons"));
  files = fs.readdirSync(resolve("./src/assets/icons"));
  files.forEach(item= > {
    let filename = item.toLocaleLowerCase().replace(/_/g."-");
    icons[filename] = true;
  });
} catch (error) {
  fs.mkdirSync(resolve("./src/assets/icons"));
}

if(! files.length) { has_sprite =false;
} else {
  try {
    let iconsObj = fs.readFileSync(resolve("./icons.json"), "utf8");
    iconsObj = JSON.parse(iconsObj);
    has_sprite = files.some(item= > {
      let filename = item.toLocaleLowerCase().replace(/_/g."-");
      return! iconsObj[filename]; });if (has_sprite) {
      fs.writeFileSync(resolve("./icons.json"), JSON.stringify(icons, null.2)); }}catch (error) {
    fs.writeFileSync(resolve("./icons.json"), JSON.stringify(icons, null.2));
    has_sprite = true; }}// Sprite image style processing template
const SpritesmithTemplate = function(data) {
  // pc
  let icons = {};
  let tpl = `.ico { 
  display: inline-block; 
  background-image: url(${data.sprites[0].image}); 
  background-size: ${data.spritesheet.width}px ${data.spritesheet.height}px; } `;

  data.sprites.forEach(sprite= > {
    const name = "" + sprite.name.toLocaleLowerCase().replace(/_/g."-");
    icons[`${name}.png`] = true;
    tpl = `${tpl} 
.ico-${name}{
  width: ${sprite.width}px; 
  height: ${sprite.height}px; 
  background-position: ${sprite.offset_x}px ${sprite.offset_y}px;
}
`;
  });
  return tpl;
};

module.exports = {
  configureWebpack: config= > {
    const plugins = [];
    if (has_sprite) {
      plugins.push(
        new SpritesmithPlugin({
          src: {
            cwd: path.resolve(__dirname, "./src/assets/icons/"), // Icon root path
            glob: "**/*.png" // Match any PNG icon
          },
          target: {
            image: path.resolve(__dirname, "./src/assets/images/sprites.png"), // Generate Sprite map target path and name
            // Sets the file or method to generate the CSS background and its location
            css: [
              [
                path.resolve(__dirname, "./src/assets/scss/sprites.scss"),
                {
                  format: "function_based_template"}}]].customTemplates: {
            function_based_template: SpritesmithTemplate
          },
          apiOptions: {
            cssImageRef: ".. /images/sprites.png" // The relative position path configuration of the Sprite diagram referenced in the CSS file
          },
          spritesmithOptions: {
            padding: 2}})); } config.plugins = [...config.plugins, ...plugins]; }};Copy the code

** Note: ** replacing the ICONS name to change the image may cause the Sprite image not to be updated; Avoid using pictures with the same name;

7. Convert SVG images to font

Add dependencies:

npm i -D svgtofont
Copy the code

Add the scripts directory to the root of the project and create the svg2font. Js file

Disadvantages: Converted font fonts, each support only one color; To retain the SVG design draft, you are advised to use it

const svgtofont = require('svgtofont')
const path = require('path')
const pkg = require('.. /package.json')

svgtofont({
  src: path.resolve(process.cwd(), "src/assets/svg"), // SVG icon directory path
  dist: path.resolve(process.cwd(), "src/assets/fonts"), // Output to the specified directory
  fontName: 'icon'.// Set the font name
  css: true.// Generate a font file
  startNumber: 20000.// Unicode start number
  svgicons2svgfont: {
    fontHeight:1000.normalize: true
  },
  website: {
    title: 'icon'.logo: ' '.version: pkg.version,
    meta: {
      description: ' '.keywords: ' '
    },
    description: ' '.links: [{title: 'Font Class'.url: "index.html"
      },
      {
        title: "Unicode".url: 'unicode.html'}].footerInfo: ` `
  }
}).then(() = >{
  console.log('Successful transformation, congratulations! ')
}).catch(err= >{
  console.log(err)
})
Copy the code

** Introduce icon.css under SRC/Assets /fonts in mian. Use HTML files that can look under the same file

8. Use SVG components

To compensate for the shortcomings of font, the SVG global component approach is adopted.

/ / add the loader
npm i -D svg-sprite-loader
Copy the code

Add common components: / SRC/components/common/SvgIcon vue

<template> <svg class="svg-icon" :style="iconStyle" aria-hidden="true"> <use :xlink:href="name"/> </svg> </template> <script> export default {// iconName: name of the SVG image to be displayed // iconStyle: a custom line style name: 'SvgIcon', props: {iconName: {type: String, required: true }, iconStyle: { type:String, default: '' } }, computed: { name() { return `#icon-${this.iconName}` } } } </script> <style scoped> .svg-icon { width: 1em; height: 1em; Vertical - align: 0.15 em. fill: currentColor; overflow: hidden; } </style>Copy the code

Add SVG resources and corresponding scripts: create an ICONS folder under SRC for handling SVG components and logic; Add an SVG file to the ICONS file to put the SVG image and add index.js

import SvgIcon from "@/components/common/SvgIcon";
import Vue from "vue";

 /* require.context("./test", false, /.test.js$/); This line of code will go under the test folder (excluding subdirectories) and look for all files whose names end in.test.js that can be required. To put it more bluntly, we can introduce the corresponding file module through regular matching. Require. context has three parameters: directory: specifies the directory that needs to be retrieved. UseSubdirectories: specifies whether a subdirectory needs to be retrieved

// Register to global
Vue.component("svg-icon", SvgIcon);

const requireAll = requireContext= > requireContext.keys().map(requireContext);
const req = require.context("./svg".false./\.svg$/);
requireAll(req);
Copy the code

Introduce in main.js:

import "@/icons/index.js";
Copy the code

Add loader configuration for SVG, modify vue.config.js

const path = require("path");
const resolve = dir= > path.join(__dirname, dir);

module.exports = {
  chainWebpack: config= > {
    const svgRule = config.module.rule("svg");
    svgRule.uses.clear();
    svgRule.exclude.add(/node_modules/);
    svgRule
      .test(/\.svg$/)
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: "icon-[name]"
      });

    const imagesRule = config.module.rule("images");
    imagesRule.exclude.add(resolve("src/icons"));
    config.module.rule("images").test(/\.(png|jpe? g|gif|svg)(\? . *)? $/); }};Copy the code

9. Add packaging analysis

Vue/CLI 3 already contains dependencies. Modify dependencies in vue.config.js

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

module.exports = {
  chainWebpack: config= > {
    // Package analysis
    if (IS_PROD) {
      config.plugin("webpack-report").use(BundleAnalyzerPlugin, [
        {
          analyzerMode: "static"}]); }}};Copy the code

10. Enable gzip compression

// Add dependencies
npm i -D compression-webpack-plugin
Copy the code

Modify the vue. Config. Js

const CompressionWebpackPlugin = require("compression-webpack-plugin");
const IS_PROD = ["production"."prod"].includes(process.env.NODE_ENV);
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\? . *)? $/i;

module.exports = {
  configureWebpack: config= > {
    const plugins = [];
    if (IS_PROD) {
      plugins.push(
        new CompressionWebpackPlugin({
          algorithm: "gzip".test: productionGzipExtensions,
          threshold: 10240.minRatio: 0.8})); } config.plugins = [...config.plugins, ...plugins]; }};Copy the code

11. Delete console.log from the production environment

Use the babel-plugin-transform-remove-console plug-in

npm i -D babel-plugin-transform-remove-console
Copy the code

Add a configuration to babel.config.js. If you don’t have this file, create a new one in the root directory:

const IS_PROD = ["production"."prod"].includes(process.env.NODE_ENV);

const plugins = [];
if (IS_PROD) {
  plugins.push("transform-remove-console");
}

module.exports = {
  presets: ["@vue/app", { useBuiltIns: "entry" }],
  plugins
};
Copy the code

12. Add COMPATIBILITY with IE

npm i -S @babel/polyfill
Copy the code

Add it in main.js

import "@babel/polyfill";
Copy the code

Configure the Babel. Config. Js

const plugins = [];

module.exports = {
  presets: [["@vue/app", { useBuiltIns: "entry" }]],
  plugins: plugins
};
Copy the code

13. SplitChunksPlugin

A very powerful and extremely useful plugin; For details, please refer to juejin.cn/post/684490…

14. Externals Cache third-party resources

Use externals to exclude fixed resources from being packaged into DIST. Generally, it is used in combination with CDN. Configuration is also relatively simple, here only put the official website; Webpack.js.org/configurati…

15. Accelerate the compilation of hard-source-webpack-plugin

NPM address: www.npmjs.com/package/har…

What it does: The first build saves the cache to node_modules’.cache directory by default, and the second build uses the cache. So you can increase the speed of construction