webpack

唐经国
2023-12-01

## webpack

- (webpack@4.41.6 webpack-cli@3.3.11)

下载(下载中注意版本问题)

  • 使用npm init初始化
  • 使用npm i webpack webpack-cli -g命令全局下载安装
  • 在使用npm i webpack webpack-cli -D 命令本地安装

webpack打包初体验

  • 使用命令webpack ./src/index.js -o ./build/build.js --mode=development
    • 命令解析:使用webpack 打包当前目录下的src目录下的index.js文件,打包后的文件输出到当前目录中的build文件夹下,文件名叫build.js,打包的模式使用开发模式
  • 使用命令webpack ./src/index.js -o ./build/build.js --mode=production
    • 命令解析:使用webpack 打包当前目录下的src目录下的index.js文件,打包后的文件输出到当前目录中的build文件夹下,文件名叫build.js,打包的模式使用生产模式(会压缩js代码)

webpack打包样式资源

  • 创建webpack.config.js

    • webpack的配置文件,指示webpack干那些活,运行webpack指令的时候会加载其中的配置,以配置去干活

    • 所有的构建工具都是基于nodejs平台运行的,模块化默认采用commonjs

    • const {resolve} = require('path');
      
      module.exports = {
          /*在这里面写webpack的配置*/
          //入口起点
          entry: './src/index.js', //输出
          output: {
              //指示输出的文件的名字
              filename: 'build.js', //输出的路径
              // __dirname ,node.js的变量,代表当前文件的绝对路径
              path: resolve(__dirname, 'build')
          }, // loader的配置
          module: {
              rules: [//详细的loader的配置
                  {
                      // 匹配那些文件
                      test: /\.css$/,
                      // 使用那些loader进行处理
                      use: [
                          // use数组的执行顺序,从下到上  依次执行
                          // 创建style标签,将js中的资源进行插入引用,添加到head中生效
                          'style-loader',
                          // 将css文件编程commonjs模块加载到css中,里面内容是样式字符串
                          'css-loader'
                      ]
                  },
                  {
                      // 匹配那些文件
                      test: /\.less$/,
                      // 使用那些loader进行处理
                      use: [
                          // use数组的执行顺序,从下到上  依次执行
                          // 创建style标签,将js中的资源进行插入引用,添加到head中生效
                          'style-loader',
                          // 将css文件编程commonjs模块加载到css中,里面内容是样式字符串
                          'css-loader',
                          // 将less文件编译成css文件
                          'less-loader'
                      ]
                  }
              ]
          },
          // plugins的配置
          plugins: [
              //详细的plugins配置
      
          ],
          // 模式
          mode: "development"
      };
      
  • 下载需要的loader配置 style-loader和css-loader

    • npm i style-loader@1.1.3 css-loader@3.4.2 -D(下载时注意版本,可以自己选择自己需要的版本)
    • npm i less-loader@5.0.0 -D
  • 直接通过webpack命令运行

webpack打包HTML资源

  • 编写webpack-config.js

    • const {resolve} = require('path');
      
      //引入html-webpack-plugin插件
      const HtmlWebpackPlugin = require('html-webpack-plugin');
      
      module.exports = {
      
          entry: './src/index.js',
          output: {
              //输出的filename
              filename: 'build.js',
              path: resolve(__dirname, "build")
          },
          //loader
          module: {
              rules: [
              ]
          },
          /*使用插件处理HTML资源,下载,引入,使用*/
          plugins: [
              //使用html-webpack-plugin插件,会自动创建一个空的HTML文件,并且会自动引入资源
              new HtmlWebpackPlugin({
                  // 复制路径对应的HTML文件机构,并且自动引入资源
                  template:'./src/index.html'
              })
          ],
          mode: 'development'
      
      }
      ;
      
  • 使用插件处理HTML资源

    • 下载插件,使用npm i html-webpack-plugin@3.2.0 -D 命令下载插件

    • 引入插件,使用commonjs,const HtmlWebpackPlugin = require(‘html-webpack-plugin’);

    • 使用插件,在plugin[]中 new HtmlWebpackPlugin ();

      • 此插件的功能:会创建一个空的HTML文件,自动引入打包输出的所有资源

        但是我们需要一个有结构的HTML文件,在new HtmlWebpackPlugin ({

        ​ template:'./src/index.html

        })---------->【传入参数,复制路径对应的HTML文件的结构】

