Skip to content

Webpack 打包配置

约 3287 字大约 11 分钟

webpack

2025-08-29

Webpack 配置笔记

这份 Webpack 配置文件 (webpack.config.js) 旨在构建一个多页面前端项目。它详细配置了开发模式下的打包、各种资源的处理(JavaScript、CSS、图片、HTML、字体等),以及静态文件的复制。

0. 必要的依赖安装

在开始之前,请确保您的项目中安装了所有必需的 Webpack 及其相关的 Loader 和 Plugin。

npm install --save-dev \
  webpack webpack-cli webpack-dev-server \
  html-webpack-plugin copy-webpack-plugin \
  style-loader css-loader html-loader \
  babel-loader @babel/core @babel/preset-env \
  mini-css-extract-plugin # 用于生产环境提取 CSS

1. 核心配置 (Core Configuration)

  • path 模块引入:

    const path = require('path');
  • path 是 Node.js 内置模块,用于处理文件路径。path.resolve(__dirname, 'dist') 会将相对路径 'dist' 解析为绝对路径,确保在不同操作系统下都能正确找到输出目录。

  • 模式 (Mode):

    mode: 'development', // 或 'production'
    • development (开发模式):
      • 优化打包速度。
      • 提供更友好的调试信息。
      • 不进行代码压缩和优化,方便快速迭代。
      • 默认启用 NamedChunksPluginNamedModulesPlugin
    • production (生产模式):
      • 启用各种优化,如 Tree Shaking (摇树优化)、Scope Hoisting (作用域提升)。
      • 进行代码压缩和混淆 (通过 TerserPlugin,Webpack 5 内置)。
      • 默认启用 FlagDependencyExportsPluginFlagDependencyUsagePluginSideEffectsFlagPluginUglifyJsPlugin (Webpack 4) / TerserPlugin (Webpack 5)。
      • 构建时间通常更长,但输出文件体积更小,运行效率更高。
  • 入口 (Entry):

    entry: './src/index.js', // 入口文件
    • 指定 Webpack 构建依赖图的起点。所有依赖都会从这里开始被解析和打包。
    • 多页面应用考虑: 当前配置只有一个 JS 入口 (index.js),这意味着所有 HTML 页面都将共享这一个 JS Bundle。如果您的每个页面需要独立的 JavaScript 逻辑,您应该将 entry 配置为一个对象:
      // 示例:为每个页面配置独立的 JS 入口
      // entry: {
      //   index: './src/index.js',
      //   acquire: './src/acquire.js',
      //   preliminary: './src/preliminary.js',
      //   consult: './src/consult.js',
      //   generate: './src/generate.js',
      // },
      • 如果采用多入口,HtmlWebpackPluginchunks 选项将变得非常重要,用于指定每个 HTML 页面应该引入哪个 JS Bundle。
  • 输出 (Output):

    output: {
      filename: 'js/bundle.js', // 输出文件名,放在 js 目录下
      path: path.resolve(__dirname, 'dist'), // 输出目录
      clean: true, // 打包前清理 dist 目录
    },
    • filename: 定义打包后的 JavaScript 文件的命名规则。
      • 在当前单入口配置下,会生成 dist/js/bundle.js
      • 生产环境最佳实践: 为了更好的缓存控制,通常会使用 [name][contenthash]
        // filename: 'js/[name].[contenthash].js',
        // [name] 会根据 entry 的键名生成 (如果是多入口)
        // [contenthash] 会根据文件内容生成哈希值,内容不变哈希不变,利于浏览器缓存
    • path: 指定所有打包文件的输出目录为项目根目录下的 dist 文件夹。
    • clean: true: Webpack 5 新特性。 在每次打包前,自动清理 output.path 目录下的所有文件。这取代了之前常用的 clean-webpack-plugin

