Webpack 面试题汇总(2026 版)
涵盖 Webpack 5 核心概念、构建原理、性能优化、Loader/Plugin 开发
概述
Webpack 是现代前端工程化的核心工具,本文汇总了 2026 年 Webpack 面试中的高频问题,包括:
- 基础概念:Entry、Output、Loader、Plugin、Mode
- 核心原理:构建流程、模块解析、依赖图、打包机制
- 性能优化:Tree Shaking、Code Splitting、缓存策略、构建速度优化
- 工程实践:多页应用配置、环境区分、Source Map、HMR
- 高级特性:Module Federation、Persistent Cache、Asset Modules
一、基础概念
1. 什么是 Webpack?它解决了什么问题?
答案:
Webpack 是一个模块打包工具,它将项目中的各种资源(JS、CSS、图片等)视为模块,通过分析模块间的依赖关系,最终打包成浏览器可识别的静态资源。
解决的问题:
- 模块化:支持 ES Module、CommonJS、AMD 等多种模块规范
- 资源管理:统一处理 JS、CSS、图片、字体等各类资源
- 代码转换:通过 Loader 转换 TypeScript、Sass、Less 等
- 性能优化:代码分割、Tree Shaking、压缩混淆
- 开发体验:HMR 热更新、Source Map 调试
示例:
// webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}2. Webpack 的核心概念有哪些?
答案:
五大核心概念:
- Entry(入口)
- 指示 Webpack 从哪个文件开始构建依赖图
- 支持单入口和多入口
// 单入口
entry: './src/index.js'
// 多入口
entry: {
app: './src/app.js',
admin: './src/admin.js'
}- Output(输出)
- 指定打包后的文件输出位置和命名规则
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true // Webpack 5 自动清理
}- Loader(加载器)
- 转换非 JavaScript 文件(CSS、图片、TypeScript 等)
- 从右到左、从下到上执行
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}- Plugin(插件)
- 执行更广泛的任务(打包优化、资源管理、环境变量注入等)
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
]- Mode(模式)
development:开发模式,启用 SourceMap、HMRproduction:生产模式,启用压缩、Tree Shakingnone:不使用任何默认优化
mode: 'production'3. Loader 和 Plugin 有什么区别?
答案:
| 特性 | Loader | Plugin |
|---|---|---|
| 作用 | 转换文件内容 | 执行更广泛的任务 |
| 执行时机 | 模块加载时 | 整个构建生命周期 |
| 配置位置 | module.rules | plugins 数组 |
| 输入输出 | 接收源文件,返回转换后内容 | 通过钩子访问 compilation 对象 |
| 示例 | babel-loader、css-loader | HtmlWebpackPlugin、MiniCssExtractPlugin |
Loader 示例:
// 处理 CSS 文件
{
test: /\.css$/,
use: [
'style-loader', // 将 CSS 注入 DOM
'css-loader', // 解析 CSS 文件
'postcss-loader' // 添加浏览器前缀
]
}Plugin 示例:
// 生成 HTML 文件
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['app']
})核心区别:
- Loader 是文件转换器,专注于单个文件的处理
- Plugin 是功能扩展器,可以介入整个构建流程
4. 常用的 Loader 有哪些?
答案:
样式处理:
// CSS
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
// Sass/SCSS
{
test: /\.s[ac]ss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
// Less
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
// PostCSS(自动添加前缀)
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}JavaScript 转换:
// Babel(ES6+ → ES5)
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
}
// TypeScript
{
test: /\.tsx?$/,
use: 'ts-loader'
}资源处理:
// 图片(Webpack 5 内置)
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset/resource'
}
// 字体
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
}
// 小图片转 base64
{
test: /\.(png|jpg|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 8kb
}
}
}5. 常用的 Plugin 有哪些?
答案:
HTML 处理:
// 生成 HTML 文件
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})CSS 处理:
// 提取 CSS 到单独文件
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
// 压缩 CSS
new CssMinimizerPlugin()代码优化:
// 压缩 JavaScript
new TerserPlugin({
parallel: true,
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
})
// 分析打包体积
new BundleAnalyzerPlugin()环境变量:
// 定义全局常量
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'API_URL': JSON.stringify('https://api.example.com')
})其他:
// 清理输出目录
new CleanWebpackPlugin()
// 复制静态资源
new CopyWebpackPlugin({
patterns: [
{ from: 'public', to: 'assets' }
]
})
// 进度条
new ProgressPlugin()二、构建流程
6. Webpack 的构建流程是什么?
答案:
Webpack 的构建流程分为三个阶段:
1. 初始化阶段
1. 读取配置文件(webpack.config.js)
2. 合并配置参数(命令行 + 配置文件)
3. 创建 Compiler 对象
4. 加载所有配置的插件
5. 执行 Compiler.run() 开始编译2. 编译阶段
1. 从 Entry 入口文件开始
2. 调用对应的 Loader 转换模块内容
3. 解析模块依赖(import、require)
4. 递归处理所有依赖模块
5. 生成 Chunk(代码块)
6. 构建完整的依赖图(Dependency Graph)3. 输出阶段
1. 根据依赖图生成最终代码
2. 根据 Output 配置输出文件
3. 写入文件系统详细流程图:
初始化
↓
读取配置 → 创建 Compiler → 注册插件
↓
编译
↓
确定入口 → 编译模块 → 完成模块编译
↓ ↑
└─ 递归依赖 ─────┘
↓
输出
↓
生成 Chunk → 输出资源 → 写入文件核心对象:
- Compiler:全局唯一,负责整个编译流程
- Compilation:每次编译创建,包含当前模块资源、编译生成资源等
- Module:代表一个模块
- Chunk:代码块,由多个 Module 组成
7. Webpack 的热更新(HMR)原理是什么?
答案:
HMR(Hot Module Replacement) 允许在运行时更新模块,无需刷新整个页面。
工作流程:
1. Webpack Compiler 监听文件变化
2. 文件变化后,重新编译生成新的模块
3. Webpack Dev Server 通过 WebSocket 推送更新消息
4. 客户端接收到更新消息
5. 客户端通过 JSONP 请求新模块代码
6. HMR Runtime 替换旧模块
7. 触发 module.hot.accept() 回调配置示例:
// webpack.config.js
module.exports = {
devServer: {
hot: true, // 启用 HMR
port: 3000
}
}使用示例:
// index.js
import { render } from './app.js'
render()
// 启用 HMR
if (module.hot) {
module.hot.accept('./app.js', () => {
console.log('app.js 更新了')
render()
})
}通信机制:
Webpack Dev Server (Node.js)
↓ WebSocket
浏览器客户端
↓ JSONP
获取更新的模块
↓
HMR Runtime 替换模块优势:
- 保留应用状态
- 只更新变化的模块
- 提升开发效率
8. 什么是 Source Map?如何配置?
答案:
Source Map 是源代码与打包后代码的映射文件,用于调试时定位源代码位置。
配置选项:
module.exports = {
devtool: 'source-map' // 多种选项
}常用选项对比:
| devtool | 构建速度 | 重构速度 | 生产环境 | 质量 |
|---|---|---|---|---|
eval | +++ | +++ | ❌ | 生成代码 |
eval-source-map | -- | + | ❌ | 原始源代码 |
cheap-source-map | + | ++ | ✅ | 转换后代码(仅行) |
cheap-module-source-map | + | ++ | ✅ | 原始源代码(仅行) |
source-map | -- | -- | ✅ | 原始源代码 |
hidden-source-map | -- | -- | ✅ | 原始源代码(不暴露) |
nosources-source-map | -- | -- | ✅ | 无源代码内容 |
推荐配置:
// 开发环境
devtool: 'eval-cheap-module-source-map'
// 生产环境
devtool: 'hidden-source-map' // 或 false原理:
// 打包后的代码末尾
//# sourceMappingURL=bundle.js.map// bundle.js.map
{
"version": 3,
"sources": ["webpack:///src/index.js"],
"mappings": "AAAA;AACA;AACA",
"file": "bundle.js"
}三、性能优化
9. 如何优化 Webpack 构建速度?
答案:
1. 缩小构建范围
module.exports = {
// 指定查找模块的目录
resolve: {
modules: [path.resolve(__dirname, 'node_modules')],
extensions: ['.js', '.json'], // 减少尝试的扩展名
alias: {
'@': path.resolve(__dirname, 'src')
}
},
// 排除不需要处理的文件
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
include: path.resolve(__dirname, 'src')
}
]
}
}2. 使用缓存
module.exports = {
// Webpack 5 持久化缓存
cache: {
type: 'filesystem',
cacheDirectory: path.resolve(__dirname, '.temp_cache')
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true // Babel 缓存
}
}
}
]
}
}3. 多进程构建
// thread-loader
{
test: /\.js$/,
use: [
'thread-loader',
'babel-loader'
]
}
// TerserPlugin 多进程压缩
optimization: {
minimizer: [
new TerserPlugin({
parallel: true
})
]
}4. 优化 Loader
// 使用更快的 Loader
{
test: /\.js$/,
use: 'esbuild-loader' // 比 babel-loader 快 10 倍
}5. DLL 预编译(已过时,Webpack 5 用 cache 代替)
6. 减少 Plugin 使用
// 只在生产环境使用某些插件
plugins: [
...(isProd ? [new BundleAnalyzerPlugin()] : [])
]效果对比:
优化前:构建耗时 60s
优化后:构建耗时 15s(提升 75%)10. 如何优化 Webpack 打包体积?
答案:
1. Tree Shaking(摇树优化)
// package.json
{
"sideEffects": false // 标记所有文件无副作用
}
// 或指定有副作用的文件
{
"sideEffects": ["*.css", "*.scss"]
}
// webpack.config.js
optimization: {
usedExports: true, // 标记未使用的导出
minimize: true, // 删除未使用的代码
sideEffects: true // 读取 package.json 的 sideEffects
}2. Code Splitting(代码分割)
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
// 提取第三方库
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
},
// 提取公共代码
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true
}
}
}
}3. 动态导入(懒加载)
// 路由懒加载
const Home = () => import('./views/Home.vue')
// 条件加载
button.addEventListener('click', async () => {
const module = await import('./heavy-module.js')
module.init()
})4. 压缩代码
optimization: {
minimizer: [
// 压缩 JS
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}),
// 压缩 CSS
new CssMinimizerPlugin()
]
}5. 外部化依赖(CDN)
externals: {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios'
}<!-- index.html -->
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>6. 图片优化
// 压缩图片
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'image-webpack-loader',
options: {
mozjpeg: { quality: 80 },
pngquant: { quality: [0.65, 0.90] }
}
}
]
}7. 分析打包体积
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
plugins: [
new BundleAnalyzerPlugin()
]效果对比:
优化前:bundle.js 2.5MB
优化后:
- vendors.js 800KB
- app.js 300KB
- home.js 150KB(懒加载)
总计:1.25MB(减少 50%)11. 什么是 Tree Shaking?如何配置?
答案:
Tree Shaking 是一种通过静态分析删除未使用代码(dead code)的优化技术。
原理:
- 基于 ES6 Module 的静态结构(
import/export) - 分析哪些导出被使用
- 删除未使用的导出
配置:
// webpack.config.js
module.exports = {
mode: 'production', // 自动启用 Tree Shaking
optimization: {
usedExports: true, // 标记未使用的导出
minimize: true, // 删除未使用的代码
sideEffects: true // 读取 package.json 的 sideEffects
}
}// package.json
{
"sideEffects": false
}
// 或指定有副作用的文件
{
"sideEffects": [
"*.css",
"*.scss",
"./src/polyfills.js"
]
}示例:
// utils.js
export function add(a, b) {
return a + b
}
export function subtract(a, b) {
return a - b
}
// index.js
import { add } from './utils.js'
console.log(add(1, 2))
// 打包后,subtract 函数会被删除注意事项:
- 必须使用 ES6 Module(CommonJS 不支持)
// ✅ 支持 Tree Shaking
import { add } from './utils'
// ❌ 不支持 Tree Shaking
const { add } = require('./utils')- 避免副作用
// ❌ 有副作用,不会被删除
export function setup() {
window.myGlobal = 'value'
}
// ✅ 无副作用,可以被删除
export function add(a, b) {
return a + b
}- Babel 配置
// .babelrc
{
"presets": [
["@babel/preset-env", {
"modules": false // 保留 ES6 Module
}]
]
}12. 什么是 Code Splitting?有哪些实现方式?
答案:
Code Splitting 是将代码分割成多个 bundle,实现按需加载,减少初始加载时间。
三种实现方式:
1. 多入口分割
entry: {
app: './src/app.js',
admin: './src/admin.js'
},
output: {
filename: '[name].bundle.js'
}2. SplitChunksPlugin(推荐)
optimization: {
splitChunks: {
chunks: 'all', // 'initial' | 'async' | 'all'
minSize: 20000, // 最小 20KB
maxSize: 244000, // 最大 244KB
minChunks: 1, // 最少被引用次数
maxAsyncRequests: 30,
maxInitialRequests: 30,
cacheGroups: {
// 第三方库
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
name: 'vendors'
},
// 公共代码
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
name: 'common'
},
// React 相关
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
priority: 10
},
// UI 库
ui: {
test: /[\\/]node_modules[\\/](antd|@ant-design)[\\/]/,
name: 'ui',
priority: 10
}
}
}
}3. 动态导入(Dynamic Import)
// 路由懒加载
const routes = [
{
path: '/home',
component: () => import(/* webpackChunkName: "home" */ './views/Home.vue')
},
{
path: '/about',
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
// 条件加载
button.addEventListener('click', async () => {
const { default: Chart } = await import(
/* webpackChunkName: "chart" */
/* webpackPrefetch: true */
'./Chart.js'
)
new Chart()
})魔法注释:
import(
/* webpackChunkName: "my-chunk" */ // 指定 chunk 名称
/* webpackPrefetch: true */ // 预加载
/* webpackPreload: true */ // 预加载(优先级更高)
'./module.js'
)效果:
优化前:
bundle.js: 2MB
优化后:
vendors.js: 800KB
react.js: 300KB
ui.js: 400KB
app.js: 200KB
home.js: 150KB (懒加载)
about.js: 150KB (懒加载)四、高级特性
13. Webpack 5 有哪些新特性?
答案:
1. 持久化缓存(Persistent Cache)
cache: {
type: 'filesystem',
cacheDirectory: path.resolve(__dirname, '.temp_cache'),
buildDependencies: {
config: [__filename]
}
}效果:二次构建速度提升 90%+
2. Module Federation(模块联邦)
// 应用 A(Remote)
new ModuleFederationPlugin({
name: 'app_a',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button',
'./Header': './src/components/Header'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
// 应用 B(Host)
new ModuleFederationPlugin({
name: 'app_b',
remotes: {
app_a: 'app_a@http://localhost:3001/remoteEntry.js'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})3. Asset Modules(资源模块)
// 替代 file-loader、url-loader、raw-loader
{
test: /\.png$/,
type: 'asset/resource' // 输出文件
}
{
test: /\.svg$/,
type: 'asset/inline' // 转 base64
}
{
test: /\.txt$/,
type: 'asset/source' // 导出源代码
}
{
test: /\.jpg$/,
type: 'asset', // 自动选择
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
}
}4. 更好的 Tree Shaking
- 支持嵌套的 Tree Shaking
- 支持 CommonJS 的 Tree Shaking
- 更智能的副作用分析
5. 移除 Node.js Polyfills
// Webpack 4 自动注入
// Webpack 5 需要手动配置
resolve: {
fallback: {
"path": require.resolve("path-browserify"),
"crypto": require.resolve("crypto-browserify")
}
}6. 更好的长期缓存
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js'
}
// Webpack 5 的 contenthash 更稳定14. 什么是 Module Federation?
答案:
Module Federation(模块联邦) 是 Webpack 5 的革命性特性,允许多个独立的构建可以共享模块。
核心概念:
- Host:消费其他应用的应用
- Remote:被消费的应用
- Shared:共享的依赖
使用场景:
- 微前端架构
- 组件库共享
- 多团队协作
配置示例:
// 应用 A(Remote)
new ModuleFederationPlugin({
name: 'app_a',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button',
'./Header': './src/components/Header'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
// 应用 B(Host)
new ModuleFederationPlugin({
name: 'app_b',
remotes: {
app_a: 'app_a@http://localhost:3001/remoteEntry.js'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})使用:
// 应用 B 中使用应用 A 的组件
import React, { lazy, Suspense } from 'react'
const RemoteButton = lazy(() => import('app_a/Button'))
function App() {
return (
<Suspense fallback="Loading...">
<RemoteButton />
</Suspense>
)
}优势:
- 运行时加载远程模块
- 共享依赖,避免重复打包
- 独立部署,互不影响
- 版本控制灵活
五、工程实践
15. 如何配置多页应用?
答案:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const glob = require('glob')
// 自动获取入口
function getEntries() {
const entries = {}
const files = glob.sync('./src/pages/*/index.js')
files.forEach(file => {
const name = file.match(/pages\/(.*)\/index\.js/)[1]
entries[name] = file
})
return entries
}
// 生成 HtmlWebpackPlugin 配置
function getHtmlPlugins() {
const entries = getEntries()
return Object.keys(entries).map(name => {
return new HtmlWebpackPlugin({
template: `./src/pages/${name}/index.html`,
filename: `${name}.html`,
chunks: ['vendors', 'common', name],
minify: {
collapseWhitespace: true,
removeComments: true
}
})
})
}
module.exports = {
entry: getEntries(),
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10
},
common: {
minChunks: 2,
name: 'common',
chunks: 'all',
priority: 5
}
}
}
},
plugins: [
...getHtmlPlugins()
]
}目录结构:
src/
pages/
home/
index.js
index.html
about/
index.js
index.html
contact/
index.js
index.html16. 如何区分开发环境和生产环境?
答案:
方法 1:使用不同的配置文件
// webpack.common.js
module.exports = {
entry: './src/index.js',
module: {
rules: [...]
}
}
// webpack.dev.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-cheap-module-source-map',
devServer: {
hot: true,
port: 3000
}
})
// webpack.prod.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
optimization: {
minimize: true
}
})// package.json
{
"scripts": {
"dev": "webpack serve --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
}
}方法 2:使用环境变量
// webpack.config.js
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
mode: isProd ? 'production' : 'development',
devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map',
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
...(isProd ? [
new MiniCssExtractPlugin(),
new CompressionPlugin()
] : [])
]
}{
"scripts": {
"dev": "NODE_ENV=development webpack serve",
"build": "NODE_ENV=production webpack"
}
}17. 如何处理环境变量?
答案:
方法 1:DefinePlugin
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'API_URL': JSON.stringify('https://api.example.com'),
'VERSION': JSON.stringify('1.0.0')
})// 代码中使用
if (process.env.NODE_ENV === 'production') {
console.log('生产环境')
}
fetch(API_URL + '/users')方法 2:dotenv-webpack
npm install dotenv-webpack -D// .env
API_URL=https://api.example.com
APP_NAME=MyApp// webpack.config.js
const Dotenv = require('dotenv-webpack')
plugins: [
new Dotenv()
]// 代码中使用
console.log(process.env.API_URL)方法 3:EnvironmentPlugin
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
API_URL: 'http://localhost:3000'
})六、面试高频题
18. Webpack 与 Vite 有什么区别?
答案:
| 特性 | Webpack | Vite |
|---|---|---|
| 构建方式 | Bundle(打包) | ESM + esbuild |
| 开发服务器 | Bundle 后启动 | 即时启动 |
| 热更新速度 | 较慢(重新打包) | 极快(ESM) |
| 生产构建 | Webpack | Rollup |
| 生态 | 成熟完善 | 快速发展 |
| 配置复杂度 | 较复杂 | 简单 |
| 适用场景 | 大型复杂项目 | 现代浏览器项目 |
Webpack 优势:
- 生态成熟,插件丰富
- 支持各种复杂场景
- 兼容性好
Vite 优势:
- 开发体验极佳
- 启动速度快
- HMR 速度快
19. 如何实现长期缓存?
答案:
1. 使用 contenthash
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js'
}
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
]2. 提取 runtime
optimization: {
runtimeChunk: 'single' // 或 { name: 'runtime' }
}3. 分离第三方库
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}4. Module IDs 优化
optimization: {
moduleIds: 'deterministic' // Webpack 5 默认
}效果:
修改业务代码:
app.js 变化 ✓
vendors.js 不变 ✓(命中缓存)
runtime.js 变化 ✓(体积小)20. 如何分析打包结果?
答案:
1. webpack-bundle-analyzer
npm install webpack-bundle-analyzer -Dconst BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
reportFilename: 'bundle-report.html'
})
]2. webpack --profile --json
webpack --profile --json > stats.json上传到 https://webpack.github.io/analyse/
3. speed-measure-webpack-plugin
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()
module.exports = smp.wrap({
// webpack 配置
})输出每个 Loader 和 Plugin 的耗时。
总结
本文涵盖了 Webpack 面试中的核心知识点:
✅ 基础概念:Entry、Output、Loader、Plugin、Mode
✅ 构建流程:初始化、编译、输出三阶段
✅ 性能优化:构建速度优化、打包体积优化
✅ 高级特性:Module Federation、Persistent Cache
✅ 工程实践:多页应用、环境区分、长期缓存
掌握这些知识点,足以应对 2026 年的 Webpack 面试!