webpack打包图片资源

  • 配置webpack.config.js

    • const {resolve} = require('path');
      //引入插件
      let htmlWebpackPlugin = require('html-webpack-plugin');
      module.exports = {
      
          //入口
          entry: './src/index.js',
          //输入
          output: {
              filename: 'build.js',
              path: resolve(__dirname, 'build')
          },
          //loader
          module: {
              rules: [
                  {
                      test: /\.less$/,
                      //使用多个loader
                      use: ['style-loader', 'css-loader', 'less-loader']
                  },
                  // 默认处理不了HTML中的img图片
                  {
                      test: /\.(jpg|png|gif|webp)$/,
                      //使用一个loader,下载url-loader 和 file-loader,因为url-loader依赖于file-loader
                      loader: 'url-loader',
                      options: {
                          // 如果图片大小小于8kb,就会被base64处理(8-12kb以下的图片应该给base64处理)
                          // 优点:减少请求数量(减轻服务器压力)
                          // 缺点:图片体积会更大(文件请求速度会更慢)
                          limit: 12 * 1024,
      
                          //url-loader是以ES6模块化解析的,而html-loader是commonjs模块化解析的
                          //解析时会出现问题:<img src="[object Module]" alt="小黄人">
                          // 解决:关闭url-loader的ES6模块化解析,使用commonJS解析
                          //    关闭ES6模块
                          esModule: false,
      
                          //如果觉得图片的名字太长,可以使用如下方法进行重命名
                          name: '[hash10].[ext]'
                      }
                  },
                  {
                      test: /\.html$/,
                      // 处理HTML文件中的img图片(负责引入img图片,从而能被url-loader处理图片)
                      loader: 'html-loader'
                  }
              ]
          },
      
          //插件
          plugins: [
              new htmlWebpackPlugin({
                  template: './src/index.html'
              })
          ],
      
          //模式
          mode: 'development'
      
      };
      
    • 下载url-loader file-loader,因为url-loader依赖于file-loader

    webpack打包其他资源

    • 配置webpack.config.js文件

      • const {resolve} = require('path');
        
        let htmlWebpackPlugin = require('html-webpack-plugin');
        module.exports = {
            entry: './src/index.js',
            output: {
                filename: 'build.js',
                path: resolve(__dirname, 'build')
            },
            module: {
                rules: [
                    {
                        test: /\.css$/,
                        use: ['style-loader', 'css-loader']
                    },
                    {
                        //除了这些文件
                        exclude: /\.(css|html|js|less)/,
                        loader: 'file-loader'
                    }
                ]
            },
            plugins: [
                new htmlWebpackPlugin({
                    template: './src/index.html'
                })
            ],
            mode: 'development'
        };
        
      • 注意打包字体图标需要引入对应的css文件和css文件对应的文件

    webpack-dev-server

    • 使用webpack-dev-server,需要下载包

      • npm i webpack-dev-server -D(根据自己的版本进行下载)
      • 由于是本地下载所以需要使用,npx webpack-dev-server启动
        • 上面直接运行webpack的原因是,webpack进行了 npm i webpack webpack-cli -g,全局安装所以可以直接使用webpack启动,但是webpack-dev-server没有全局安装,所以要使用npx来启动
      • 启动之后,通过localhost:设置的端口号来访问或者通过127.0.0.1:设置的端口号访问
    • 配置webpack.config.js

      • const {resolve} = require('path');
        
        let htmlWebpackPlugin = require('html-webpack-plugin');
        module.exports = {
            entry: './src/index.js',
            output: {
                filename: 'build.js',
                path: resolve(__dirname, 'build')
            },
            module: {
                rules: [
                    {
                        test: /\.css$/,
                        use: ['style-loader', 'css-loader']
                    },
                    {
                        //除了这些文件
                        exclude: /\.(css|html|js|less)/,
                        loader: 'file-loader'
                    }
                ]
            },
            plugins: [
                new htmlWebpackPlugin({
                    template: './src/index.html'
                })
            ],
            mode: 'development',
        
            /*
            * 配置DevServer,用来自动化,就不用每次修改源代码之后都要手动重新运行webpack指令打包
            * 自动编译,自动刷新浏览器,自动打开浏览器
            * 特点:是在内存中编译打包,不会有任何输出
            * 启动指令为:webpack-dev-server
            * 因为是本地下载,要启动本地的webpack-dev-server,要使用npx webpack-dev-server
            * */
            devServer: {
                //路径为打包后输出的路径
                contentBase: resolve(__dirname, 'build'),
                //启动gzip压缩
                compress: true,
                //端口号
                port: 3000,
                // 自动打开默认的浏览器
                open: true
            }
        };
        
        

开发环境的配置

  • 配置webpack.config.js文件

    • //引入绝对路径的包
      const {resolve} = require('path');
      //引入插件
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      module.exports = {
          //入口文件
          entry: './src/index.js', output: {
              //指定js文件输出到build目录下的js下,文件名为build.js
              filename: 'js/build.js', path: resolve(__dirname, 'build')
          }, module: {
              rules: [// 处理less文件
                  {
                      test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'],
                  }, // 处理css文件
                  {
                      test: /\.css$/, use: ['style-loader', 'css-loader']
                  }, //处理图片
                  {
                      test: /\.(gif|png|jpg|webp)$/, loader: 'url-loader', options: {
                          limit: 10 * 1024,
                          esModule: false,
                          name: '[hash:10].[ext]', // 指定图片资源输出到images目录下,less会编译成css文件和css文件一起输出到build.js文件中
                          outputPath: 'images'
                      }
                  }, // 负责引入图片
                  {
                      test: /\.html$/, loader: 'html-loader'
                  }, //处理其他资源
                  {
                      exclude: /\.(js|css|html|less|gif|jpg|png|webp)$/, loader: 'file-loader', options: {
                          outputPath: 'others'
                      }
      
      
                  }]
          }, plugins: [new htmlWebpackPlugin({
              template: './src/index.html'
          })],
      
          mode: 'development',
      
          //开发环境配置
          devServer: {
              contentBase: resolve(__dirname, 'build'), compress: true, port: 3000
              // open:true
          }
      
      };
      

