WinddSnow

Webpack-Common-Loaders-and-Plugins

字数统计: 4.3k阅读时长: 19 min
2026/07/31

第81课:Webpack 常用 Loader 与 Plugin——css-loaderbabel-loaderHtmlWebpackPluginMiniCssExtractPlugin

上一课我们学习了 Webpack 的五大核心概念。本节课将深入到最常用的 LoaderPlugin 的具体配置与工作原理。在日常开发中,你不需要记住所有 Loader 和 Plugin 的细节,但必须熟练掌握以下高频组合:**babel-loader(ES6+ 转译)、css-loader + style-loader / MiniCssExtractPlugin(CSS 处理)、HtmlWebpackPlugin(HTML 生成)、postcss-loader(CSS 后处理)、sass-loader(预处理器)、ts-loader**(TypeScript 编译),以及资源处理(图片、字体)。本节课将逐一拆解它们的配置参数、链式调用机制以及常见配置陷阱,并通过实战案例展示如何在项目中高效组合它们。


1. css-loaderstyle-loaderMiniCssExtractPlugin

这三个工具协同工作,构成了 Webpack 处理 CSS 的核心流水线。

1.1 css-loader:解析 CSS 中的依赖关系

css-loader 的核心职责是处理 @importurl() 语句。它将这些 CSS 中的资源引用转换为 Webpack 可以理解的模块请求(require/import),使 CSS 能够被纳入依赖图中参与打包。css-loader 本身不会将 CSS 注入页面——它只是将 CSS 解析为 JavaScript 模块(一个包含 CSS 字符串的对象)。

1
2
3
4
5
6
7
8
9
10
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] // 先 css-loader 解析,再 style-loader 注入
}
]
}
};

关键配置选项

  • **modules**:启用 CSS Modules。当设为 true 时,CSS 类名会被局部作用域化(自动生成唯一哈希),避免全局样式冲突。也可以设为对象进行精细控制。
1
2
3
4
5
6
7
8
9
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]--[hash:base64:5]', // 自定义类名格式
exportLocalsConvention: 'camelCase', // 将 kebab-case 转为 camelCase 导出
}
}
}

CSS Modules 的典型用法:

1
2
3
4
5
/* Button.module.css */
.primaryButton {
background-color: blue;
color: white;
}
1
2
import styles from './Button.module.css';
// styles.primaryButton 为 'Button__primaryButton--a1b2c'
  • **importLoaders**:指定在 css-loader 之前还有多少个 Loader 需要处理 @import 引入的 CSS 文件。这个配置常被忽视但非常重要。当你在 CSS 文件中 @import 'another.css' 时,被导入的 CSS 默认不会再经过 postcss-loadersass-loader 的处理。设置 importLoaders: 1 可确保 @import 的文件也会被前一个 Loader(如 postcss-loader)处理。
1
2
3
4
5
6
7
8
use: [
'style-loader',
{
loader: 'css-loader',
options: { importLoaders: 1 } // 确保 @import 的文件也经过 postcss-loader
},
'postcss-loader'
]

1.2 style-loader:将 CSS 注入 DOM

style-loadercss-loader 解析出的 CSS 字符串通过创建 <style> 标签注入到页面的 <head> 中。它还支持 HMR(热模块替换)——在开发模式下修改 CSS 文件后,页面无需刷新即可看到样式变化。

style-loader 仅在开发环境使用。在生产环境中,应该使用 MiniCssExtractPlugin 将 CSS 提取为独立的 .css 文件,以便浏览器并行加载、缓存,并避免 JS 执行后才应用样式导致的“闪白”问题。

1.3 MiniCssExtractPlugin:提取 CSS 为独立文件

MiniCssExtractPlugin 将 CSS 从 JavaScript bundle 中抽取出来,生成独立的 .css 文件。它提供 MiniCssExtractPlugin.loader,在生产环境中替换 style-loader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';

return {
module: {
rules: [
{
test: /\.css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader'
]
}
]
},
plugins: [
isProduction && new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css'
})
].filter(Boolean)
};
};

工作流程对比

阶段 style-loader 开发模式 MiniCssExtractPlugin 生产模式
CSS 所在 嵌入在 JS bundle 中,运行时注入 <style> 独立的 .css 文件。
加载速度 JS 执行后才显示样式(可能闪白)。 CSS 与 JS 并行下载,浏览器提前渲染样式。
缓存 无法单独缓存 CSS。 可对 CSS 文件进行独立版本控制和缓存。
HMR 支持 ✅ 原生支持。 ❌ 需额外配置(通常开发环境不使用)。

