跳到主要内容

Webpack

Webpack 更像一个高度可编排的构建平台。它没有 Vite 那么轻,但在复杂项目、老项目和深度定制场景里依然很常见。

Webpack 主要做什么

  • 从入口文件出发收集依赖
  • 用 loader 处理不同类型的模块
  • 用 plugin 扩展构建能力
  • 输出一个或多个可部署的 bundle

三个核心概念

Entry / Output

  • entry:从哪里开始构建
  • output:最终产物输出到哪里

Loader

loader 用来把“Webpack 默认不认识的东西”转换成它能处理的模块。

常见例子:

  • babel-loader
  • css-loader
  • style-loader
  • sass-loader
  • file-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-loaderts-loader 通常会进场。现在更常见的思路是:

  • Babel 负责产物转译
  • tsc 负责类型检查

2. 样式

Webpack 项目里,样式链通常会比较明显:

  • style-loader
  • css-loader
  • sass-loader
  • postcss-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 仍然是很现实的选择。

常见排查顺序

真在项目里遇到问题时,通常先看这几层:

  1. entry / output
  2. resolve.alias / extensions
  3. module.rules
  4. plugins
  5. devServer

很多“页面打不开”“样式没生效”“路径不对”“资源没进包”,最后都能归到这几层。

一个更实际的判断

如果只是做现代单页应用,新项目通常不必强行从 Webpack 起步。

但如果当前面对的是历史项目、复杂工程或深度定制构建链,Webpack 依然很有价值,而且理解它能帮助看清很多后来构建工具在试图简化什么。