将css文件单独提取成一个文件

  • 首先要用到插件 mini-css-extract-plugin

    • 使用命令npm i mini-css-extract-plugin -D 下载
  • 之后引入插件

    • let miniCss = require('mini-css-extract-plugin');
      
  • 使用插件

    • plugins: [
          new htmlWebpackPlugin({
              template: "./src/index.html"
          }),
          new miniCss({
              // 将提取出来的css文件输出到build/css/build.css
              filename: 'css/build.css'
          })
      ],
      
    • module: {
          rules: [
              {
                  test: /\.css$/,
                  use: [
                      // 创建style标签将样式放入HTML文件中
                      // 但是此时我们需要将css文件提取出来就不需要style-loader了
                      // 'style-loader',
                      //miniCss.loader,提取js文件中的css文件为单独的文件
                      miniCss.loader,
                      'css-loader'
                  ]
              }
          ]
      },
      
  • 完整的配置

    • const {resolve} = require('path');
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      let miniCss = require('mini-css-extract-plugin');
      
      module.exports = {
      
          entry: './src/js/index.js',
          output: {
              filename: 'js/build.js',
              path: resolve(__dirname, 'build')
          },
          module: {
              rules: [
                  {
                      test: /\.css$/,
                      use: [
                          // 创建style标签将样式放入HTML文件中
                          // 但是此时我们需要将css文件提取出来就不需要style-loader了
                          // 'style-loader',
                          //miniCss.loader,提取js文件中的css文件为单独的文件
                          miniCss.loader,
                          'css-loader'
                      ]
                  }
              ]
          },
          plugins: [
              new htmlWebpackPlugin({
                  template: "./src/index.html"
              }),
              new miniCss({
                  // 将提取出来的css文件输出到build/css/build.css
                  filename: 'css/build.css'
              })
          ],
          mode: 'development'
      
      };
      

css文件的兼容性处理

  • 会对一些具有兼容问题的css样式进行处理

  • 首先也要将css文件单独提取出来----步骤如上

  • 需要一个postcss-loader,和postcss-preset-env插件

    • 使用npm i postcss-loader postcss-preset-env -D 进行本地下载
  • {
        loader: "postcss-loader",
        options: {
            ident: 'postcss',
            plugins: () => [
                // postcss的插件
                //帮postcss找到package.json中browserslist里面的配置,
                // 通过配置加载指定的css兼容样式
                /*
                *   "browserslist": {
                        "development": [
                *        距离最近一个版本的谷歌浏览器
                          "last 1 chrome version",
                *        距离最近一个版本的火狐浏览器
                          "last 1 firefox version"
                        ],
                        "production": [
                          ">0.2%",
                          * 不要死了的浏览器
                          "not dead",
                          "not op_mini all"
                        ]
                      }
                * */
                require('postcss-preset-env')()
            ]
        }
    
    }
    
    • 在package.json中设置

      • "browserslist": {
          "development": [
            "last 1 chrome version",
            "last 1 firefox version"
          ],
          "production": [
            ">0.2%",
            "not dead",
            "not op_mini all"
          ]
        }
        
  • 完整配置

    • const {resolve} = require('path');
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      let miniCss = require('mini-css-extract-plugin');
      
      //设置nodejs环境变量为开发模式,因为默认会找开发模式的设置,所以这里要通过设置来改变
      // process.env.NODE_ENV = 'development';
      
      
      module.exports = {
      
          entry: './src/js/index.js',
          output: {
              filename: 'js/build.js',
              path: resolve(__dirname, 'build')
          },
          module: {
              rules: [
                  {
                      test: /\.css$/,
                      use: [
                          // 创建style标签将样式放入HTML文件中
                          // 但是此时我们需要将css文件提取出来就不需要style-loader了
                          // 'style-loader',
                          //miniCss.loader,提取js文件中的css文件为单独的文件
                          miniCss.loader,
                          'css-loader',
                          /*
                          * 处理css的兼容性问题需要一个loader和一个插件
                          * loader:postcss-loader
                          * 插件:postcss-preset-env
                          * */
                          //修改loader配置
                          {
                              loader: "postcss-loader",
                              options: {
                                  ident: 'postcss',
                                  plugins: () => [
                                      // postcss的插件
                                      //帮postcss找到package.json中browserslist里面的配置,
                                      // 通过配置加载指定的css兼容样式
                                      /*
                                      *   "browserslist": {
                                              "development": [
                                      *        距离最近一个版本的谷歌浏览器
                                                "last 1 chrome version",
                                      *        距离最近一个版本的火狐浏览器
                                                "last 1 firefox version"
                                              ],
                                              "production": [
                                                ">0.2%",
                                                * 不要死了的浏览器
                                                "not dead",
                                                "not op_mini all"
                                              ]
                                            }
                                      * */
                                      require('postcss-preset-env')()
                                  ]
                              }
      
                          }
      
                      ]
                  }
              ]
          },
          plugins: [
              new htmlWebpackPlugin({
                  template: "./src/index.html"
              }),
              new miniCss({
                  // 将提取出来的css文件输出到build/css/build.css
                  filename: 'css/build.css'
              })
          ],
          mode: 'development'
      
      };
      

压缩css文件

  • 下载插件optimize-css-assets-webpack-plugin

    • npm i optimize-css-assets-webpack-plugin -D 本地下载
  • 引入插件

    • let optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
      
  • 使用插件

    • plugins: [
          new htmlWebpackPlugin({
              template: "./src/index.html"
          }),
          new miniCss({
              // 将提取出来的css文件输出到build/css/build.css
              filename: 'css/build.css'
          }),
          //使用css压缩插件
          new optimizeCssAssetsWebpackPlugin()
      ],
      
  • 完整配置

    • const {resolve} = require('path');
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      let miniCss = require('mini-css-extract-plugin');
      //引入压缩css插件
      let optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
      
      
      //设置nodejs环境变量为开发模式,因为默认会找开发模式的设置,所以这里要通过设置来改变
      // process.env.NODE_ENV = 'development';
      
      
      module.exports = {
      
          entry: './src/js/index.js',
          output: {
              filename: 'js/build.js',
              path: resolve(__dirname, 'build')
          },
          module: {
              rules: [
                  {
                      test: /\.css$/,
                      use: [
                          // 创建style标签将样式放入HTML文件中
                          // 但是此时我们需要将css文件提取出来就不需要style-loader了
                          // 'style-loader',
                          //miniCss.loader,提取js文件中的css文件为单独的文件
                          miniCss.loader,
                          'css-loader',
                          /*
                          * 处理css的兼容性问题需要一个loader和一个插件
                          * loader:postcss-loader
                          * 插件:postcss-preset-env
                          * */
                          //修改loader配置
                          {
                              loader: "postcss-loader",
                              options: {
                                  ident: 'postcss',
                                  plugins: () => [
                                      require('postcss-preset-env')()
                                  ]
                              }
      
                          }
      
                      ]
                  }
              ]
          },
          plugins: [
              new htmlWebpackPlugin({
                  template: "./src/index.html"
              }),
              new miniCss({
                  // 将提取出来的css文件输出到build/css/build.css
                  filename: 'css/build.css'
              }),
              //使用css压缩插件
              new optimizeCssAssetsWebpackPlugin()
          ],
          mode: 'development'
      
      };
      
    • 压缩后的css文件

      • #box1{background-color:pink}#box1,#box2{display:flex;height:200px;width:200px}#box2{background-color:#ff1493}
        