2. babel-loader:JavaScript 编译器

babel-loader 是 Webpack 与 Babel 之间的桥梁。Babel 将现代 JavaScript(ES6+)转译为向后兼容的版本,使代码能在旧浏览器中运行。

2.1 基础配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
}
]
}
};

预设(Preset) 是一组预先配置好的插件集合。

  • **@babel/preset-env**:根据目标环境(browserslist 配置)自动确定需要转译的 ES 语法和 polyfill。无需手动逐个添加插件。
  • **@babel/preset-react**:处理 JSX 语法,自动注入 React 的 import(可配置 runtime: 'automatic' 启用 React 17+ 的新 JSX 转换)。
  • **@babel/preset-typescript**:将 TypeScript 代码转译为 JavaScript(注意:Babel 仅移除类型注解,不做类型检查)。

2.2 独立的 Babel 配置文件

当 Babel 配置较复杂时,推荐将配置提取到 babel.config.js.babelrc 文件中,而非内嵌在 webpack.config.js 的 Loader 选项中。这使其他工具(如 Jest、ESLint)也能共享同一份 Babel 配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
targets: '> 0.5%, not dead', // 目标浏览器
useBuiltIns: 'usage', // 按需引入 polyfill
corejs: '3.32' // core-js 版本
}],
['@babel/preset-react', {
runtime: 'automatic' // React 17+ 新 JSX 转换
}]
]
};

webpack.config.js 中简化为:

1
2
3
4
5
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader'
}

2.3 useBuiltIns 与 polyfill

Babel 通过 core-js 提供 polyfill。useBuiltIns 选项控制 polyfill 的引入策略:

行为
false(默认) 不自动引入 polyfill,需手动 import 'core-js/stable'
'entry' 在入口文件引入 core-jsregenerator-runtime 后,根据目标环境替换为具体的 polyfill。
'usage' 按需自动引入:Babel 分析代码中使用的 ES 特性,仅引入实际需要的 polyfill。这是生产环境推荐的方式

使用 'usage' 时,无需在入口文件中手动 import 任何 polyfill,Babel 会自动为缺失的 API(如 PromiseArray.from)注入引用。这一特性极大地减小了打包产物的体积。


3. HtmlWebpackPlugin:HTML 生成

HtmlWebpackPlugin 的核心作用是生成或更新 HTML 文件,并自动将打包后的所有 JS 和 CSS 资源注入到 HTML 中。对于使用哈希文件名的生产构建,这是必需的——因为每次构建后生成的文件名都不同,你无法手动维护 <script> 标签的引用。

3.1 基础用法

1
2
3
4
5
6
7
8
9
10
11
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html', // 自定义 HTML 模板
title: 'My Application', // 设置 <title> 标签内容
favicon: './public/favicon.ico', // 网站图标
})
]
};

3.2 模板中的变量

template 指向的 HTML 文件中,可以使用 EJS 风格的变量插入(<%= htmlWebpackPlugin.options.title %>):

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>

3.3 多页面应用配置

HtmlWebpackPlugin 支持多次实例化,为每个入口生成独立的 HTML 页面(多页应用 MPA)。通过 chunks 属性指定该页面需要引入哪些入口 chunk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module.exports = {
entry: {
app: './src/app.js',
admin: './src/admin.js',
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './public/index.html',
chunks: ['app'] // 仅引入 app chunk
}),
new HtmlWebpackPlugin({
filename: 'admin.html',
template: './public/admin.html',
chunks: ['admin'] // 仅引入 admin chunk
})
]
};

4. postcss-loadersass-loader:CSS 后处理与预处理器

4.1 sass-loader:SCSS/Less 编译

sass-loader 将 SCSS/Sass 语法编译为标准 CSS。通常与 css-loaderstyle-loader(或 MiniCssExtractPlugin.loader)链式使用。执行顺序:sass-loadercss-loaderstyle-loader

1
2
3
4
5
6
7
8
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader' // 将 SCSS 编译为 CSS
]
}

全局变量注入:可以通过 additionalData 选项在每个 SCSS 文件的开头自动注入变量或 mixin:

1
2
3
4
5
6
{
loader: 'sass-loader',
options: {
additionalData: '@import "@/styles/variables.scss";'
}
}

这样所有 SCSS 文件都可以直接使用 variables.scss 中定义的变量,无需手动在每个文件中重复 import。

4.2 postcss-loader:CSS 后处理