2. 开发服务器 (Development Server)

  • 开发工具 (Devtool):

    devtool: 'inline-source-map',
    • 配置 Source Map 的生成方式,用于调试。不同的值有不同的性能和准确性权衡:
      • eval: 最快,但映射到原始代码不够准确。
      • eval-source-map: 较快,准确性高,Source Map 以 Data URL 形式嵌入到 JS 文件中。
      • inline-source-map (当前配置): 类似于 eval-source-map,但 Source Map 包含在打包后的 JS 文件底部。
      • source-map: 独立生成 .map 文件,最准确,但构建速度最慢。
      • cheap-module-source-map: 不包含列信息,只包含行信息,构建速度较快,适用于大多数情况。
      • 推荐: 开发环境使用 eval-source-mapcheap-module-module-source-map,生产环境通常使用 source-map (或 hidden-source-map 以隐藏 Source Map,但结合错误报告工具使用)。
  • 开发服务器配置 (DevServer):

    devServer: {
      static: './dist', // Webpack 5 之前是 contentBase
      hot: true, // 启用热更新
      port: 8080, // 指定开发服务器端口
      open: true, // 启动后自动打开浏览器
      compress: true, // 启用 gzip 压缩
      // historyApiFallback: true, // 对于使用 HTML5 History API 的单页应用路由非常有用
      // proxy: { // 配置 API 代理,解决跨域问题
      //   '/api': 'http://localhost:3000',
      // },
    },
    • static: 指定开发服务器从哪个目录提供静态文件服务。
    • hot: true: 启用模块热替换 (Hot Module Replacement, HMR)。在开发过程中,当你修改代码时,Webpack 会在不刷新整个页面的情况下,只更新被修改的模块,极大地提高开发效率和用户体验。
    • port: 指定开发服务器监听的端口。
    • open: 在服务器启动后,自动在浏览器中打开页面。
    • compress: 启用 gzip 压缩,可以模拟生产环境的网络传输效果。

3. 模块规则 (Loaders - module.rules)

Loaders 用于处理非 JavaScript 文件(如 CSS、图片、HTML),将它们转换为 Webpack 可以处理的模块。

  • CSS 文件处理:

    {
      test: /\.css$/i,
      use: ['style-loader', 'css-loader'],
    },
    • test: /\.css$/i: 匹配所有以 .css 结尾的文件(不区分大小写)。
    • use: Loader 的执行顺序是从右到左(或从下到上)。
      • css-loader: 解释 CSS 文件中的 @importurl() 等语句,将 CSS 转换为 CommonJS 模块。
      • style-loader: 将 CSS 注入到 DOM 中(通过 <style> 标签),使样式生效。这适用于开发环境。
    • 生产环境优化: 在生产环境中,通常会将 CSS 提取到单独的文件中,以避免 FOUC (Flash Of Unstyled Content) 并利用浏览器缓存。这需要 mini-css-extract-plugin
      // 生产环境配置示例 (需要引入 MiniCssExtractPlugin)
      // {
      //   test: /\.css$/i,
      //   use: [MiniCssExtractPlugin.loader, 'css-loader'],
      // },
    • 预处理器支持: 如果使用 Less/Sass/Stylus,还需要添加相应的 Loader (如 less-loader, sass-loader)。
      // {
      //   test: /\.scss$/i,
      //   use: [
      //     'style-loader', // 或 MiniCssExtractPlugin.loader
      //     'css-loader',
      //     'sass-loader', // 处理 Sass/SCSS 文件
      //   ],
      // },
    • PostCSS: 推荐使用 postcss-loader 配合 autoprefixer 来自动添加 CSS 浏览器前缀。
      // {
      //   test: /\.css$/i,
      //   use: [
      //     'style-loader',
      //     'css-loader',
      //     'postcss-loader', // 添加 PostCSS 处理
      //   ],
      // },
  • JavaScript (ES6+) 文件处理 (Babel):

    • 这是一个非常重要的补充,因为现代 JavaScript 项目通常会使用 ES6+ 语法,需要 Babel 进行转译以兼容旧浏览器。
    {
      test: /\.m?js$/, // 匹配 .js 和 .mjs 文件
      exclude: /node_modules/, // 排除 node_modules 目录,提高编译速度
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'] // 根据目标环境自动配置 Babel 插件
        }
      }
    },
    • babel-loader: Webpack 和 Babel 之间的桥梁。
    • @babel/core: Babel 的核心库。
    • @babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript 语法,并根据您指定的目标浏览器或运行环境自动转换代码。
  • 图片资源处理:

    {
      test: /\.(png|svg|jpg|jpeg|gif)$/i,
      type: 'asset/resource', // 处理图片资源
      generator: {
        filename: 'asset/images/[hash][ext][query]' // 图片输出路径
      }
    },
    • test: /\.(png|svg|jpg|jpeg|gif)$/i: 匹配常见的图片文件格式。
    • type: 'asset/resource': 这是 Webpack 5 内置的 Asset Modules 类型之一。它会将资源文件复制到输出目录,并导出其 URL。
    • generator.filename: 定义图片资源的输出路径和命名规则。图片将被放置在 dist/asset/images/ 目录下,文件名将包含 hash 值、原始扩展名 (ext) 和查询参数 (query),以确保唯一性和缓存。
    • 其他 Asset Modules 类型:
      • asset/inline: 将资源作为 Data URI 注入到 Bundle 中(适用于小图标,减少 HTTP 请求)。
      • asset: 根据文件大小,自动选择 asset/resourceasset/inline (默认 8KB 阈值)。
      • asset/source: 导出资源的源代码(例如 SVG 文件)。
  • 字体文件处理:

    • 通常与图片处理类似,也属于静态资源。
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/i,
      type: 'asset/resource',
      generator: {
        filename: 'asset/fonts/[name][ext][query]' // 字体输出路径
      }
    },
  • HTML 文件处理:

    {
      test: /\.html$/i,
      loader: "html-loader",  // 处理 HTML 文件
    },
    • test: /\.html$/i: 匹配所有以 .html 结尾的文件。
    • loader: "html-loader": 将 HTML 文件导出为字符串。它的主要作用是解析 HTML 中的图片引用(例如 <img src="..." />),使其能够被 Webpack 的其他 Loader 处理(例如 asset/resource)。