js语法检查

  • 需要的的插件和loader

    • eslint
    • eslint-loader
    • eslint eslint-config-airbnb-base
    • eslint-plugin-import
      • 使用npm i eslint eslint-config-airbnb-base eslint-loader eslint-plugin-import -D 进行本地下载
    • 下载后不需要引入
  • rules里面的配置

    • {
          test: /\.js$/,
          //由于第三方库的代码不用检查,所以使用exclude排除第三方的库的代码
          exclude: /node_modules/,
          loader: 'eslint-loader',
          options: {
              // 自动修复eslint的错误(会自动修改js文件的格式)
              fix: true
          }
      
  • package.json 里面的配置

    • "eslintConfig": {
        "extends": "airbnb-base"
      }
      
  • 完整的 webpack.config 配置

    • const {resolve} = require('path');
      
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      module.exports = {
      
          entry: './src/js/index.js',
          output: {
              filename: 'js/build.js',
              path: resolve(__dirname, 'build')
          },
          module: {
              rules: [
                  /*
                      * 语法检查 eslint-loader eslint
                  *
                  * 只检查源代码,第三方库不用检查
                  *
                  * 在package.json里面设置检查规则
                  *   package.json中eslintConfig中设置
                  *
                  *         "eslintConfig": {
                  *               // 继承airbnb-base
                              "extends": "airbnb-base"
                            }
                  *
                  *   使用airbnb规则需要使用到eslint-config-airbnb-base eslint-plugin-import eslint,
                  *       上面也要使用eslint就一起下载了
                  *
                  * */
                  {
                      test: /\.js$/,
                      //由于第三方库的代码不用检查,所以使用exclude排除第三方的库的代码
                      exclude: /node_modules/,
                      loader: 'eslint-loader',
                      options: {
                          // 自动修复eslint的错误(会自动修改js文件的格式)
                          fix: true
                      }
                  }
              ]
          },
          plugins: [
              new htmlWebpackPlugin({
                  template: './src/index.html'
              })
          ],
          mode: 'development'
      
      };
      

js兼容性处理

  • 1.基本的js兼容性处理 --> babel-loader,@babel/preset-env

    • 存在的问题:只能转换一些基本的语法,如Promise就不能转换
  • 2.全部js的兼容性处理 --> @babel/polyfill

    • 存在的问题:将所有的兼容性代码引入,导致代码体积变大
    • 需要在入口文件中引入
      • //引入@babel/polyfill
        // import ‘@babel/polyfill’;
  • 3.按需求进行兼容处理 —> core-js(推荐使用)

    • 需要下载core-js

      • npm i core-js -D

      • {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            options: {
                // 预设,只是babel做怎么样的兼容性处理
                presets: [
                    [
                        '@babel/preset-env',
                        {
                            //设置按需加载
                            useBuiltIns: 'usage',
                            corejs: {
                                version: 3
                            },
                            //指定兼容性做到那个版本的浏览器
                            targets: {
                                chrome: '80',
                                firefox: '70',
                                edge:'12'
                            }
                        }
                    ]
                ]
            }
        }
        
  • 完整webpack.config.js配置

    • const {resolve} = require('path');
      
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      module.exports = {
      
          entry: './src/js/index.js',
          output: {
              filename: 'js/build.js',
              path: resolve(__dirname, 'build')
          },
          module: {
              rules: [
      
                  /*
                  * js兼容性处理,需要使用 babel-loader,@babel/preset-env
                  *
                  * 1.基本的js兼容性处理 --> babel-loader,@babel/preset-env
                  *   存在的问题:只能转换一些基本的语法,如Promise就不能转换
                  * 2.全部js的兼容性处理 --> @babel/polyfill
                  *   存在的问题:将所有的兼容性代码引入,导致代码体积变大
                  * 3.按需求进行兼容处理 ---> core-js
                  *
                  * */
      
                  {
                      test: /\.js$/,
                      //排除node_modules中的文件
                      exclude: /node_modules/,
                      loader: 'babel-loader',
                      options: {
                          // 预设,只是babel做怎么样的兼容性处理
                          presets: [
                              [
                                  '@babel/preset-env',
                                  {
                                      //设置按需加载
                                      useBuiltIns: 'usage',
                                      //指定corejs的版本
                                      corejs: {
                                          version: 3
                                      },
                                      //指定兼容性做到那个版本的浏览器
                                      targets: {
                                          chrome: '80',
                                          firefox: '70',
                                          edge:'12'
                                      }
                                  }
                              ]
                          ]
                      }
                  }
              ]
          },
          plugins: [
              new htmlWebpackPlugin({
                  template: './src/index.html'
              })
          ],
          mode: 'development'
      
      };
      

js文件压缩

  • 生产模式下自动压缩 js 文件

    • mode: 'production'
      

html文件压缩

  • 使用插件html-webpack-plugin

    • plugins: [
          new htmlWebpackPlugin({
              template: './src/index.html',
              // 压缩文件,至少需要两个参数
              minify: {
                  // 移除空格
                  collapseWhitespace: true,
                  // 移除注释
                  removeComments: true
              }
          })
      ],
      
  • 完整配置

    • const {resolve} = require('path');
      
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      module.exports = {
      
          entry: './src/js/index.js',
          output: {
              filename: 'js/build.js',
              path: resolve(__dirname, 'build')
          },
      
          plugins: [
              new htmlWebpackPlugin({
                  template: './src/index.html',
                  // 压缩文件,至少需要两个参数
                  minify: {
                      // 移除空格
                      collapseWhitespace: true,
                      // 移除注释
                      removeComments: true
                  }
              })
          ],
      
          mode: 'development'
      
      };
      

生产环境配置

  • const {resolve} = require("path");
    let htmlWebpackPlugin = require('html-webpack-plugin');
    let miniCss = require('mini-css-extract-plugin');
    
    //引入压缩css插件
    let optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
    
    //服用loader
    const loaderCss = {
        loader: 'postcss-loader',
        options: {
            ident: 'postcss',
            plugins: () => [
                require('postcss-preset-env')()
            ]
        }
    };
    
    module.exports = {
    
        entry: './src/js/index.js',
        output: {
            filename: 'js/build.js',
            path: resolve(__dirname, 'build')
        },
        module: {
            rules: [
    
                //处理less文件
                {
                    test: /\.less$/,
                    use: [
                        // 'style-loader',
                        miniCss.loader,
                        'css-loader',
                        loaderCss,
                        'less-loader'
                    ]
                },
    
                // 处理css文件
                {
                    test: /\.css$/,
                    use: [
                        miniCss.loader,
                        'css-loader',
                        // 对css兼容性做处理
                        loaderCss
                    ]
                },
    
                //处理图片文件
                {
                    test: /\.(png|gif|jpg|webp)$/,
                    loader: 'url-loader',
                    options: {
                        // 12kb以下的图片使用base64处理
                        limit: 12 * 1024,
                        esModule: false,
                        name: '[hash:10].[ext]',
                        //指定图片资源输出到images文件夹下
                        outputPath: 'images'
                    }
                },
    
                //处理HTML文件中的图片文件
                {
                    test: /\.html$/,
                    loader: 'html-loader'
                },
    
    
                /*
                * 一般来讲,一个文件只能被一个loader处理,
                *  当一个文件要被多个loader处理时,一定要指定loader的执行顺序
                *
                * 在这个配置中就要先执行 eslint , 在执行 babel
                *
                * 使用 enforce:'pre'; 优先执行
                *
                *
                * */
    
                //js语法检查
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'eslint-loader',
                    // 优先执行
                    enforce: 'pre',
                    options: {
                        fix: true
                    }
                },
    
                //js兼容性处理
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    useBuiltIns: 'usage',
                                    corejs: {
                                        version: 3
                                    },
                                    targets: {
                                        chrome: 80,
                                        firefox: 70,
                                        edge: '13'
                                    }
                                }
                            ]
                        ]
                    }
                },
    
    
                // 处理其他文件
                {
                    exclude: /.(less|css|html|js|img|jpg|png|gif|webp)$/,
                    loader: 'file-loader',
                    options: {
                        outputPath: 'others'
                    }
                }
    
            ]
        },
        plugins: [
    
    
            // css 兼容性处理
            new miniCss({
                filename: 'css/build.css'
            }),
    
            // 处理HTML文件
            new htmlWebpackPlugin({
                template: './src/index.html',
                // 压缩HTML文件
                minify: {
                    collapseWhitespace: true,
                    removeComments: true
                }
            }),
    
            // 压缩css文件
            new optimizeCssAssetsWebpackPlugin()
    
    
        ],
    
        mode: 'production'
    
    };
    

