一万字webpack5基础&高级学习笔记

130 阅读9分钟

webpack5学习笔记

webpack基础

中文官网
https://www.webpackjs.com/
基本使用
  1. 在当前目录下使用npm i webpack webpack-cil -D下载webpack需要的包
  2. npx webpack ./src/main.js --mode=production可以将代码编译成生产环境可以运行的代码
  3. npx webpack ./src/main.js --mode=development可以将代码编译成开发环境可以运行的代码
  4. 如果根目录下有webpack.config.js文件就可以直接使用npx webpack打包
核心配置
  1. entry(入口):指定打包的入口文件。默认为src/main.js
  2. output(出口):指定打包的出口文件
  3. loader(加载器):webpack本身只能处理js、css文件,其他的资源文件需要借助loader、webpack才能解析
  4. pulgins(插件):扩展webpack功能
  5. mode(模式):开发模式development和生产模式production
开发模式下webpack作用
  1. 解析处理css,字体资源,图片文件资源以及html文件
  2. 代码质量检查,树立代码规范
处理css样式资源
  1. 下载npm i css-loader --save-devnpm i style-loader -D
  2. main.js文件中引入css文件
  3. rules中添加规则如下:
        rules:[
            // loader配置
            {
                test:/.css$/, // 只检测以.css结尾的文件,
                use: [
                    'style-loader', 
                    'css-loader'  // 将css资源编译成commonjs的模块到js中
                ],  // 从下往上解析
            }
        ]
  1. npx webpack 打包css文件
处理less资源
  1. 下载npm i less-loader --save-dev
  2. main.js文件中引入less文件
  3. rules中添加规则如下:
        rules:[
            // loader配置
            {
                test:/.less$/, // 只检测以.less结尾的文件
                use: [
                    'style-loader', 
                    'css-loader',
                    'less-loader' 
                ], 
            }
        ]
  1. npx webpack 打包less文件
处理sass资源:同上
处理stylus资源:同上
处理图片资源
  1. webpack默认会将图片资源进行转化不用下载任何的loader资源
  2. 可以配置图片打包的一些输出结果。比如:将小于10kb的图片转化为base64格式
            {
                test: /.(png|jpe?g|svg| gif| webg)$/, // 图片格式
                type: 'asset',
                parser:{
                    dataUrlCondition: {
                        // 小于10kb 的转base64
                        maxSize: 10 * 1024
                    }
                },
                配置图片资源的路径
                generator:{
                    // 输入图片名称、路径
                    // hash8位
                    filename:'static/imagse/[hash:8][ext][query]'
                }
            }
自动清空上次打包资源
    output: {
        // 输出路径。绝对路径
        path: path.resolve(__dirname, 'dist'), // __dirname代表当前文件的目录
        // js文件打包路径
        filename: 'static/js/main.js',
        // 自动清空上次打包结果
        clean:true,
    },
处理字体图标库资源
  1. 项目中引入字体图标库文件
  2. 在main中引入字体图标css文件
  3. 配置打包路径
            {
                test: /.(ttf|woff2?)$/,
                type: 'asset/resource', // 将文件原封不动进行输出,不会转化为base64
                generator: {
                    filename: "fonts/[hash:8][ext][query]",
                }
            }
  1. npx webpack 打包
处理其他资源如:音视频资源
            {
                test: /.(mp3 | mp4)$/, 
                type: 'asset/resource',
                generator: {
                    filename: "fonts/[hash:8][ext][query]",
                }
            }
处理js资源。
  1. 将es5转化为es6,兼容性问题。babel
  2. 代码格式规范。eslint
eslint
  1. 文件写法:

    • .eslintrc.*:位于根目录下
    • .eslintrc
    • .eslintrc.js
    • .eslintrc.json
    • 在packjson中eslintconfig即可
  2. 在webpack使用,可以参考

    • 安装eslint-webpack-plugineslint

    • 在vue.config.vue文件中引入,最后创建文件进行配置即可。

      const ESLintPlugin = require('eslint-webpack-plugin');module.exports = {
        // ...
        plugins: [new ESLintPlugin(options)],
        // ...
      };
      
  3. eslint文件配置

// 配置文件
module.exports = {
    extends: ['eslint:recommended'], // 继承eslint规则
    env: {
        node:true, // 启用node全局变量
        browser:true, // 启用浏览器全局变量
    },
    parserOptions: {
        ecmaVersion:6, // es6
        sourceType:'module',  // es module
    },
    rules:{
        "no-var": 2  // 不能使用var定义变量
    }
}
  1. .eslintignoreeslint规范忽略文件。在改文件下输入忽略的文件即可。