4. 插件 (Plugins - plugins)

插件用于执行范围更广的任务,如优化、资源管理、注入环境变量等。

  • HtmlWebpackPlugin (多实例,用于生成多页面): 这个配置文件中使用了多个 HtmlWebpackPlugin 实例,每个实例负责生成一个独立的 HTML 文件。这非常适合构建多页应用。

    • 通用配置项解释:

      • template: 指定作为模板的 HTML 文件路径。
      • filename: 指定输出的 HTML 文件名,相对于 output.path
      • inject: 指定打包后的 JavaScript 和 CSS 文件注入到 HTML 的位置 (head, body, true (body), false)。
      • chunks (重要,针对多入口): 如果 entry 配置了多个 JS 入口,你需要用 chunks 选项来指定每个 HTML 页面应该引入哪些 JS Bundle。
        // 示例:如果 entry 配置为 { index: './src/index.js', acquire: './src/acquire.js' }
        // new HtmlWebpackPlugin({
        //   template: './src/view/index.html',
        //   filename: 'index.html',
        //   chunks: ['index'], // 只引入 index.js 打包的 JS
        // }),
        // new HtmlWebpackPlugin({
        //   template: './src/view/acquire.html',
        //   filename: 'acquire.html',
        //   chunks: ['acquire'], // 只引入 acquire.js 打包的 JS
        // }),
      • minify (生产环境): 在生产模式下启用 HTML 压缩。
        // minify: {
        //   removeComments: true, // 移除 HTML 注释
        //   collapseWhitespace: true, // 移除空格
        //   removeAttributeQuotes: true, // 移除属性的引号
        // },
      • title: 可以动态设置 HTML 的 <title> 标签内容。
    • 您的配置示例:

      new HtmlWebpackPlugin({ template: './src/view/index.html', filename: 'index.html', inject: 'body', }),
      new HtmlWebpackPlugin({ template: './src/view/acquire.html', filename: 'acquire.html', inject: 'body', }),
      // ... 其他页面
      • 这些配置确保了项目中的每个 HTML 页面都能被正确地处理,并自动引入打包后的 JavaScript 文件 (当前配置下是 bundle.js)。
  • CopyWebpackPlugin (复制静态资源):

    new CopyWebpackPlugin({ // 复制静态资源
      patterns: [
        { from: 'src/asset', to: 'asset' }, // 复制 src/asset 目录到 dist/asset
        { from: 'src/api', to: 'api' },     // 复制 src/api 目录到 dist/api
      ],
    }),
    • CopyWebpackPlugin 用于将不需要 Webpack 处理(例如不需要打包、压缩或转换)的静态文件直接复制到输出目录。
    • patterns: 定义要复制的文件或目录。
      • from: 源路径,相对于 Webpack 配置文件的目录。
      • to: 目标路径,相对于 output.path
    • 这通常用于复制字体文件、第三方库、JSON 数据、不需要经过模块化处理的图片或其他静态资源。
  • MiniCssExtractPlugin (生产环境提取 CSS):

    • 这个插件与上面提到的 CSS Loader 配合使用,用于将 CSS 从 JavaScript Bundle 中提取到单独的 .css 文件中。这有助于并行加载,并允许浏览器缓存 CSS。
    // 引入插件
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
    // 在 plugins 数组中添加
    // new MiniCssExtractPlugin({
    //   filename: 'css/[name].[contenthash].css', // 输出的 CSS 文件名
    //   chunkFilename: 'css/[id].[contenthash].css',
    // }),
    • 注意: 使用此插件时,CSS 规则中的 style-loader 需要替换为 MiniCssExtractPlugin.loader
  • webpack.DefinePlugin (定义全局常量/环境变量):

    • 允许您创建可在编译时配置的全局常量。这对于注入环境变量(如 API 地址、构建模式)非常有用。
    // const webpack = require('webpack'); // 如果没有引入过需要引入
    
    // new webpack.DefinePlugin({
    //   'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
    //   'process.env.API_BASE_URL': JSON.stringify('http://api.example.com'),
    //   // 可以在代码中直接使用 process.env.API_BASE_URL
    // }),

5. 项目结构建议

一个典型的多页面项目结构可能如下所示:

my-multi-page-app/
├── public/                     // 静态文件,如果不需要 Webpack 处理,可以直接放这里
│   └── favicon.ico
├── src/
│   ├── index.js                // 主入口 JS (或公共 JS)
│   ├── acquire.js              // acquire 页面专属 JS (如果采用多入口)
│   ├── preliminary.js          // preliminary 页面专属 JS
│   ├── styles/
│   │   ├── main.css            // 公共 CSS
│   │   └── _variables.scss     // Sass 变量
│   ├── view/
│   │   ├── index.html          // 首页模板
│   │   ├── acquire.html        // acquire 页面模板
│   │   ├── preliminary.html    // preliminary 页面模板
│   │   └── ...
│   ├── asset/
│   │   ├── images/
│   │   │   └── logo.png
│   │   └── fonts/
│   │       └── myfont.woff
│   └── api/                    // 静态 API 数据或模拟数据
│       └── data.json
├── dist/                       // Webpack 打包输出目录 (自动生成)
├── node_modules/
├── package.json
├── webpack.config.js
└── .babelrc                    // Babel 配置文件 (如果需要更复杂的 Babel 配置)

6. package.json 脚本

为了方便运行 Webpack 命令,通常会在 package.json 中定义脚本:

{
  "name": "my-app",
  "version": "1.0.0",
  "scripts": {
    "start": "webpack serve --mode development --open",
    "build": "webpack --mode production"
  },
  "devDependencies": {
    // ... 你的依赖
  }
}
  • npm start (或 yarn start): 启动开发服务器,在开发模式下进行热更新。
  • npm run build (或 yarn build): 在生产模式下进行打包,生成优化后的文件到 dist 目录。

7. 总结与最佳实践

  • 多页面应用: 仔细规划 entry 配置和 HtmlWebpackPluginchunks 选项,确保每个页面引入正确的 JavaScript 和 CSS。
  • 性能优化 (生产环境):
    • Tree Shaking: 确保 mode: 'production' 启用,并在 package.json 中设置 sideEffects: false 或精确指定有副作用的文件,以移除未使用的代码。
    • Code Splitting (代码分割): 通过配置 optimization.splitChunks 或使用动态 import() 语法,将公共模块或不常变化的模块单独打包,利用浏览器缓存。
    • Caching (缓存):output.filenameMiniCssExtractPlugin.filename 中使用 [contenthash],确保文件内容不变时哈希值不变,利于浏览器缓存。
    • 图片优化: 使用 image-minimizer-webpack-plugin 等插件在打包时压缩图片。
  • 环境变量: 使用 webpack.DefinePlugindotenv-webpack 插件管理不同环境下的配置。
  • 代码风格检查: 集成 ESLint (通过 eslint-webpack-plugin) 确保代码质量。
  • 打包分析: 使用 webpack-bundle-analyzer 插件可视化分析打包后的文件大小,找出优化点。