PostCSS 是一个强大的 CSS 处理工具,通过插件实现各种功能。最常用的插件是 **autoprefixer**(自动添加浏览器前缀)和 **postcss-preset-env**(允许使用未来 CSS 语法,自动转译为当前可用的写法)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
['autoprefixer'],
['postcss-preset-env', { stage: 3 }]
]
}
}
}
]
}

推荐在项目根目录创建 postcss.config.js 统一配置:

1
2
3
4
5
6
7
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
require('postcss-preset-env')({ stage: 3 })
]
};

5. 其他常用 Loader 与 Plugin

工具 类型 功能
ts-loader Loader 编译 TypeScript(包含类型检查,比 babel-loader + TypeScript 慢)。
file-loader Loader 将文件复制到输出目录并返回 URL(Webpack 5 推荐用 type: 'asset/resource')。
CopyWebpackPlugin Plugin 将静态文件从源目录复制到输出目录,不参与打包。
CleanWebpackPlugin Plugin 在每次构建前清空输出目录(Webpack 5 可用 output.clean: true 替代)。
TerserWebpackPlugin Plugin 压缩 JavaScript(Webpack 5 内置,生产模式自动启用)。
CssMinimizerWebpackPlugin Plugin 压缩 CSS(Webpack 5 内置)。
BundleAnalyzerPlugin Plugin 生成交互式的打包体积分析图。
DefinePlugin Plugin 在编译时定义全局常量(如 process.env.API_URL)。

6. Loader 执行顺序与配置优化

6.1 链式调用规则

多个 Loader 作用于同一个文件时,按 use 数组中从后往前的顺序执行。对于 Webpack 5,推荐使用 use 数组而非 loader 字符串,因为后者不支持 options。

1
2
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']
// 执行顺序:sass-loader → postcss-loader → css-loader → style-loader

6.2 oneOf 避免重复匹配

当一个文件只需要匹配一组规则时,可以将规则放入 oneOf 数组中。一旦匹配到第一个规则,后续规则将被跳过,提升构建性能。

1
2
3
4
5
6
7
8
9
10
11
12
module: {
rules: [
{
oneOf: [
{ test: /\.module\.css$/, use: [...] },
{ test: /\.css$/, use: [...] },
{ test: /\.(png|jpg|gif)$/, type: 'asset' },
{ test: /\.[jt]sx?$/, loader: 'babel-loader' },
]
}
]
}

6.3 includeexclude:缩小 Loader 作用范围

指定 includeexclude 字段可以大幅减少 Loader 处理的文件数量,显著提升构建速度。

1
2
3
4
5
6
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'), // 只处理 src 目录
exclude: /node_modules/, // 排除 node_modules
loader: 'babel-loader'
}

7. 综合实战:一个完整的 Loader/Plugin 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = (env, argv) => {
const isProd = argv.mode === 'production';

return {
mode: isProd ? 'production' : 'development',
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[contenthash:8].js',
clean: true,
},

module: {
rules: [
{
oneOf: [
// 1. SCSS Modules
{
test: /\.module\.scss$/,
use: [
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
{ loader: 'css-loader', options: { modules: { localIdentName: '[name]__[local]--[hash:base64:5]' } } },
'postcss-loader',
{ loader: 'sass-loader', options: { additionalData: '@use "@/styles/variables.scss" as *;' } }
]
},
// 2. 普通 SCSS
{
test: /\.scss$/,
use: [
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'postcss-loader',
'sass-loader'
]
},
// 3. 图片与字体
{ test: /\.(png|jpe?g|gif|webp|svg)$/i, type: 'asset', parser: { dataUrlCondition: { maxSize: 8 * 1024 } } },
{ test: /\.(woff2?|eot|ttf|otf)$/i, type: 'asset/resource' },
// 4. JS/JSX
{ test: /\.[jt]sx?$/, exclude: /node_modules/, loader: 'babel-loader' }
]
}
]
},

plugins: [
new HtmlWebpackPlugin({ template: './public/index.html', title: 'My App' }),
isProd && new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' })
].filter(Boolean),

optimization: {
minimizer: [ '...', new CssMinimizerPlugin() ],
},

resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: { '@': path.resolve(__dirname, 'src') }
},

devServer: {
port: 3000,
hot: true,
historyApiFallback: true,
},

devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map',
};
};

课后练习