babel
  1. 定义:babel为js代码编译器,可以将es6比较高级的写法转化为向后兼容的代码,以便可以在浏览器中运行。

  2. 配置文件写法

    • babe.config.* 位于根目录

      • babel.config.js
      • babel.config.json
    • .babelrc.*位于根目录

      • .babelrc
      • .babelrc.js
      • .babelrc.json
    • package.json中babel:不需要创建文件,可以直接编写。

  3. 在webpack使用。参考

    • 安装插件

      • npm install -D babel-loader @babel/core @babel/preset-env webpack
    • 在webpack中加入规则

                  {
                      test: /.m?js$/,
                      exclude: /(node_modules|bower_components)/, // 排除的文件名称
                      use: {
                        loader: 'babel-loader',
                        options: { // 也可以在bable.config文件中写
                          presets: ['@babel/preset-env']
                        }
                      }
                  }
      
  4. bablel文件配置

    // bable 配置文件
    module.exports = {
        // 智能映射,能够编译es6语法
        presets: ['@babel/preset-env'],
    }
    
自动引入打包后的文件
  1. 下载插件npm install --save-dev html-webpack-plugin参考

  2. 在webpack文件中引入

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    
    module.exports = {
      entry: 'index.js',
      output: {
        path: path.resolve(__dirname, './dist'),
        filename: 'index_bundle.js',
      },
      plugins: [new HtmlWebpackPlugin({
           // 模板,以pubilc/index.html为模板创建新的文件
          // 新的html文件特点;1.结构和原来一致2.自动引入打包的js文件
          template: path.join(__dirname, 'pubilc/index.html')
      })],
    };
    
开发服务器&自动化

因为每次代码需要手动输入指令才能编译代码

  1. 下载包

    • npm i webpack-dev-server -D
  2. webpack配置

        // 开发服务器。不会输出任何资源,在内存中编译打包的
        devServer:{
            host: 'localhost', // 域名
            port: '3000',  //端口
            open: true, // 是否自动打开浏览器
        },
    
  3. 启动服务npx webpack server