webpack性能优化

  • 开发环境优化

    • 优化打包构建速度
    • 优化代码调试
  • 生产环境优化

    • 优化构建打包速度
    • 优化代码运行的性能
  • HMR (热模块替换)

    • * HMR
      *   - 热模块替换
      *   - 一个模块发生变化时,只会重新打包这个模块,而不会将全部的模块重新打包,极大提高构建速度
      *
      *   样式文件
      *       - 可以使用HMR功能,是因为style-loader内部实现了
      *   js文件
      *       - 默认没有HMR功能
                  *       -if (module.hot) {
                              // 监听print.js文件的变化,一旦发生变化,其他代码不会重新打包构建,会执行后面的回调函数
                              module.hot.accept('./print.js', function () {
                                  // 重新将模块的行为调用
                                  print();
                              });
                          }
      *       - js文件只能处理非入口文件的其他文件
      *   HTML文件
      *       - 默认没有HMR功能,而且导致HTML文件不能热更新了(HTML文件不用做HMR功能)
      *       - 解决:将HTML文件放入起点入口中
      

source-map

  • 提供源代码到构建后代码映射技术

    • 如果构建够代码出错了,可以显示出错位置在源代码中的位置
  • * source-map
    *   - 外部
    *   - 错误代码的准确信息,源代码的错误位置
    *
    * inline-source-map
    *   - 生成一个内联的source-map
    *   - 错误代码准确信息,源代码的错误位置
    *
    * hidden-source-map
    *   - 错误代码的错误原因,没有源代码错误的位置
    *   - 不能追踪源代码的错误,只能提示构建后代码的错误位置
    *
    * eval-source-map
    *   - 内联
    *   - 每一个文件都生成对应的source-map,都在eval
    *   - 错误代码准确信息,源代码的错误位置
    *
    * nosources-source-map
    *   - 外部
    *   - 错误代码的准确信息,但是没有任何代码信息
    * cheap-source-map
    *   - 错误代码准确信息,源代码的错误位置
    *   - 不能精确到列,只能知道哪一行出错
    *
    * cheap-module-source-map
    *   - 错误代码准确信息,源代码的错误位置
    *   - module
    *
    
  • 完整配置

    • //引入绝对路径的包
      const {resolve} = require('path');
      //引入插件
      let htmlWebpackPlugin = require('html-webpack-plugin');
      
      module.exports = {
          //入口文件
          entry: ['./src/index.js', './src/index.html'],
          output: {
              //指定js文件输出到build目录下的js下,文件名为build.js
              filename: 'js/build.js', path: resolve(__dirname, 'build')
          }, module: {
              rules: [// 处理less文件
                  {
                      test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'],
                  }, // 处理css文件
                  {
                      test: /\.css$/, use: ['style-loader', 'css-loader']
                  }, //处理图片
                  {
                      test: /\.(gif|png|jpg|webp)$/, loader: 'url-loader', options: {
                          limit: 10 * 1024, esModule: false, name: '[hash:10].[ext]', // 指定图片资源输出到images目录下,less会编译成css文件和css文件一起输出到build.js文件中
                          outputPath: 'images'
                      }
                  }, // 负责引入图片
                  {
                      test: /\.html$/, loader: 'html-loader'
                  }, //处理其他资源
                  {
                      exclude: /\.(js|css|html|less|gif|jpg|png|webp)$/, loader: 'file-loader', options: {
                          outputPath: 'others'
                      }
      
      
                  }]
          }, plugins: [new htmlWebpackPlugin({
              template: './src/index.html'
          })],
      
          mode: 'development',
      
          //开发环境配置
          devServer: {
              contentBase: resolve(__dirname, 'build'), compress: true, port: 3000,
              // 开启HMR功能,
              // 当修改了webpack配置,新配置要生效,必须重启webpack服务
              /*
              * HMR
              *   - 热模块替换
              *   - 一个模块发生变化时,只会重新打包这个模块,而不会将全部的模块重新打包,极大提高构建速度
              *
              *   样式文件
              *       - 可以使用HMR功能,是因为style-loader内部实现了
              *   js文件
              *       - 默认没有HMR功能
                          *       -if (module.hot) {
                                      // 监听print.js文件的变化,一旦发生变化,其他代码不会重新打包构建,会执行后面的回调函数
                                      module.hot.accept('./print.js', function () {
                                          // 重新将模块的行为调用
                                          print();
                                      });
                                  }
              *       - js文件只能处理非入口文件的其他文件
              *   HTML文件
              *       - 默认没有HMR功能,而且导致HTML文件不能热更新了(HTML文件不用做HMR功能)
              *       - 解决:将HTML文件放入起点入口中
              *
              * */
              hot: true,
              // open:true
          },
      
          devtool: 'source-map'
      
      };
      