一、概念自测(选择题 / 填空题)

  1. (单选) 在 Webpack 中,css-loader 的核心职责是什么?
    A. 将 CSS 注入 DOM 的 <style> 标签。
    B. 解析 CSS 中的 @importurl(),将其转换为模块请求。
    C. 压缩 CSS 代码。
    D. 将 SCSS 编译为 CSS。

  2. (单选) 在生产环境中,为什么推荐用 MiniCssExtractPlugin.loader 替代 style-loader
    A. 因为 style-loader 不支持 HMR。
    B. 因为 MiniCssExtractPlugin.loader 可以将 CSS 提取为独立文件,便于浏览器缓存和并行加载。
    C. 因为 style-loader 不能与 css-loader 一起使用。
    D. 因为 MiniCssExtractPlugin.loader 处理速度更快。

  3. (填空) 在 Babel 的 @babel/preset-env 中,useBuiltIns: '______' 选项可以按需自动引入 polyfill,减小打包产物体积。

  4. (多选) 以下哪些是 PostCSS 的常见用途?
    A. 自动添加浏览器前缀(autoprefixer)。
    B. 将未来 CSS 语法转译为当前可用的写法(postcss-preset-env)。
    C. 将 SCSS 编译为标准 CSS。
    D. 压缩 CSS 代码。

二、AI 编程任务:编写面向 AI 的提示词

场景:你需要为一个 Webpack 5 项目配置 CSS 处理流水线。要求如下:

  • 支持 SCSS 文件。
  • 启用 CSS Modules(仅对 .module.scss 文件),类名格式为 [local]_[hash:base64:6]
  • 开发环境使用 style-loader 支持 HMR,生产环境使用 MiniCssExtractPlugin 提取 CSS 为独立文件。
  • 使用 postcss-loader + autoprefixer 自动添加浏览器前缀。
  • 使用 sass-loader,并配置 additionalData 为每个 SCSS 文件自动注入变量文件 @/styles/variables.scss
  • 配置 HtmlWebpackPlugin 生成 HTML。

任务要求:请写出一段完整的中文提示词,发送给 AI,使其生成符合上述要求的 webpack.config.js 配置。提示词中需明确指定 Loader 的执行顺序、环境区分策略和变量注入方式。

三、Agent 模式下的提示词示例

你是一个资深前端开发 Agent。请为一个 Webpack 5 项目创建 CSS 处理配置。需要生成以下文件:

  1. webpack.config.js
    • 导出一个函数,接收 (env, argv),通过 argv.mode === 'production' 判断环境。
    • entry: ./src/index.js,output: dist/,filename 带 [contenthash:8]
    • module rules 使用 oneOf:先匹配 .module.scss(启用 CSS Modules,localIdentName: '[local]_[hash:base64:6]'),再匹配普通 .scss。两个规则都使用 [MiniCssExtractPlugin.loader/ style-loader, css-loader, postcss-loader, sass-loader]
    • sass-loader 设置 additionalData: '@use "@/styles/variables.scss" as *;'
    • 创建 postcss.config.js,引入 autoprefixer
    • plugins: HtmlWebpackPlugin,生产环境 MiniCssExtractPlugin
    • optimization.minimizer: [ '...', new CssMinimizerPlugin() ]
  2. postcss.config.jsplugins: [ require('autoprefixer') ]
  3. 所有配置遵循 Webpack 5 最佳实践。完成后列出所有文件内容。

四、面试真题与参考答案

题目(字节跳动前端面试题):

请解释 Webpack 中 css-loaderstyle-loader 的分工,以及为什么在生产环境中通常用 MiniCssExtractPlugin.loader 替代 style-loadercss-loader 中的 importLoaders 选项有什么作用?请举例说明。

参考答案

css-loader 负责解析 CSS 中的 @importurl() 引用,将其转换为 Webpack 的模块请求,使 CSS 文件能够被纳入依赖图。style-loader 则将 css-loader 解析出的 CSS 字符串通过创建 <style> 标签注入到 DOM 中。两者的分工明确:前者解析模块关系,后者负责运行时注入。

在生产环境中,MiniCssExtractPlugin.loader 替代 style-loader,因为它将 CSS 提取为独立的 .css 文件而非嵌入 JS bundle。这样做的好处是:CSS 可以与 JS 并行下载,浏览器可提前渲染样式(避免 JS 执行后才显示样式的“闪白”);CSS 文件可被独立缓存,利用内容哈希实现长效缓存;减少 JS 体积,提升解析和编译性能。

importLoaders 选项指定在 css-loader 之前还有多少个 Loader 需要处理 @import 引入的外部 CSS 文件。例如,配置 { loader: 'css-loader', options: { importLoaders: 1 } } 后紧跟 'postcss-loader',当主 CSS 文件中通过 @import 'theme.css' 引入另一个 CSS 时,theme.css 也会先经过 postcss-loader 处理(如 autoprefixer),否则它只会直接经过 css-loader,跳过了 PostCSS 的处理步骤。这个配置保证了所有 CSS(包括通过 @import 引入的)都能经过完整的 Loader 流水线。


课后练习答案

一、概念自测答案

  1. B

    • 解析:css-loader 解析 CSS 中的依赖关系,将 @importurl() 转为模块请求。A 是 style-loader 的职责,C 是 CssMinimizerPlugin 的功能,D 是 sass-loader 的功能。
  2. B

    • 解析:生产环境提取 CSS 为独立文件可以并行加载、利用浏览器缓存,是性能最佳实践。A 错误,style-loader 支持 HMR;C 错误,两者必须配合使用;D 错误,速度不是主要区别。
  3. usage

    • 解析:useBuiltIns: 'usage' 按需自动引入 polyfill,仅引入代码中实际使用的 ES 特性的 polyfill,以最小化产物体积。
  4. A、B

    • 解析:PostCSS 是 CSS 后处理工具,autoprefixer(A)和 postcss-preset-env(B)是其最常用的插件。C 是 sass-loader 的功能,D 是 CssMinimizerPlugin 的功能。

二、AI 编程任务参考答案(提示词示例)

示例提示词
“请生成一个 Webpack 5 的 CSS 处理配置。要求:

  • webpack.config.js 导出一个函数,通过 argv.mode 区分开发/生产环境。
  • 支持 .scss 文件。.module.scss 启用 CSS Modules(localIdentName: '[local]_[hash:base64:6]')。
  • 开发用 style-loader,生产用 MiniCssExtractPlugin.loader。链式顺序:...loader, css-loader, postcss-loader, sass-loader
  • sass-loader 设置 additionalData 注入全局变量文件。
  • postcss.config.js 使用 autoprefixer
  • HtmlWebpackPlugin 生成 HTML,生产环境添加 MiniCssExtractPluginCssMinimizerPlugin
  • 直接输出所有文件内容。”
CATALOG
  1. 1. 第81课:Webpack 常用 Loader 与 Plugin——css-loader、babel-loader、HtmlWebpackPlugin、MiniCssExtractPlugin 等
    1. 1.1. 1. css-loader、style-loader 与 MiniCssExtractPlugin
      1. 1.1.1. 1.1 css-loader:解析 CSS 中的依赖关系
      2. 1.1.2. 1.2 style-loader:将 CSS 注入 DOM
      3. 1.1.3. 1.3 MiniCssExtractPlugin:提取 CSS 为独立文件
    2. 1.2. 2. babel-loader:JavaScript 编译器
      1. 1.2.1. 2.1 基础配置
      2. 1.2.2. 2.2 独立的 Babel 配置文件
      3. 1.2.3. 2.3 useBuiltIns 与 polyfill
    3. 1.3. 3. HtmlWebpackPlugin:HTML 生成
      1. 1.3.1. 3.1 基础用法
      2. 1.3.2. 3.2 模板中的变量
      3. 1.3.3. 3.3 多页面应用配置
    4. 1.4. 4. postcss-loader 与 sass-loader:CSS 后处理与预处理器
      1. 1.4.1. 4.1 sass-loader:SCSS/Less 编译
      2. 1.4.2. 4.2 postcss-loader:CSS 后处理
    5. 1.5. 5. 其他常用 Loader 与 Plugin
    6. 1.6. 6. Loader 执行顺序与配置优化
      1. 1.6.1. 6.1 链式调用规则
      2. 1.6.2. 6.2 oneOf 避免重复匹配
      3. 1.6.3. 6.3 include 与 exclude:缩小 Loader 作用范围
    7. 1.7. 7. 综合实战:一个完整的 Loader/Plugin 配置
    8. 1.8. 课后练习
      1. 1.8.1. 一、概念自测(选择题 / 填空题)
      2. 1.8.2. 二、AI 编程任务:编写面向 AI 的提示词
      3. 1.8.3. 三、Agent 模式下的提示词示例
      4. 1.8.4. 四、面试真题与参考答案
    9. 1.9. 课后练习答案
      1. 1.9.1. 一、概念自测答案
      2. 1.9.2. 二、AI 编程任务参考答案(提示词示例)