生产模式
  1. 注意:

    • 在开发文件中所有的绝对路径都要添加上一级目录。'../'
    • 开发环境输入文件的路径可以为空,因为是试内存中进行编译的
    • 自动删除dist文件可以为false
  2. 启动不同的配置文件命令:

    • npx webpack serve --config ./config/webpack.dev.js
    • npx webpack --config ./config/webpack.prod.js
  3. 在package文件中配置启动文件快捷命令

      "scripts": {
        "start": "npm run dev",
        "dev": "webpack serve --config ./config/webpack.dev.js",
        "build":"webpack  --config ./config/webpack.prod.js"
      },
    
  4. 开发和生产环境webpack文件具体配置

    • 开发

      // webpage基本配置
      const path = require('path');
      const ESLintPlugin = require('eslint-webpack-plugin');
      const HtmlWebpackPlugin = require('html-webpack-plugin');
      module.exports = {
          // 相对路径
          entry: './src/main.js',
          output: {
              // 生产环境可以为undefined,没有输出。输出路径。绝对路径
              path: undefined, // __dirname代表当前文件的目录
              // js文件打包路径
              filename: 'static/js/main.js',
              // 自动清空上次打包结果
              // clean:true,
          },
          module: {
              rules: [
                  // loader配置
                  {
                      test: /.css$/, // 只检测以.css结尾的文件,
                      use: [
                          'style-loader',
                          'css-loader'  // 将css资源编译成commonjs的模块到js中
                      ],  // 从下往上解析
                  },
                  {
                      test: /.less$/, // 只检测以.less结尾的文件,
                      use: [
                          'style-loader',
                          'css-loader',
                          'less-loader'
                      ],
                  },
                  {
                      test: /.s[ac]ss$/, // 只检测以.sass结尾的文件,
                      use: [
                          'style-loader',
                          'css-loader',
                          'less-loader',
                          'sass-loader'
                      ],
                  },
                  {
                      test: /.styl$/, // 只检测以.sass结尾的文件,
                      use: [
                          'style-loader',
                          'css-loader',
                          'less-loader',
                          'sass-loader',
                          'stylus-loader'
                      ],
                  },
                  {
                      test: /.(png|jpe?g|svg| gif| webg)$/, // 图片格式
                      type: 'asset',
                      parser:{
                          dataUrlCondition: {
                              // 小于10kb 的转base64
                              maxSize: 10 * 1024
                          }
                      },
                      generator: {
                          filename: "imgs/[hash:8][ext][query]",
                      }
                  },
                  {
                      test: /.(ttf|woff2? | mp3 | mp4)$/, // 图片格式
                      type: 'asset/resource',
                      generator: {
                          filename: "fonts/[hash:8][ext][query]",
                      }
                  },
                  {
                      test: /.m?js$/,
                      exclude: /(node_modules|bower_components)/, // 排除的文件名称
                      use: {
                        loader: 'babel-loader',
                      //   options: {
                      //     presets: ['@babel/preset-env']
                      //   }
                      }
                  }
              ]
          },
          // 插件
          plugins: [
              new ESLintPlugin({
                  context: path.resolve(__dirname, '../src'), 
              }),
              new HtmlWebpackPlugin({
                  // 模板,以pubilc/index.html为模板创建新的文件
                  // 新的html文件特点;1.结构和原来一致2.自动引入打包的js文件
                  template: path.join(__dirname, '../pubilc/index.html')
              })
          ],
          // 开发服务器: 不会输出任何资源,在内存中编译打包的
          devServer:{
              host: 'localhost', // 域名
              port: '3000',  //端口
              open: true, // 是否自动打开浏览器
          },
          // 模式
          mode: 'development'
      }
      
  • 生产

    // webpage基本配置
    const path = require('path');
    const ESLintPlugin = require('eslint-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
        // 相对路径
        entry: './src/main.js',
        output: {
            // 输出路径。绝对路径
            path: path.resolve(__dirname, '../dist'), // __dirname代表当前文件的目录
            // js文件打包路径
            filename: 'static/js/main.js',
            // 自动清空上次打包结果
            clean:true,
        },
        module: {
            rules: [
                // loader配置
                {
                    test: /.css$/, // 只检测以.css结尾的文件,
                    use: [
                        'style-loader',
                        'css-loader'  // 将css资源编译成commonjs的模块到js中
                    ],  // 从下往上解析
                },
                {
                    test: /.less$/, // 只检测以.less结尾的文件,
                    use: [
                        'style-loader',
                        'css-loader',
                        'less-loader'
                    ],
                },
                {
                    test: /.s[ac]ss$/, // 只检测以.sass结尾的文件,
                    use: [
                        'style-loader',
                        'css-loader',
                        'less-loader',
                        'sass-loader'
                    ],
                },
                {
                    test: /.styl$/, // 只检测以.sass结尾的文件,
                    use: [
                        'style-loader',
                        'css-loader',
                        'less-loader',
                        'sass-loader',
                        'stylus-loader'
                    ],
                },
                {
                    test: /.(png|jpe?g|svg| gif| webg)$/, // 图片格式
                    type: 'asset',
                    parser:{
                        dataUrlCondition: {
                            // 小于10kb 的转base64
                            maxSize: 10 * 1024
                        }
                    },
                    generator: {
                        filename: "imgs/[hash:8][ext][query]",
                    }
                },
                {
                    test: /.(ttf|woff2 |woff | mp3 | mp4)$/, // 图标字体格式
                    type: 'asset/resource',
                    generator: {
                        filename: "fonts/[hash:8][ext][query]",
                    }
                },
                {
                    test: /.m?js$/,
                    exclude: /(node_modules|bower_components)/, // 排除的文件名称
                    use: {
                      loader: 'babel-loader',
                    //   options: {
                    //     presets: ['@babel/preset-env']
                    //   }
                    }
                }
            ]
        },
        // 插件
        plugins: [
            new ESLintPlugin({
                context: path.resolve(__dirname, '../src'),
            }),
            new HtmlWebpackPlugin({
                // 模板,以pubilc/index.html为模板创建新的文件
                // 新的html文件特点;1.结构和原来一致2.自动引入打包的js文件
                template: path.join(__dirname, '../pubilc/index.html')
            })
        ],
        // 生产模式不需要
        // // 开发服务器: 不会输出任何资源,在内存中编译打包的
        // devServer:{
        //     host: 'localhost', // 域名
        //     port: '3000',  //端口
        //     open: true, // 是否自动打开浏览器
        // },
        // 模式
        mode: 'production', // 生产模式
    }
    
生产环境Css文件处理
提取Css为单独文件

因为css文件和js文件打包在一起,当js加载时,会创建一个style标签来生成样式,这样会导致出现闪屏现象,体验不好,

应该单独打包css文件,通过link标签引入。

  1. 下载包: npm i mini-css-extract-pulgin --save-dev参考

  2. 在webpack中配置

    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    
    module.exports = {
      plugins: [new MiniCssExtractPlugin({
                filename: 'css/index.css' // 指定css文件打包后的路径
            })], 
      module: {
        rules: [
          {
            test: /.css$/i,
            use: [MiniCssExtractPlugin.loader, "css-loader"],// 将所有的style-loader换成这个MiniCssExtractPlugin.loader,
          },
        ],
      },
    };
    
