我来帮你生成《包体构成分析实战教程》第4章的HTML正文内容。这是一份关于Webpack核心配置(entry、output、loader、plugin)的实战教程,以资深工程师口吻撰写,并包含一张内联SVG知识结构图。 ```html

第4章 Webpack 核心配置:entry、output、loader、plugin 的实战用法

如果你用过 Webpack,一定对这四个词不陌生:entry、output、loader、plugin。 说白了,它们就是 Webpack 打包的四根柱子。你只要把这四个东西搞明白,剩下的配置基本都是排列组合。

我个人习惯把 Webpack 想象成一条生产线——entry 是原材料入口,loader 是加工工序, plugin 是质检包装环节,output 是成品仓库。嗯,这个比喻不算严谨,但好记。

4.1 entry —— 打包的起点

entry 就是告诉 Webpack:"从哪个文件开始干活。" 所有依赖关系都从这里往外捋。有三种常见写法,我直接列出来:

  • 单入口(字符串):适合简单 SPA 或单页应用。
  • 多入口(对象):适合多页面应用,或需要分离 vendor 的场景。
  • 动态入口(函数):适合按需加载或条件判断的场景,用得相对少一些。
// 单入口 —— 最常见
module.exports = {
  entry: './src/index.js'
};

// 多入口 —— 我项目中常用,比如拆分管理后台和前台
module.exports = {
  entry: {
    main: './src/index.js',
    admin: './src/admin.js',
    vendor: ['react', 'react-dom']
  }
};

// 动态入口 —— 返回一个 Promise 或字符串
module.exports = {
  entry: () => './src/index.js'
};
💡 我的习惯:单入口用字符串,多入口用对象。动态入口我一般不用,除非要做灰度或多环境动态加载。 你想想,如果入口写死了,后面改起来多麻烦。

我在项目中遇到过一个问题:多入口打包时,忘了给每个入口配独立的 output.filename, 结果所有文件都叫 bundle.js,后面的直接把前面的覆盖了。 嗯,从那以后我再也不偷懒了。

4.2 output —— 打包的归宿

output 控制打包结果往哪放、叫什么名字。核心就三个字段,我挨个说。

  1. filename:输出文件的命名规则。
  2. path:输出目录的路径。
  3. publicPath:静态资源在 HTML 中引用的基础路径。
const path = require('path');

module.exports = {
  output: {
    // 我建议加上 contenthash,方便缓存控制
    filename: 'js/[name].[contenthash:8].js',
    // 输出到 dist 目录
    path: path.resolve(__dirname, 'dist'),
    // 如果部署到 CDN,这里填 CDN 地址
    publicPath: '/'
  }
};
⚠️ 踩坑实录:我曾经在生产环境忘了配 publicPath, 结果所有图片和字体都报了 404。因为打包后的资源路径是相对路径,而部署时静态资源放在了 CDN 子目录下。 记住:publicPath 不是写给本地看的,是写给服务器看的。

filename 里的 [contenthash] 是我个人最看重的配置。 为什么?因为只要文件内容不变,hash 就不变,浏览器就能放心用缓存。 你想想,如果每次部署文件名都一样,用户还得重新下载整个包,多亏。

4.3 loader —— 让 Webpack 理解所有文件

Webpack 原生只认识 JS 和 JSON。遇到 CSS、图片、字体、TypeScript 怎么办? 靠 loader。loader 就是一个"翻译官",把非 JS 文件转成 Webpack 能处理的模块。

常用 loader 我整理了一份:

文件类型 常用 loader 说明
JavaScript / JSX babel-loader 转译 ES6+ 和 React JSX
TypeScript ts-loader 或 babel-loader 我推荐用 babel-loader + @babel/preset-typescript
CSS css-loader + style-loader css-loader 解析 import,style-loader 注入页面
图片 / 字体 url-loader 或 asset module 小图转 base64,大图走文件
SCSS / LESS sass-loader / less-loader 配合 css-loader 一起用
module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        // 我建议一定加上 exclude,不然 node_modules 也会被转译,慢得离谱
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react']
          }
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(png|jpg|gif)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024 // 8KB 以下转 base64
          }
        }
      }
    ]
  }
};
💡 一个小经验:loader 的执行顺序是从右往左、从下往上。 比如 ['style-loader', 'css-loader'],先由 css-loader 解析 CSS, 再由 style-loader 插入页面。顺序写反了会直接报错。

4.4 plugin —— 打包流程的扩展

loader 管的是文件级别的转换,plugin 管的是打包流程的"大活儿"。 比如生成 HTML、压缩代码、提取 CSS、注入环境变量……这些 loader 做不了,得靠 plugin。

我项目中几乎必用的几个 plugin:

  • HtmlWebpackPlugin:自动生成 HTML,并注入打包后的 JS/CSS 链接。
  • MiniCssExtractPlugin:把 CSS 从 JS 中提取成独立文件,生产环境必用。
  • DefinePlugin:注入全局常量,比如 process.env.NODE_ENV。
  • CopyWebpackPlugin:复制静态资源到输出目录。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      // 多入口时可以指定 chunks
      chunks: ['main']
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css'
    })
  ]
};
⚠️ 注意:plugin 是实例化对象,要用 new 关键字。 我见过有人直接把 HtmlWebpackPlugin 扔进数组,没加 new, 结果 Webpack 直接报错。这种低级错误排查起来特别浪费时间。

📌 loader vs plugin —— 核心区别一张表

对比维度 loader plugin
定位 模块转换器(翻译官) 流程扩展器(指挥官)
作用范围 单个文件级别 整个打包流程
配置方式 module.rules 数组中配置 plugins 数组中实例化
典型场景 转译 JS、解析 CSS、加载图片 生成 HTML、提取 CSS、压缩代码
执行时机 在模块加载阶段执行 在打包生命周期各阶段执行
能否自定义 可以,但开发成本较高 可以,通过 Tapable 钩子机制

简单总结:loader 管"怎么读文件",plugin 管"怎么处理打包结果"。 两者不是替代关系,是协作关系。我见过不少新手把两者搞混,配置了半天就是不生效, 其实就是没搞明白这个区别。

下图梳理了 Webpack 核心配置的完整知识体系,你可以把它当作一张"配置地图":

Webpack 核心配置知识体系 entry 入口 单入口 (string) 多入口 (object) 动态入口 (function) loader 转换器 babel-loader css-loader + style-loader url-loader / asset module plugin 扩展器 HtmlWebpackPlugin MiniCssExtractPlugin DefinePlugin output 输出 filename 命名 path 目录 publicPath 基础路径 📌 核心流程:entry → loader → plugin → output loader 负责文件转换,plugin 负责流程扩展,两者协作完成整个打包任务。

✅ 第4章核心要点

  • entry:定义打包起点,支持单入口、多入口、动态入口三种写法。
  • output:控制输出文件的位置和命名,contenthash 是缓存利器。
  • loader:模块转换器,在 module.rules 中配置,注意执行顺序从右向左。
  • plugin:流程扩展器,在 plugins 中实例化,能干预打包全过程。
  • 两者不是二选一,而是 各司其职、协同工作。
🔧 给你一个实用建议:初学者可以先从单入口 + babel-loader + HtmlWebpackPlugin 练手, 跑通后再慢慢加多入口、CSS 提取、hash 命名这些高级配置。一口吃不成胖子,配置也一样。
```