Webpack 打包配置
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
(开发模式):- 优化打包速度。
- 提供更友好的调试信息。
- 不进行代码压缩和优化,方便快速迭代。
- 默认启用
NamedChunksPlugin
和NamedModulesPlugin
。
production
(生产模式):- 启用各种优化,如 Tree Shaking (摇树优化)、Scope Hoisting (作用域提升)。
- 进行代码压缩和混淆 (通过 TerserPlugin,Webpack 5 内置)。
- 默认启用
FlagDependencyExportsPlugin
、FlagDependencyUsagePlugin
、SideEffectsFlagPlugin
、UglifyJsPlugin
(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', // },
- 如果采用多入口,
HtmlWebpackPlugin
的chunks
选项将变得非常重要,用于指定每个 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-map
或cheap-module-module-source-map
,生产环境通常使用source-map
(或hidden-source-map
以隐藏 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 文件中的@import
和url()
等语句,将 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/resource
或asset/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
)。
- 这些配置确保了项目中的每个 HTML 页面都能被正确地处理,并自动引入打包后的 JavaScript 文件 (当前配置下是
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
。
- 这个插件与上面提到的 CSS Loader 配合使用,用于将 CSS 从 JavaScript Bundle 中提取到单独的
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
配置和HtmlWebpackPlugin
的chunks
选项,确保每个页面引入正确的 JavaScript 和 CSS。 - 性能优化 (生产环境):
- Tree Shaking: 确保
mode: 'production'
启用,并在package.json
中设置sideEffects: false
或精确指定有副作用的文件,以移除未使用的代码。 - Code Splitting (代码分割): 通过配置
optimization.splitChunks
或使用动态import()
语法,将公共模块或不常变化的模块单独打包,利用浏览器缓存。 - Caching (缓存): 在
output.filename
和MiniCssExtractPlugin.filename
中使用[contenthash]
,确保文件内容不变时哈希值不变,利于浏览器缓存。 - 图片优化: 使用
image-minimizer-webpack-plugin
等插件在打包时压缩图片。
- Tree Shaking: 确保
- 环境变量: 使用
webpack.DefinePlugin
或dotenv-webpack
插件管理不同环境下的配置。 - 代码风格检查: 集成 ESLint (通过
eslint-webpack-plugin
) 确保代码质量。 - 打包分析: 使用
webpack-bundle-analyzer
插件可视化分析打包后的文件大小,找出优化点。