css兼容性处理
  1. 下载包: npm i postcss-loader postcss postcss-preset-env -D。参考

  2. webpack 配置。需要在css-loader下面。less-loader上面进行填写

    // webpage基本配置
    const path = require('path');
    const ESLintPlugin = require('eslint-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    module.exports = {
        // 相对路径
        entry: './src/main.js',
        output: {
            // 输出路径。绝对路径
            path: path.resolve(__dirname, '../dist'), // __dirname代表当前文件的目录
            // js文件打包路径
            filename: 'static/js/main.js',
            // 自动清空上次打包结果
            clean:true,
        },
        module: {
            rules: [
                // loader配置
                {
                    test: /.css$/, // 只检测以.css结尾的文件,
                    use: [
                        MiniCssExtractPlugin.loader, // 提取css为单独文件
                        'css-loader', // 将css资源编译成commonjs的模块到js中
                        {
                            loader: 'postcss-loader',
                            options: {
                              postcssOptions: {
                                plugins: [
                                  [
                                    'postcss-preset-env',
                                    {
                                      // 其他选项
                                    },
                                  ],
                                ],
                              },
                            },
                        },
                    ],  // 从下往上解析
                },
                {
                    test: /.less$/, // 只检测以.less结尾的文件,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        {
                            loader: 'postcss-loader',
                            options: {
                              postcssOptions: {
                                plugins: [
                                  [
                                    'postcss-preset-env',
                                    {
                                      // 其他选项
                                    },
                                  ],
                                ],
                              },
                            },
                        },
                        'less-loader'
                    ],
                },
                {
                    test: /.s[ac]ss$/, // 只检测以.sass结尾的文件,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        {
                            loader: 'postcss-loader',
                            options: {
                              postcssOptions: {
                                plugins: [
                                  [
                                    'postcss-preset-env',
                                    {
                                      // 其他选项
                                    },
                                  ],
                                ],
                              },
                            },
                        },
                        'less-loader',
                        'sass-loader'
                    ],
                },
                {
                    test: /.styl$/, // 只检测以.sass结尾的文件,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        {
                            loader: 'postcss-loader',
                            options: {
                              postcssOptions: {
                                plugins: [
                                  [
                                    'postcss-preset-env',
                                    {
                                      // 其他选项
                                    },
                                  ],
                                ],
                              },
                            },
                        },
                        'less-loader',
                        'sass-loader',
                        'stylus-loader'
                    ],
                },
                {
                    test: /.(png|jpe?g|svg| gif| webg)$/, // 图片格式
                    type: 'asset',
                    parser:{
                        dataUrlCondition: {
                            // 小于10kb 的转base64
                            maxSize: 10 * 1024
                        }
                    },
                    generator: {
                        filename: "imgs/[hash:8][ext][query]",
                    }
                },
                {
                    test: /.(ttf|woff2 |woff | mp3 | mp4)$/, // 图标字体格式
                    type: 'asset/resource',
                    generator: {
                        filename: "fonts/[hash:8][ext][query]",
                    }
                },
                {
                    test: /.m?js$/,
                    exclude: /(node_modules|bower_components)/, // 排除的文件名称
                    use: {
                      loader: 'babel-loader',
                    //   options: {
                    //     presets: ['@babel/preset-env']
                    //   }
                    }
                }
            ]
        },
        // 插件
        plugins: [
            new ESLintPlugin({
                context: path.resolve(__dirname, '../src'),
            }),
            new HtmlWebpackPlugin({
                // 模板,以pubilc/index.html为模板创建新的文件
                // 新的html文件特点;1.结构和原来一致2.自动引入打包的js文件
                template: path.join(__dirname, '../pubilc/index.html')
            }),
            new MiniCssExtractPlugin({
                filename: 'css/index.css',
            })
        ],
        // 生产模式不需要
        // // 开发服务器: 不会输出任何资源,在内存中编译打包的
        // devServer:{
        //     host: 'localhost', // 域名
        //     port: '3000',  //端口
        //     open: true, // 是否自动打开浏览器
        // },
        // 模式
        mode: 'production', // 生产模式
    }
    
  3. 在package文件中配置css兼容程度,和scripts同级。

      "browserslist":[
        "ie>=8"
      ]
      
      开发常见配置
      "browserslist":[ // 同时满足
        "last 2 versions", // 所有浏览器的最后俩个版本
        "> 1%",  // 99%浏览器
        "not dead" // 版本死的不要
      ]
    

    就会出现兼容ie 8 的css代码

减少重复代码

// webpage基本配置
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

