需要安装的模块

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "serve": ""
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.23.9",
    "@babel/preset-env": "^7.23.9",
    "add-asset-html-webpack-plugin": "^6.0.0",
    "autoprefixer": "^10.4.17",
    "babel-loader": "^9.1.3",
    "css-loader": "^6.10.0",
    "css-minimizer-webpack-plugin": "^6.0.0",
    "csv-loader": "^3.0.5",
    "dart-sass": "^1.25.0",
    "html-webpack-plugin": "^5.6.0",
    "imports-loader": "^5.0.0",
    "json5": "^2.2.3",
    "mini-css-extract-plugin": "^2.8.0",
    "postcss-loader": "^8.1.0",
    "sass-loader": "^14.1.0",
    "style-loader": "^3.3.4",
    "terser-webpack-plugin": "^5.3.10",
    "toml": "^3.0.0",
    "ts-loader": "^9.5.1",
    "typescript": "^5.3.3",
    "webpack": "^5.90.0",
    "webpack-bundle-analyzer": "^4.10.1",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1",
    "webpack-merge": "^5.10.0",
    "xml-loader": "^1.2.1",
    "yaml": "^2.3.4"
  },
  "dependencies": {
    "lodash": "^4.17.21",
    "rgb-random-lazychild": "^1.0.2"
  },
  "browserslist": ["> 1%", "last 2 versions"]
}

基本命令

"scripts": {
    "serve": "webpack serve --config webpack.config.js",
    "build": "webpack --config webpack.config.js"
}

基本配置

webpack 的配置文件为:webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./src/index.js", //以哪个文件为主

  output: {
    // filename: '[name].[contenthash].js',
    filename: "index.js",
    path: path.resolve(__dirname, "./dist"), //绝对路径
    clean: true, //清理上次打包的文件
  },

  mode: "development", // 指定运行模式为开发模式

  devtool: "eval-cheap-module-source-map",

  plugins: [
    new HtmlWebpackPlugin({
      template: "./index.html",
      filename: "app.html",
      inject: "body", //在body里面生成script标签
    }),
  ],

  // 配置热更新服务器
  devServer: {
    static: "./dist",
  },
};

静态资源处理

1.处理图片文件

asset/resource:

module: {
  rules: [
    {
      //处理图片文件
      test: /\.png$/,
      type: "asset/resource", //类型
      // 路径
      generator: {
        filename: "images/[contenthash][ext]",
      },
    },
  ];
}

asset/inline:

module: {
  rules: [
    {
      //处理图片文件
      test: /\.svg$/,
      type: "asset/inline", //inline类型,将图片变为base64
    },
  ];
}

asset:

module: {
  rules: [
    {
      //处理图片文件
      test: /\.png$/,
      type: "asset", //类型:自动选择:默认如果大于8k-->本地资源,否则就是inline类型
      // 自定义
      parser: {
        dataUrlCondition: {
          maxSize: 4 * 1024 * 1024, //如果图片大于4M,那么就作为本地资源,否则就是inline类型
        },
      },
    },
  ];
}

2.处理纯文本

module: {
  rules: [
    {
      //处文本文件
      test: /\.txt$/,
      type: "asset/source", //类型
    },
  ];
}

3.处理字体文件

module: {
  rules: [
    {
      // 加载字体
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      type: "asset/resource",
      // 路径
      generator: {
        filename: "iconFont/[contenthash][ext]",
      },
    },
  ];
}

4.其它文件的处理

module: {
    rules: [
        {
            test: /\.toml$/,
            type: 'json',
            // 指定解析器
            parser: {
                parse: toml.parse,
            }
        },
        {
            test: /\.yaml$/,
            type: 'json',
            parser: {
                parse: yaml.parse,
            }
        },
        {
            test: /\.json5$/,
            type: 'json',
            parser: {
                parse: json5.parse,
            }
        },
        {
            test: /\.csv$/,
            use: 'csv-loader'
        },
        {
            test: /\.xml$/,
            use: 'xml-loader'
        }
    ],
},

babel-loader

这个可以将 ES6 转 ES5

// 需要安装的库
/**
 * 1. babel-loader: 用于处理es6语法
 * 2. @babel/core: babel核心库
 * 3. @babel/preset-env: babel预设库, 一组babel插件集合
 */
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: "babel-loader",
        options: {
          presets: ["@babel/preset-env"],
        },
      },
    },
  ];
}

代码分离

防止引入的第三方库重复导出

内置模块处理:

optimization: {
  splitChunks: {
    chunks: "all"; //对所有模块进行分割
  }
}

使用 dependOn:

module.exports = {
  // 多个入口文件
  entry: {
    index: {
      import: "./src/index.js",
      dependOn: "comment",
    },
    another: {
      import: "./src/another.js",
      dependOn: "comment",
    },
    comment: "lodash",
  },
};

预获取和预加载

预获取 prefetch: 在浏览器加载完必要的资源后,空闲时就会去获取可能需要的资源。 预加载 preload: 预先加载当前页面可能需要的资源, 它会与必要资源并行请求。

/* webpackPrefetch: true */
/* webpackPreload: true */

btn.addEventListener("click", () => {
  import(/* webpackPrefetch: true */ "./math").then(({ add }) => {
    console.log(add(4, 8));
  });
});

缓存第三方库

optimization: {
    splitChunks: {
        cacheGroups: {
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                        chunks: 'all'
            }
        }
    }
}

公共路径

output: {
    filename: 'index.js',
    path: path.resolve(__dirname, './dist'),   //绝对路径
    clean: true,  //清理上次打包的文件
    publicPath: 'http://127.0.0.1:5500/公共路径/dist/' //设置打包后的文件访问路径
},

动态改变 mode

module.exports = (env) => {
    mode: env.production ? 'production' : 'development', // 如果要压缩, 则需要生产环境
}

配置文件的拆分与合并

const { merge } = require("webpack-merge");

const configDev = require("./webpack.config.dev");
const configPro = require("./webpack.config.pro");
const configCommon = require("./webpack.config.common");

module.exports = (env) => {
  switch (true) {
    case env.development:
      return merge(configDev, configCommon);
    case env.production:
      return merge(configPro, configCommon);
    default:
      return new Error("No valid environment");
  }
};

路径别名

resolve: {
    alias: {
        '@': path.resolve(__dirname, './src')
    }
}

外部扩展

externalsType: "script",
externals: {
    jquery: [
        "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js",
        "$"
    ]
}

这样就可以直接使用了:

import $ from "jquery";
console.log($);

依赖分析图

使用插件:webpack-bundle-analyzer

const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); //依赖图插件
module.exports = {
  plugins: [new BundleAnalyzerPlugin()],
};

css 的自动兼容

module: {
  rules: [
    {
      test: /\.css$/,
      use: ["style-loader", "css-loader", "postcss-loader"],
    },
  ];
}

css 模块化

module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        "style-loader",
        {
          loader: "css-loader",
          options: {
            modules: true,
          },
        },
      ],
    },
  ];
}

解析 sass

module: {
  rules: [
    {
      // 加载css或者scss文件
      test: /\.(css|scss)$/,
      use: [
        "style-loader",
        "css-loader",
        {
          loader: "sass-loader",
          options: {
            implementation: require("dart-sass"),
          },
        },
      ], //顺序不能改,,从数组后往前进行加载
    },
  ];
}

抽离与压缩 css

需要生产环境

const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //提取css
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //压缩css
module.exports = {
  plugins: [
    // 提取css
    new MiniCssExtractPlugin({
      filename: "styles/[contenthash].css", //生成的css位置与css文件名字
    }),
  ],
  module: {
    rules: [
      {
        // 加载css或者scss文件
        test: /\.(css|scss)$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              implementation: require("dart-sass"),
            },
          },
        ], //顺序不能改,,从数组后往前进行加载
      },
    ],
  },
  optimization: {
    minimizer: [new CssMinimizerPlugin()], //压缩css
  },
};

压缩 js

需要生产环境

const terserPlugin = require("terser-webpack-plugin"); //压缩js
module.exports = {
  // 我们发现在使用了css压缩后,js不能进行自动压缩了,所以需要自己配置
  optimization: {
    minimizer: [
      new terserPlugin(), //压缩js
    ],
  },
};

解析 ts

module: {
  rules: [
    {
      test: /\.ts$/,
      use: "ts-loader",
    },
  ];
}

shimming 预置全局变量

const webpack = require("webpack");

module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      _: "lodash",
    }),
  ],
};

使用:

console.log(_.join([1, 2, 3], "~"));

将 this 指向为 window

module: {
  rules: [
    {
      test: /\.js$/,
      use: "imports-loader?wrapper=window",
    },
  ];
}

自建小轮子之 library

因为 webpack 打包后的文件都是一个自执行函数,在库外部的任何位置都访问不到它,所以需要配置 library

module.exports = {
  // 如果library的type为module时,必须配置
  experiments: {
    outputModule: true,
  },
  output: {
    library: {
      // type: "umd"
      type: "module",
    },
    globalObject: "globalThis", //解决在type: "umd"时,self未定义的问题
  },
};