Webpack
Webpack 更像一个高度可编排的构建平台。它没有 Vite 那么轻,但在复杂项目、老项目和深度定制场景里依然很常见。
Webpack 主要做什么
- 从入口文件出发收集依赖
- 用 loader 处理不同类型的模块
- 用 plugin 扩展构建能力
- 输出一个或多个可部署的 bundle
三个核心概念
Entry / Output
entry:从哪里开始构建output:最终产物输出到哪里
Loader
loader 用来把“Webpack 默认不认识的东西”转换成它能处理的模块。
常见例子:
babel-loadercss-loaderstyle-loadersass-loaderfile-loader或资源模块
Plugin
plugin 用来扩展整个构建流程,比如:
- 生成 HTML
- 提取 CSS
- 清理构建目录
- 注入环境变量
- 分析 bundle
一个更完整的前端项目配置
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true,
publicPath: '/',
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
devServer: {
port: 3000,
historyApiFallback: true,
proxy: {
'/api': 'http://localhost:8080',
},
},
plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })],
}
前端项目里最常接的几层
1. React / TypeScript
babel-loader 或 ts-loader 通常会进场。现在更常见的思路是:
- Babel 负责产物转译
tsc负责类型检查
2. 样式
Webpack 项目里,样式链通常会比较明显:
style-loadercss-loadersass-loaderpostcss-loader
3. 资源处理
图片、字体、SVG、媒体文件都会进 module rules。老项目和新项目的写法可能还不太一样。
4. 开发服务器
代理、history fallback、多页入口、本地 mock,这些往往都会在 devServer 里处理。
一个更进阶的配置参考
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
mode: 'production',
entry: {
app: './src/main.tsx',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[contenthash:8].js',
chunkFilename: 'js/[name].[contenthash:8].chunk.js',
assetModuleFilename: 'assets/[name].[hash:8][ext]',
publicPath: '/',
clean: true,
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.(css|scss)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
type: 'asset',
},
],
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react-vendor',
priority: 20,
},
},
},
runtimeChunk: 'single',
},
plugins: [
new HtmlWebpackPlugin({ template: './public/index.html' }),
new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' }),
new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }),
],
}
这类配置更适合:
- 历史大型项目
- 多团队长期维护的后台系统
- 对拆包、产物结构和性能分析要求更高的项目
Webpack 为什么在复杂项目里还常见
因为它的可定制空间很大。
如果项目有这些特征:
- loader / plugin 历史包袱重
- 构建流程很深
- 多入口很多
- 产物策略复杂
- 需要和老系统或特殊运行环境对接
Webpack 仍然是很现实的选择。