oneof

  • 使用oneof使所有的loader只会匹配一次

  • 完整配置

    • const {resolve} = require("path");
      let htmlWebpackPlugin = require('html-webpack-plugin');
      let miniCss = require('mini-css-extract-plugin');
      
      //引入压缩css插件
      let optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
      
      //服用loader
      const loaderCss = {
          loader: 'postcss-loader',
          options: {
              ident: 'postcss',
              plugins: () => [
                  require('postcss-preset-env')()
              ]
          }
      };
      
      module.exports = {
      
          entry: './src/js/index.js',
          output: {
              filename: 'js/build.js',
              path: resolve(__dirname, 'build')
          },
          module: {
              rules: [
                  //js语法检查
                  {
                      test: /\.js$/,
                      exclude: /node_modules/,
                      loader: 'eslint-loader',
                      // 优先执行
                      enforce: 'pre',
                      options: {
                          fix: true
                      }
                  },
      
                  {
                      // 以下loader只会匹配一个
                      // 不能有两个配置处理同一种类型的文件
                      // 将其中一个配置提取出去
      
                      oneOf: [
                          //处理less文件
                          {
                              test: /\.less$/,
                              use: [
                                  // 'style-loader',
                                  miniCss.loader,
                                  'css-loader',
                                  loaderCss,
                                  'less-loader'
                              ]
                          },
      
                          // 处理css文件
                          {
                              test: /\.css$/,
                              use: [
                                  miniCss.loader,
                                  'css-loader',
                                  // 对css兼容性做处理
                                  loaderCss
                              ]
                          },
      
                          //处理图片文件
                          {
                              test: /\.(png|gif|jpg|webp)$/,
                              loader: 'url-loader',
                              options: {
                                  // 12kb以下的图片使用base64处理
                                  limit: 12 * 1024,
                                  esModule: false,
                                  name: '[hash:10].[ext]',
                                  //指定图片资源输出到images文件夹下
                                  outputPath: 'images'
                              }
                          },
      
                          //处理HTML文件中的图片文件
                          {
                              test: /\.html$/,
                              loader: 'html-loader'
                          },
      
      
                          /*
                          * 一般来讲,一个文件只能被一个loader处理,
                          *  当一个文件要被多个loader处理时,一定要指定loader的执行顺序
                          *
                          * 在这个配置中就要先执行 eslint , 在执行 babel
                          *
                          * 使用 enforce:'pre'; 优先执行
                          *
                          *
                          * */
      
      
      
                          //js兼容性处理
                          {
                              test: /\.js$/,
                              exclude: /node_modules/,
                              loader: 'babel-loader',
                              options: {
                                  presets: [
                                      [
                                          '@babel/preset-env',
                                          {
                                              useBuiltIns: 'usage',
                                              corejs: {
                                                  version: 3
                                              },
                                              targets: {
                                                  chrome: 80,
                                                  firefox: 70,
                                                  edge: '13'
                                              }
                                          }
                                      ]
                                  ]
                              }
                          },
      
      
                          // 处理其他文件
                          {
                              exclude: /.(less|css|html|js|img|jpg|png|gif|webp)$/,
                              loader: 'file-loader',
                              options: {
                                  outputPath: 'others'
                              }
                          }
                      ]
                  }
              ]
          },
          plugins: [
      
      
              // css 兼容性处理
              new miniCss({
                  filename: 'css/build.css'
              }),
      
              // 处理HTML文件
              new htmlWebpackPlugin({
                  template: './src/index.html',
                  // 压缩HTML文件
                  minify: {
                      collapseWhitespace: true,
                      removeComments: true
                  }
              }),
      
              // 压缩css文件
              new optimizeCssAssetsWebpackPlugin()
      
      
          ],
      
          mode: 'production'
      };
      