// loaderType为传入的loader类型。less sass
function getStyleLoader(loaderType) {
    return [
        MiniCssExtractPlugin.loader, // 提取css为单独文件
        'css-loader', // 将css资源编译成commonjs的模块到js中
        {
            loader: 'postcss-loader',
            options: {
                postcssOptions: {
                    plugins: [
                        [
                            'postcss-preset-env',
                            {
                                // 其他选项
                            },
                        ],
                    ],
                },
            },
        },
        loaderType, // 不传就会自动过滤掉
    ].filter(Boolean) // 将不Boolean自动过滤掉
}
module.exports = {
    // 相对路径
    entry: './src/main.js',
    output: {
        // 输出路径。绝对路径
        path: path.resolve(__dirname, '../dist'), // __dirname代表当前文件的目录
        // js文件打包路径
        filename: 'static/js/main.js',
        // 自动清空上次打包结果
        clean: true,
    },
    module: {
        rules: [
            // loader配置
            {
                test: /.css$/, // 只检测以.css结尾的文件,
                use: getStyleLoader(),  // 从下往上解析
            },
            {
                test: /.less$/, // 只检测以.less结尾的文件,
                use: getStyleLoader('less-loader'),
            },
            {
                test: /.s[ac]ss$/, // 只检测以.sass结尾的文件,
                use: getStyleLoader('sass-loader'),
            },
            {
                test: /.styl$/, // 只检测以.sass结尾的文件,
                use: getStyleLoader('stylus-loader'),
            },
            {
                test: /.(png|jpe?g|svg| gif| webg)$/, // 图片格式
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        // 小于10kb 的转base64
                        maxSize: 10 * 1024
                    }
                },
                generator: {
                    filename: "imgs/[hash:8][ext][query]",
                }
            },
            {
                test: /.(ttf|woff2 |woff | mp3 | mp4)$/, // 图标字体格式
                type: 'asset/resource',
                generator: {
                    filename: "fonts/[hash:8][ext][query]",
                }
            },
            {
                test: /.m?js$/,
                exclude: /(node_modules|bower_components)/, // 排除的文件名称
                use: {
                    loader: 'babel-loader',
                    //   options: {
                    //     presets: ['@babel/preset-env']
                    //   }
                }
            }
        ]
    },
    // 插件
    plugins: [
        new ESLintPlugin({
            context: path.resolve(__dirname, '../src'),
        }),
        new HtmlWebpackPlugin({
            // 模板,以pubilc/index.html为模板创建新的文件
            // 新的html文件特点;1.结构和原来一致2.自动引入打包的js文件
            template: path.join(__dirname, '../pubilc/index.html')
        }),
        new MiniCssExtractPlugin({
            filename: 'css/index.css',
        })
    ],
    // 生产模式不需要
    // // 开发服务器: 不会输出任何资源,在内存中编译打包的
    // devServer:{
    //     host: 'localhost', // 域名
    //     port: '3000',  //端口
    //     open: true, // 是否自动打开浏览器
    // },
    // 模式
    mode: 'production', // 生产模式
}
css压缩
  1. 下载插件 npm install css-minimizer-webpack-plugin --save-dev参考

  2. 在webpack中配置

    const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
    在plugins中注册
        plugins: [
            new CssMinimizerPlugin()
        ],
    
html压缩

默认生产环境已经开启了html和js压缩,不需要做额外的配置。

webpack高级

webpack高级其实就是进行优化,提升开发体验,提升打包速度,减少代码体积,优化代码运行性能

提升开发体验

有时候开发环境出现报错,控制台输出的文件都是打包之后的报错位置,非常不友好,可以使用sourceMap解决。

sourceMap(源代码映射):是一个用来生成源代码与构建代码映射的方案。它会生成一个xxx.map文件,里面包含源代码和构建后每行/每列的映射关系。当构建后代码出现错误,可以通过该文件快速定位错误位置。

使用 参考
  1. 开发模式 cheap-module-source-map

    • 优点:打包编译速度快,只包含行映射

    • 缺点:没有列映射

      devtool: 'cheap-module-source-map' //mode同级添加
      
  2. 生产模式 source-map

    • 优点:包含行/列映射

    • 缺点:打包编译速度更慢

      devtool: 'source-map'
      
  3. 注意:需要重启看效果

提升构建打包速度

模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:

  • 保留在完全重新加载页面期间丢失的应用程序状态。
  • 只更新变更内容,以节省宝贵的开发时间。
  • 在源代码中 CSS/JS 产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。
  • 该配置为默认配置
HMR使用 参考
  1. webpack基本配置
    devServer:{
        host: 'localhost', // 域名
        port: '3000',  //端口
        open: true, // 是否自动打开浏览器
        hot: true // 开启HML
    },
  1. 注意

    • css样式默认有热加载,js没有。

    • 也可以使用vue-loader和react-hot-loader来实现

