Webpack 配置基础

配置 Webpack,说白了就是给它一张行动地图。从入口到出口,中间跑什么 loader、挂什么 plugin,全在这一个文件里定。

我刚开始做前端工程化时,觉得配置就是个杂活。后来项目一复杂,才发现配置写得烂,后面改到哭。所以这章,咱们把配置的骨架讲透。

webpack.config.js 结构

一个典型的 webpack.config.js 长这样:

const path = require('path');

module.exports = {
  // 模式:development | production | none
  mode: 'development',
  // 入口:告诉 Webpack 从哪开始
  entry: './src/index.js',
  // 输出:打包后的文件放哪
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  // 模块规则:怎么处理各种文件
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  // 插件:扩展功能
  plugins: [],
  // 解析:模块路径查找规则
  resolve: {
    extensions: ['.js', '.jsx'],
  },
};

核心字段其实就几个:entry、output、module.rules、plugins、resolve。嗯,还有个 mode,它直接影响内置优化。

重点提醒:output.path 必须用路径,所以要用 path.resolve。我见过有人直接写字符串 `./dist`,开发时没问题,CI 里直接炸了。

多环境配置(dev / prod)

开发和生产环境,需求天差地别。开发要快、要 source map、要热更新;生产要小、要缓存、要压缩。怎么能只用一套配置搞定?

我的做法是:拆成三个文件——webpack.common.js、webpack.dev.js、webpack.prod.js。

不同环境的核心区别我用一个表格列出来,你一看就懂:

配置项 开发环境 生产环境
mode development production
devtool eval-cheap-module-source-map source-map(或不启用)
devServer hot, open, port 不配置
优化 最小化处理 压缩、tree-shaking、代码分割
文件名 bundle.js bundle.[contenthash].js

个人经验:开发环境我会把 devtool 设成 eval-cheap-module-source-map,编译快且报错定位准。以前用过 inline-source-map,结果每次热更新慢了一倍,后来就再也没敢用。

那么具体怎么拆分?接着往下看。

配置文件拆分与合并(webpack-merge)

拆分配置,就是用 webpack-merge 这个库把公共部分抽出来,环境特有部分单独写。说白了就是“公共 + 覆盖”。

最经典的结构:

build/
  webpack.common.js   // 公共:entry、output、loader、resolve
  webpack.dev.js      // 开发:devServer、devtool、mode
  webpack.prod.js     // 生产:优化、压缩、contenthash

举个例子,webpack.common.js:

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, '../dist'),
    clean: true,
  },
  module: {
    rules: [
      { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader' },
      { test: /\.css$/, use: ['style-loader', 'css-loader'] },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' }),
  ],
};

然后 webpack.dev.js:

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map',
  devServer: {
    port: 3000,
    hot: true,
    open: true,
  },
});

webpack.prod.js:

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'production',
  output: {
    filename: '[name].[contenthash].js',
  },
  optimization: {
    minimize: true,
    splitChunks: {
      chunks: 'all',
    },
  },
});

避坑指南:我曾经在合并时把两个配置的 output 里都写了 filename,结果 merge 会把后一个覆盖前一个。所以公共的 output.path 放 common,环境特有的 filename 放各自的配置里。

用 webpack-merge 的好处是:你不用再去手写深合并逻辑。它自动处理数组覆盖、对象合并,连 loader 顺序都能帮你整合。

你想想看,如果项目里还分了 test、staging 环境,就继续加 webpack.staging.js,还是用 merge 跟 common 合并。维护起来特别清爽。

核心结论:多环境配置 = 一份公共配置 + N 份环境配置,然后用 webpack-merge 粘起来。就这么简单。

Webpack 配置拆分与合并流程 公共配置 (common) entry, output, loader, resolve 开发配置 (dev) devServer, devtool 生产配置 (prod) 压缩, contenthash, 代码分割 webpack-merge 深度合并插件、loader、配置 最终配置 按环境输出不同 webpack 配置 dev: 快速构建 / prod: 极致优化 合并策略 后插入的相同字段会覆盖前者 合并到公共 按环境选择 按环境选择

你看这个流程,左边是三个独立的配置文件,经过 webpack-merge 这个“搅拌机”,出来一份完整的环境配置。开发时跑 webpack-dev-server --config webpack.dev.js,打包时跑 webpack --config webpack.prod.js。清晰又好维护。

最后,别忘了在 package.json 的 scripts 字段里加上环境参数:

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

这招我从第一个 Webpack 项目用到现在,不管项目多大,配置从来没乱过。希望对你有用。