缓存

  • babel缓存

    • 让第二次构建打包速度更快

    • 开启babel缓存

      • cacheDirectory: true

      • {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            options: {
                presets: [
                    [
                        '@babel/preset-env',
                        {
                            useBuiltIns: 'usage',
                            corejs: {
                                version: 3
                            },
                            targets: {
                                chrome: 80,
                                firefox: 70,
                                edge: '13'
                            }
                        }
                    ]
                ],
                // 开启babel缓存
                // 第二次构建时,会读取之前的缓存
                cacheDirectory: true
            }
        },
        
  • 文件资源缓存

    • 让上线代码缓存更好使用

    • 给文件名加上一个哈希值,使用的是webpack每次打包生成的哈希值

      •     // css 兼容性处理
            new miniCss({
                filename: 'css/build.[chunkhash:10].css'
            }),
        
    • hash:每次webpack构建时,会生成一个唯一的哈希值

      • 问题:因为js和css同时使用一个哈希值,如果重新打包,js文件的哈希值发生变化,css文件的哈希值也会发生变化,就会导致缓存都失效,(但是此时我却只改动一个文件,只想让改动过的文件的缓存失效)
    • chunkhash:根据chunk【Chunk是过程中的代码块】生成的哈希值。如果打包来源于同一个chunk,那么hash值就一样

      • 问题:因为css文件是在js文件中引入的,所以同属于一个chunk,所以最后的哈希值还是一样
    • contenthash,根据文件内容生成的哈希值,不同文件的哈希值一定不一样

tree shaking

  • 去除没有使用的代码
  • 前提
    • 必须使用ES6模块化
    • 开启production模式
  • 在package.json中配置
    • “sideEffects”: false,表示所有代码都没有副作用,都可以进行tree shaking,可能就会把css / @babel / polyfill(副作用文件)给干掉,所以得改变配置为:
      • “sideEffects”: [‘*.css’],这样就表示不对css文件进行tree shaking

代码分割

  • 第一种方式 ----->> 多入口的方式

    • 每个 entry 都会在最后的打包中输出一个对应的文件。因此可以显示地进行代码分割:

      • entry: {
            // 使用多入口的方式,来进行代码分割
            add: './src/js/add.js',
            reduce: './src/js/reduce.js'
        },
        
  • 第二种方式 ------>> splitChunks

    • 可以将node_modules中的第三方代码单独打包成一个chunk输出

    • 会自动分析多入口中,有没有公共的依赖,如果有会单独打包成一个chunk,不会重复打包

      • optimization: {
            splitChunks: {
                chunks: 'all'
            }
        },
        
  • 第三种方式 ------->> 动态导入模块

    • 在入口文件进行配置

    • import动态导入语法,能够将某个文件单独打包成一个chunk,将某个文件单独打包

    • /*
      * 通过js代码,能够将某个文件单独打包成一个chunk
      *   import动态导入语法,将某个文件单独打包
      *
      * 通过 注释 webpackChunkName:'add' 的方式给打包的文件制定名字
      *
      *
      * */
      
      import(/* webpackChunkName:'add' */'./add').then((module1) => {
          console.log(module.add(1, 2));
      }).catch(() => {
          console.log("加载失败");
      });
      
      import(/* webpackChunkName:'reduce' */'./reduce').then((module2) => {
          module2.reduce(32, 8);
      }).catch(() => {
          console.log("文件加载失败");
      });
      

懒加载和预加载

  • 懒加载

    • 使用第三种代码分割的语法

    • 在需要使用的时候才加载相关的资源文件

    • 在入口文件中使用js代码进行设置

      • // 懒加载,只有点击的时候,add.js 文件才会加载,不使用就不会进行加载
        document.getElementById('btn1').onclick = function () {
            // 使用 注释webpackChunkName:'add' 指定输出文件的名字为add,
            // webpackPrefetch:true , 设置预加载,等其他资源加载完毕然后在加载,但是不会显示在页面上
            //      等到使用的时候在显示在页面上
            import(/* webpackChunkName:'add' , webpackPrefetch:true */'./add').then((module1) => {
                console.log(module1.add(1, 2));
            }, (reason) => {
                console.log(reason);
            });
        };
        
        
        console.log('index.js文件被加载了');
        
  • 预加载

    • /* webpackPrefetch:true */,设置预加载
    • 将设置了预加载的相关资源文件提前加载好,加载完成不会立即在页面上生效,等到使用的时候才会显示在页面上