Oneof使用

打包时每个文件都会经过所有的loader处理,虽然test正则没有匹配上,但是还是会经过,导致比较慢。开发和生产环境都可以配置

主要配置(开发环境为例):

        rules: [
            {
                // 每个文件只能被其中一个loader处理,不会全部都经过一遍
                oneOf: [
                    // loader配置
                    {
                        test: /.css$/, // 只检测以.css结尾的文件,
                        use: [
                            'style-loader',
                            'css-loader', // 将css资源编译成commonjs的模块到js中
                        ],  // 从下往上解析
                    },
                    {
                        test: /.less$/, // 只检测以.less结尾的文件,
                        use: [
                            'style-loader',
                            'css-loader',
                            'less-loader'
                        ],
                    },
                    {
                        test: /.s[ac]ss$/, // 只检测以.sass结尾的文件,
                        use: [
                            'style-loader',
                            'css-loader',
                            'less-loader',
                            'sass-loader'
                        ],
                    },
                    {
                        test: /.styl$/, // 只检测以.sass结尾的文件,
                        use: [
                            'style-loader',
                            'css-loader',
                            'less-loader',
                            'sass-loader',
                            'stylus-loader'
                        ],
                    },
                    {
                        test: /.(png|jpe?g|svg| gif| webg)$/, // 图片格式
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                // 小于10kb 的转base64
                                maxSize: 10 * 1024
                            }
                        },
                        generator: {
                            filename: "imgs/[hash:8][ext][query]",
                        }
                    },
                    {
                        test: /.(ttf|woff2? | mp3 | mp4)$/, // 图片格式
                        type: 'asset/resource',
                        generator: {
                            filename: "fonts/[hash:8][ext][query]",
                        }
                    },
                    {
                        test: /.m?js$/,
                        exclude: /(node_modules|bower_components)/, // 排除的文件名称
                        use: {
                            loader: 'babel-loader',
                            //   options: {
                            //     presets: ['@babel/preset-env']
                            //   }
                        }
                    }
                ]
            }
        ]
include/exclude

在处理js文件要排除node_modules文件。开发和生产环境都可以做。注意只能同时用一种,不然就会报错。

  1. webpack配置
                    {
                        test: /.js$/,
                        // exclude: /(node_modules|bower_components)/, // 排除node_modules的文件名称
                        include:path.resolve(__dirname, "../src"), // 只处理src下面的文件
                        use: {
                        }
                    }
      plugins: [
        new ESLintPlugin({
            context: path.resolve(__dirname, '../src'),
            exclude: 'node_modules' // 默认值
        }),
       ]
Cache

对eslint和babel编译结果进行缓存

  1. webpack配置

    {
        test: /.js$/,
            // exclude: /(node_modules|bower_components)/, // 排除node_modules的文件名称
            include:path.resolve(__dirname, "../src"), // 只处理src下面的文件
                use: {
                    loader: 'babel-loader',
                        options: {
                            cacheDirectory: true ,// 开启bable缓存
                                cacheCompression: false //关闭缓存文件压缩
                        }
                }
    },
    
        plugins: [
            new ESLintPlugin({
                context: path.resolve(__dirname, '../src'),
                exclude: 'node_modules', // 默认值
                cache: true, // 开启eslint缓存
                cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintCache') // 缓存路径
            }),
        ]
    
  2. 如果缓存成功就可以在node_modules下面看到一个.cache的文件

Thead

多线程提升js文件打包速度,也就是开启多喝线程同时干一件事情。每个进程开启时间大概为600ms,所以该方法比较适用于比较大的项目。开发和生产环境都可以配置。

  1. 获取cpu核数

  2. 下载包 npm i thread-loader -D

  3. webpack配置

    const os =require('os');
    const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
    const threads =os.cpus().length // cpu核数
    ​
                    {
                        test: /.?js$/,
                        // exclude: /(node_modules|bower_components)/, // 排除node_modules的文件名称
                        include:path.resolve(__dirname, "../src"), // 只处理src下面的文件
                        use: [
                            {
                                loader: 'thead-loader',  // 在前面进行处理
                            },
                            {
                                loader: 'babel-loader',
                                  options: {
                                    cacheDirectory: true ,// 开启bable缓存
                                    cacheCompression: false //关闭缓存文件压缩
                                    // presets: ['@babel/preset-env']
                                  }
                            }
                        ]
                    }
        // 插件
        plugins: [
            new TerserWebpackPlugin({
                parallel:threads  // 开启多进程和设置进程数量
            })
        ],
    
减少代码体积
Tree Shaking

开发的时候需要用到第三方库,有时候我们只会用到其中几个,所以将整个打包下来会导致体积很大。Tree Shaking用于移除js中没有用的代码。注意:它依赖es module。默认已经开启不需要做任何配置。

Babel

babel为编译的每一个文件都加入了辅助代码,使得体积过大。

babel对一些公共方法使用非常小的辅助代码,比如_extend。默认情况下会被添加到每一个需要他的文件中,我们可以将这些辅助代码作为一个独立模块,来避免重复使用。

  1. 下载包 npm i @babel/plugin-transform-runtime -D

    • 可以禁用babel对每个文件runtime注入,并可以使所有辅助代码从这里引用

    • 开发和生产环境都可以配置

    1. webpack配置

                          {
                                  loader: 'babel-loader',
                                    options: {
                                      cacheDirectory: true ,// 开启bable缓存
                                      cacheCompression: false, //关闭缓存文件压缩
                                      plugins: ['@babel/plugin-transform-runtime'] // 在babel使用
                                    }
                              }
      
image Minimizer

进行图片压缩,减少图片体积。只有本地图片才需要进行压缩。参考

  1. 下载包 npm install image-minimizer-webpack-plugin imagemin --save-dev

    • 无损压缩 npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
    • 有损压缩 npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo --save-dev
  2. webpack配置,以无损压缩为例

    const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
    ​
        // 所有有关压缩都在此配置
        optimizations:{
            // 压缩配置
            minimizer:[
                // 压缩图片
                new ImageMinimizerPlugin({
                    minimizer: {
                        implementation: ImageMinimizerPlugin.imageminGenerate,
                        options: {
                            plugins: [
                                ["gifsicle", { interlaced: true }],
                                ["jpegtran", { progressive: true }],
                                ["optipng", { optimizationLevel: 5 }],
                                [                                "svgo",                                {                                    plugins: [                                        'preset-default',                                        'prefixIds',                                        {                                            name: "sortAttrs",                                            params: {                                                xmlnsOrder: 'alphabetical'                                            }                                        }                                    ],
                                    },
                                ],
                            ],
                        },
                    }
                }),
            ]
        },
    
优化代码运行性能
code spilt

打包代码时会将所有的js文件打包到一个文件中,体积太大,如果我们只要渲染首页,就应该只加载首页对应的js文件。所以我们需要将打包生成的文件进行代码分割,生成多个文件,渲染那个页面就只加载那个js文件。

代码分割(code spilt) 参考

  1. 分割文件,将打包生成的文件进行分割,生成多个js文件
  2. 按需加载,需要哪个文件就加载那个文件

webpack配置多入口。使用 entry 配置手动地分离代码

  entry: {
    index: './src/index.js',
    main: './src/main.js',
  },
  
   output: {
     filename: '[name].bundle.js',  // [name]为webpack命名方式,文件名自己命名
     path: path.resolve(__dirname, 'dist'),
   },

公共代码单独打包成js,进行复用

 optimization: {
      // 代码分割配置
      splitChunks: {
        chunks: "all", // 对所有模块都进行分割
        // 以下是默认值
        // minSize: 20000, // 分割代码最小的大小
        // minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
        // minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
        // maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
        // maxInitialRequests: 30, // 入口js文件最大并行请求数量
        // enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
        // cacheGroups: { // 组,哪些模块要打包到一个组
        //   defaultVendors: { // 组名
        //     test: /[\/]node_modules[\/]/, // 需要打包到一起的模块
        //     priority: -10, // 权重(越大越高)
        //     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
        //   },
        //   default: { // 其他没有写的配置会使用上面的默认值
        //     minChunks: 2, // 这里的minChunks权重更大
        //     priority: -20,
        //     reuseExistingChunk: true,
        //   },
        // },
        // 修改配置
        cacheGroups: {
          // 组,哪些模块要打包到一个组
          // defaultVendors: { // 组名
          //   test: /[\/]node_modules[\/]/, // 需要打包到一起的模块
          //   priority: -10, // 权重(越大越高)
          //   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
          // },
          default: {
            // 其他没有写的配置会使用上面的默认值
            minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true,
          },
        },
      },
    },

按需加载,动态导入

第一种,也是推荐选择的方式是,使用符合 ECMAScript 提案import() 语法 来实现动态导入。

第二种,则是 webpack 的遗留功能,使用 webpack 特定的 require.ensure

写法,使用import动态引入js文件,改文件就会单独打包为一个js文件

    import('./js/count').then((res) =>{
        console.log('count', '‘成功');
    },() =>{
        console.log('count', '失败');
    });

单入口。其他都用默认值即可

 optimization: {
      // 代码分割配置
      splitChunks: {
        chunks: "all", // 对所有模块都进行分
      }
  }

动态导入文件命名

        // 动态引入
        import(/*webpackChunKName: 'math'*/ './js/sum').then(({sum}) => {
            console.log('sum', sum(1,2));
        },() =>{
            console.log('sum', '失败');
        })
        
        output: {
            // 输出路径。绝对路径
            path: path.resolve(__dirname, '../dist'), // __dirname代表当前文件的目录
            // js文件打包路径
            filename: 'static/js/main.js',
            chunkFilename: 'static/js/[name].js', // 指定动态导入文件的路径名称,[name]会对应上面的math
            // 自动清空上次打包结果
            clean: true,
        },

统一命名配置

    output: {
        // 输出路径。绝对路径
        path: path.resolve(__dirname, '../dist'), // __dirname代表当前文件的目录
        // js文件打包路径
        filename: 'static/js/[name].js',
        chunkFilename: 'static/js/[name].chunk.js',
        // 图片字体等统一处理文件名称
        assetModuleFilename: "static/media/[hash:8][ext][query]",
        // 自动清空上次打包结果
        clean: true,
    },

// 做了以上assetModuleFilename配置generator就可以不需要
{
     test: /.(ttf|woff2 |woff | mp3 | mp4)$/, // 图标字体格式
     type: 'asset/resource',
     // generator: {
         //     filename: "fonts/[hash:8][ext][query]",
         // }
},   

        new MiniCssExtractPlugin({
            filename: 'css/[name].css',
            chunkFilename: 'css/[name].chunk.css',
        })
...
Preload/Prefetch

如果用户点击时加载的资源太大,会导致卡顿效果。所以可以当浏览器空闲的时候加载后续的资源。

Preload: 告诉浏览器立即加载资源

Prefetch:空闲才加载资源

共同点:

  • 都会加载资源并不执行
  • 都有缓存

区别:

  • Preload优先级比较高,Prefetch优先级比较低
  • Preload只加载当前页面需要使用的资源,Prefetch可以加载当前页面资源,也可以加载下一个页面需要的资源。

总结:

  • 当页面优先级比较高的时候用Preload
  • 下一个页面需要使用资源用Prefetch

问题:

  • 兼容性比较差。参考
  • Preload兼容性比Prefetch

下载包 npm install --save-dev @vue/preload-webpack-plugin参考

webpack配置

      const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');
      new PreloadWebpackPlugin({
            rel: 'preload',
            as: 'script'
        })
      // 如果rel为Prefetch as属性就不需要。打包后实际为link标签。
network cache

当一个文件B发生变化,但是又不想用了B文件的A文件发生变化,可以在两者中间加一个runtime.js文件来解决。

  1.     new MiniCssExtractPlugin({
    
    ​      filename: 'css/[name].[contenthash:10].css',  // [contenthash:10]
    
    ​      chunkFilename: 'css/[name].chunk.[contenthash:10].css',
    
    ​    }),
    
  2. optimization: {
         // 生成runtime文件
         runtimeChunk: {
             name: (enwtrypoint) =>{
                 `runtimes: ${enwtrypoint}.js`
             }
         }
     },
    
core.js

可以解决js代码在低版本浏览器不兼容问题

core.js是专门用来做es6以及以上api的polyfill

polyfill翻译过来就是补丁。

  1. 下载: npm i core-js

  2. 在main.js手动全部引入

    import "core-js";
    
  3. 在main.js按需加载

    import "core-js/es/promise";
    
  4. 在babel-config.js配置自动引入

    // bable 配置文件
    module.exports = {
        // 智能映射,能够编译es6语法
        presets: [
            [
                '@babel/preset-env',
                {
                    useBuiltIns: 'usage',  // 按需自动加载core
                    corejs: 3 // 版本
                }
            ]
        ],
    }
    
PWA

渐进式网络应用程序:是一种可以提供类似于native app体验的web app技术,重要的是在离线时也可以持续运行,内部通过service

Workers技术实现

  1. 下载包npm install workbox-webpack-plugin --save-dev参考

  2. webpack配置

    const WorkboxPlugin = require('workbox-webpack-plugin');
    new WorkboxPlugin.GenerateSW({
           // 这些选项帮助快速启用 ServiceWorkers
           // 不允许遗留任何“旧的” ServiceWorkers
           clientsClaim: true,
           skipWaiting: true,
         }),
    
  3. main引入

     if ('serviceWorker' in navigator) {
       window.addEventListener('load', () => {
         navigator.serviceWorker.register('/service-worker.js').then(registration => {
           console.log('SW registered: ', registration);
         }).catch(registrationError => {
           console.log('SW registration failed: ', registrationError);
         });
       });
     }
    

注:如有错误欢迎指正,一起学习!!!