PWA(渐进式式网络开发应用程序)—(离线可以正常访问大部分资源)

  • 需要使用插件workbox

    • 下载插件 npm i workbox-webpack-plugin -D (本地下载)
  • 引入插件

    • let workbox = require(‘workbox-webpack-plugin’);
  • 使用插件,在plugins中进行如下配置:

    • //PWA
      new workbox.GenerateSW({
          /*
              1.帮助serviceworker快速启动
              2.删除旧的serviceworker
                  - 会帮助我们生成一个serviceworker的配置文件,通过配置文件注册serviceworker
                  - 注册:一般是在入口的js文件中作配置
           */
          clientsClaim: true,
          skipWaiting: true
      })
      
  • 注册 serviceworker

    • 在入口文件中配置

    • serviceworker 必须运行在服务器中

    •   1.eslint 不认识window,navigator全局变量
            解决:
             - 修改package.json中的eslintConfig配置为:
                     "env": {
                        "browser": true  // 设置支持浏览器端的全局变量
                      }  
                  
        2.serviceworker代码必须运行在服务器上面
             使用npm i serve -g 全局安装,快速生成一个简单的服务器
             启动命令:serve -s build,启动服务器,将build目录下的所有资源,作为静态资源暴露出去
      
      //注册serviceworker
      //使用if判断,serviceworker 这个属性是否存在
      if ('serviceWorker' in navigator) {
          window.addEventListener('load', () => {
              // 注册serviceworker
              let serviceWorkerRegistrationPromise = navigator.serviceWorker.register('/service-worker.js');
              // 监听 serviceworker 是否注册成功
              serviceWorkerRegistrationPromise.then(() => {
                  // 成功
                  console.log("注册成功");
              }).catch((reason) => {
                  // 失败
                  console.log("注册失败");
                  console.log(reason);
              });
          });
      }
      

多进程打包

  • 需要使用thread-loader

    • 下载 npm i thread-loader -D
  • 一般是给babel-loader使用

  • 在module中配置

    • 使用thread-loader开启多进程打包

    • 进程启动时间约为600ms,只有工作消耗时间比较长,才会使用多进程打包

    • 可以使用workers来调成进程

    • //js兼容性处理
                  {
                      test: /\.js$/,
                      exclude: /node_modules/,
                      use: [
                          {
                              // 开启多进程打包
                              loader: 'thread-loader',
                              options: {
                                  workers: 2 //2个进程
                              }
                          },
                          {
                              loader: 'babel-loader',
                              options: {
                                  presets: [
                                      [
                                          '@babel/preset-env',
                                          {
                                              useBuiltIns: 'usage',
                                              corejs: {
                                                  version: 3
                                              },
                                              targets: {
                                                  chrome: 80,
                                                  firefox: 70,
                                                  edge: '13'
                                              }
                                          }
                                      ]
                                  ]
                              }
                          }
                      ],
      
                  },
      

externals

  • 防止将某些包打包

  • // 拒绝jQuery被打包进来,打包时,忽略jQuery这个库
    externals: {
        jquery: 'jQuery'
    },
    
  • 忽略后,在HTML资源中要使用,要手动进行引入

dll

  • 会将node_modules中的库分别打包

  • 需要单独写一个dll配置文件

    • const {resolve} = require('path');
      
      const webpack = require('webpack');
      
      
      /*
      * 直接运行webpack,默认运行的是webpack.config.js文件
      *   而我们现在需要运行的是webpack.dll.js文件
      *       - 指令为:webpack --config webpack.dll.js
      *
      * */
      
      module.exports = {
      
          entry:{
              // jquery --- name为jQuery
              // [jQuery] --- 打包的库为jQuery
              jquery:['jQuery']
          },
          output:{
      
              filename:'[name].js',
              path:resolve(__dirname,'dll'),
              library:'[name]_[hash:5]' // 打包的库里面的内容向外暴露出去的内容叫什么名字
      
          },
      
      
      
          plugins:[
              // 生成一个manifest.json文件,提供和jQuery的映射关系
              new webpack.DllPlugin({
                  name:'[name]_[hash:5]', // 映射库暴露的内容的名称
                  path: resolve(__dirname,'dll/manifest.json') // 输出文件路径
              })
          ],
          mode:'production'
      
      
      };
      
  • 通过在webpack.config.js中的配置,来告诉webpack哪一些库不用打包了,引入已经打包过的库

    • 告诉webpack不用打包哪一个库,同时使用这个库的时候,名称也要改变

      • ​ 告诉webpack那些库不参与打包,同时使用的名称也需要改变
        • new webpack.DLLReferencePlugin({
          manifest:resolve(__dirname,‘dll/manifest.json’)
          }),
      • 引入已经打包的库
        • 需要使用插件add-asset-html-webpack-plugin
        • ​ // 将之前打包的jQuery资源引入
          ​ new addAssetHtmlPlugin({
          ​ filepath:resolve(__dirname,‘dll/jquery.js’)
          ​ })
    • 
      const {resolve} = require('path');
      
      const webpack = require('webpack');
      
      
      /*
      * 直接运行webpack,默认运行的是webpack.config.js文件
      *   而我们现在需要运行的是webpack.dll.js文件
      *       - 指令为:webpack --config webpack.dll.js
      *
      * */
      
      module.exports = {
      
          entry:{
              // jquery --- name为jQuery
              // [jQuery] --- 打包的库为jQuery
              jquery:['jQuery']
          },
          output:{
      
              filename:'[name].js',
              path:resolve(__dirname,'dll'),
              library:'[name]_[hash:5]' // 打包的库里面的内容向外暴露出去的内容叫什么名字
      
          },
      
      
      
          plugins:[
              // 生成一个manifest.json文件,提供和jQuery的映射关系
              new webpack.DllPlugin({
                  name:'[name]_[hash:5]', // 映射库暴露的内容的名称
                  path: resolve(__dirname,'dll/manifest.json') // 输出文件路径
              })
          ],
          mode:'production'
      
      
      };
      
 类似资料: