文章目录
-
- 概要
- 主要内容
-
- [1. 安装nvm、node.js](#1. 安装nvm、node.js)
- [2. 初始化项目、安装并配置Webpack5](#2. 初始化项目、安装并配置Webpack5)
- [3. Loader 和 Plugin](#3. Loader 和 Plugin)
- [4. 减小打包体积](#4. 减小打包体积)
- [5. 提高打包速度](#5. 提高打包速度)
- [6. 优化 LCP/FCP](#6. 优化 LCP/FCP)
- [7. Web Vitals 优化](#7. Web Vitals 优化)
- [8. DDL 预加载](#8. DDL 预加载)
-
- [8.1 创建 DLL 配置文件](#8.1 创建 DLL 配置文件)
- [8.2 总配置方案](#8.2 总配置方案)
- [8.3 配置 package.json 脚本](#8.3 配置 package.json 脚本)
- 小结
概要
时光飞逝,前端技术更是日新月异。转眼间,我们已站在2025年的尾巴上,即将迈入2026年。在这个框架林立、工具纷繁的时代,你是否曾感到一丝焦虑:那些被视为"基石"的技术,真的掌握了吗?
Webpack5,作为现代前端工程化的奠基者与核心,曾一度是面试和开发的"必问题"。尽管如今有Vite等后起之秀凭借其极速的热更新吸引了大量目光,但Webpack凭借其无与伦比的生态、成熟的解决方案和极其灵活的模块打包能力,依然是众多大型项目的首选,其底层思想更是理解前端构建的关键。
前面都是废话,Webpack5是一个现代化的前端构建工具,用于打包JavaScript、CSS、图像等资源。它通过模块化处理依赖关系,提升开发效率和性能。三十年河东三十年河西,今时不同往日,虽然Webpack已经没有了往日的荣光,但是当年这么多用 Webpack 创建的项目都还需要维护,因此还是值得前端开发者去学习的。
主要内容
1. 安装nvm、node.js
Webpack5依赖Node.js环境,首先确保已安装 Node.js(建议版本14+)。
但我不推荐你直接安装 Node.js,而是推荐你先安装 nvm-windows,然后再通过 nvm 来安装和管理 Node.js 版本。
-
安装最新的长期支持版本:
bash# 安装最新的 LTS 版本 nvm install lts # 使用刚刚安装的 LTS 版本 nvm use lts # 设置该版本为默认版本(可选) nvm on # 验证安装是否成功 node --version npm --version -
不同项目使用不同版本(切换版本):
bash# 查看所有可安装的远程版本 nvm list available # 安装特定版本,如 18.20.2 nvm install 18.20.2 # 查看本地已安装的所有版本 nvm list # 切换到版本 18.20.2 nvm use 18.20.2
这样做主要有以下几个无法替代的巨大优势:
- 轻松切换 Node.js 版本:不同的项目可能需要不同版本的 Node.js。使用 nvm,你可以在一台电脑上同时安装多个版本(如最新的 20.x、稳定的 18.x LTS),并可以随时在命令行中一键切换,非常灵活。
- 避免权限问题:在 Windows 上直接安装 Node.js 可能会遇到全局包安装需要管理员权限的问题。通过 nvm 安装的 Node.js 会存在于你的用户目录下,彻底避免这类烦人的权限错误。
- 简单的安装/卸载:使用
nvm install <version>和nvm uninstall <version>来安装或卸载 Node.js 版本比手动清理要简单干净得多。
2. 初始化项目、安装并配置Webpack5
-
初始化Node.js项目:在命令行中创建项目文件夹并初始化
package.json文件。bashmkdir my-webpack-project # 创建项目文件夹 cd my-webpack-project # 进入文件夹 npm init -y # 初始化项目,使用默认配置 -
安装Webpack5:推荐局部安装(仅当前项目使用),避免全局冲突。
bashnpm install webpack webpack-cli --save-dev # 安装最新版Webpack和CLI工具 npm install webpack-dev-server --save-dev # 安装开发服务器(devServer)实现热更新和本地调试 -
安装后,Webpack5命令可通过
npx webpack执行。安装Webpack-cli后,可使用webpack-cli init交互式初始化项目配置。bash# 查看Webpack版本 webpack -v # 指定入口文件打包,例如webpack src/index.js dist/bundle.js webpack <entry> [<entry>] <output> # 使用自定义配置文件打包 webpack --config webpack.conf.js -
Webpack5的核心是配置文件
webpack.config.js:-
定义入口、输出、加载器等。
js// webpack.config.js const path = require('path'); module.exports = { entry: './src/index.js', // 入口文件 output: { filename: 'bundle.js', // 输出文件名 path: path.resolve(__dirname, 'dist') // 输出目录 }, mode: 'development', // 开发模式(简化调试) }; -
定义热更新和本地调试。
jsmodule.exports = { // ...其他配置 devServer: { static: './dist', // 静态文件目录 hot: true, // 热更新 port: 8080 // 端口 } }; -
安装配置Loader和Plugin。
- Loader处理非JS资源(如CSS),例如安装css-loader和style-loader。
- Plugin优化构建,如HtmlWebpackPlugin生成HTML文件。
-
3. Loader 和 Plugin
-
Webpack 5 的常用 Loader 和 Plugin 分类及代表工具:
类型 名称 作用描述 Loader babel-loader 转换 ES6+/TypeScript 代码为浏览器兼容JS css-loader 解析CSS 中的 @import 和 url() 依赖 style-loader 将 CSS 注入 DOM(通过 <style>标签)sass-loader 编译 SCSS/Sass 为 CSS postcss-loader 使用 PostCSS 处理 CSS(自动添加前缀等) file-loader 处理图片/字体等资源文件(Webpack 5 可用资源模块替代) Plugin HtmlWebpackPlugin 自动生成 HTML 并注入打包后的资源链接 MiniCssExtractPlugin 将 CSS 提取为独立文件(替代 style-loader) CleanWebpackPlugin 构建前清理输出目录 CompressionPlugin 生成 Gzip/Brotli 压缩文件 BundleAnalyzerPlugin 可视化分析包体积 -
Loader:文件加载时转换器
-
babel-loader:转换 ES6+/TypeScript 代码为浏览器兼容 JS
-
css-loader:解析 CSS 中的
@import和url()依赖 -
style-loader:将 CSS 注入 DOM(通过
<style>标签) -
sass-loader:编译 SCSS/Sass 为 CSS
-
postcss-loader:使用 PostCSS 处理 CSS(自动添加前缀等)
-
file-loader:处理图片/字体等资源文件(Webpack 5 可用资源模块替代)
-
安装
bashnpm i -D babel-loader @babel/core @babel/preset-env npm i -D css-loader npm i -D style-loader npm i -D sass-loader sass npm i -D postcss-loader postcss npm i -D file-loader -
配置
js/** * CSS处理链:sass-loader(先编译Sass) -> postcss-loader(处理CSS) -> css-loader(解析CSS) -> style-loader(注入CSS) */ module.exports = { module: { rules: [ // Babel for JavaScript { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader' }, // CSS with PostCSS { test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] }, // Sass with PostCSS { test: /\.scss$/, use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] }, // File loader for images { test: /\.(png|jpe?g|gif|svg)$/, use: { loader: 'file-loader', options: { outputPath: 'assets/' } } } ] } };
-
-
Plugin:扩展 Webpack 功能的钩子,用于优化资源
-
HtmlWebpackPlugin:自动生成 HTML 并注入打包后的资源链接
-
MiniCssExtractPlugin:将 CSS 提取为独立文件(替代 style-loader)
-
CleanWebpackPlugin:构建前清理输出目录
-
CompressionPlugin:生成 Gzip/Brotli 压缩文件
-
BundleAnalyzerPlugin:可视化分析包体积
-
安装
bashnpm i -D html-webpack-plugin npm i -D mini-css-extract-plugin npm i -D clean-webpack-plugin npm i -D compression-webpack-plugin npm i -D webpack-bundle-analyzer -
配置
js/** * HtmlWebpackPlugin: 生成HTML文件,并自动注入打包后的资源 * MiniCssExtractPlugin: 将CSS提取为单独的文件 * CleanWebpackPlugin: 在每次构建前清理输出目录 * CompressionPlugin: 为资源提供gzip等压缩版本 * BundleAnalyzerPlugin: 生成打包分析报告,帮助优化体积 */ const path = require('path'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CompressionPlugin = require('compression-webpack-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'js/[name].[contenthash:8].js' }, module: { rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'] } ] }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: './public/index.html' }), new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' }), new CompressionPlugin(), new BundleAnalyzerPlugin({ analyzerMode: 'disabled' }) // 按需启用 ] };
-
-
Loader vs Plugin 核心区别:
- Loader:文件加载时转换器(如转译 JSX、编译 SCSS)
- Plugin:扩展 Webpack 功能的钩子(如优化资源、生成HTML)
4. 减小打包体积
-
关键优化:
- Tree Shaking:生产模式自动启用(需 ES6 模块语法)
- 资源压缩:图片使用 image-webpack-loader 进一步压缩
- 按需加载:使用 import() 动态导入路由组件
-
插件:
- 压缩JavaScript:
terser-webpack-plugin - 压缩CSS:
css-minimizer-webpack-plugin - 压缩图片:
image-minimizer-webpack-plugin
bashnpm i -D terser-webpack-plugin npm i -D css-minimizer-webpack-plugin npm i -D image-minimizer-webpack-plugin - 压缩JavaScript:
-
配置:
jsconst TerserPlugin = require("terser-webpack-plugin"); const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); // 引入图片压缩插件 module.exports = { optimization: { minimize: true, minimizer: [ // 1. JS 压缩器 new TerserPlugin({ parallel: true, terserOptions: { compress: { drop_console: true }, }, }), // 2. CSS 压缩器 new CssMinimizerPlugin(), // 3. 图片压缩插件 new ImageMinimizerPlugin({ minimizer: { implementation: ImageMinimizerPlugin.imageminMinify, options: { plugins: [ ["imagemin-mozjpeg", { quality: 80 }], // 压缩 JPEG ["imagemin-pngquant", { quality: [0.6, 0.8] }], // 压缩 PNG ["imagemin-gifsicle", { interlaced: true }], // 压缩 GIF ["imagemin-svgo", { plugins: [{ removeViewBox: false }] }], // 压缩 SVG ], }, }, // 生成 webp 格式的选项(可选) generator: [ { preset: "webp", implementation: ImageMinimizerPlugin.imageminGenerate, options: { plugins: ["imagemin-webp"] }, }, ], }), ], // 4. 代码分割配置(保持原样) splitChunks: { chunks: "all", cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: "vendors", }, }, }, }, module: { rules: [ // 5. 资源模块配置(图片处理) { test: /\.(png|jpe?g|gif|svg)$/i, type: "asset/resource", generator: { filename: "images/[hash][ext][query]", // 输出路径 }, }, ], }, };
5. 提高打包速度
- 提速技巧:
- 限制 Loader 范围:通过 include/exclude 减少处理文件
- 多进程构建:使用 thread-loader(CPU密集型操作),需要在 babel-loader 之前!
- DLL 预构建:对稳定库(如 React)提前打包
js
const os = require("os");
module.exports = {
// Webpack 5 持久化缓存配置
cache: {
type: "filesystem",
buildDependencies: {
config: [__filename], // 配置文件变更时刷新缓存
},
},
resolve: {
extensions: [".js", ".jsx", ".json"], // 文件扩展名
alias: {
"@": path.resolve(__dirname, "src"), // 路径别名
},
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: "thread-loader", // 添加 thread-loader
options: {
workers: os.cpus().length - 1, // 根据 CPU 核心数自动设置
workerParallelJobs: 50,
poolTimeout: 2000,
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 启用 Babel 缓存[^1]
presets: ["@babel/preset-env"],
},
},
],
},
],
},
};
6. 优化 LCP/FCP
- 概念
- LCP(最大内容渲染):首屏主要内容加载时间
- FCP(首次内容渲染):首次任意内容渲染时间
- LCP/FCP 专项优化:
- 关键 CSS 内联:使用 critters-webpack-plugin 首屏 CSS 内联
- 资源预加载:对关键字体/图片添加
<link rel="preload"> - 延迟非关键 JS:通过
async/defer延迟第三方脚本 - CDN 加速:将静态资源上传至 CDN
- 优化图片格式:使用 WebP 格式(通过 image-minimizer-webpack-plugin)
js
// 优化配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
minify: true, // 压缩 HTML
preload: '**/*.css' // 预加载关键 CSS
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
],
module: {
rules: [{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 提取 CSS 文件
'css-loader'
]
}]
}
};
7. Web Vitals 优化
- LCP 优化:
- 使用 loading="eager" 优先加载 LCP 元素图片
- 服务端渲染(SSR)或静态站点生成(SSG)
- 移除渲染阻塞资源
- FCP 优化:
- 内联关键 CSS(减少网络请求)
- 使用骨架屏(Skeleton Screen)
- 优化 Web 字体加载(font-display: swap)
- 验证工具:
- ighthouse(Chrome DevTools)
- Webpack 性能分析:
webpack --profile --json > stats.json+ Webpack Analyse
- 通过以上优化,典型项目可达到:
- 打包体积减少 40%~60%
- 构建速度提升 50%~70%
- LCP 时间 < 2.5s(良好标准)
8. DDL 预加载
在 Webpack 5 中配置 DLL 预构建优化大体积库,对 echarts、lodash 等大体积库的 DLL 预构建配置。DLL 预构建能够显著提升构建速度,特别是对于大型库。
- DLL 预构建优点
- 显著提升构建速度:大型库只需构建一次
- 减少开发环境构建时间:开发时只构建业务代码
- 优化生产构建:分离第三方库减少主包体积
- 关键配置点
- DLL 配置文件:单独配置需要预构建的库
- DllReferencePlugin:在主配置中引用预构建的库
- AddAssetHtmlPlugin:自动将 DLL 文件添加到 HTML 中
- 缓存优化:与 Webpack 5 持久化缓存协同工作
- 推荐预构建的库
- echarts: 大型图表库
- lodash: 实用工具库
- moment: 日期处理库
- react-dom: React 渲染库
- axios: HTTP 客户端
- antd: UI 组件库
- three: 3D 库
8.1 创建 DLL 配置文件
js
// webpack.dll.config.js
const path = require('path');
const { DllPlugin } = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendor: [
'echarts', // 添加需要预构建的大型库
'lodash',
'moment',
'react-dom',
'axios'
]
},
output: {
path: path.resolve(__dirname, 'dll'),
filename: '[name].dll.js',
library: '[name]_dll' // 全局变量名,供引用
},
plugins: [
new DllPlugin({
name: '[name]_dll', // 与 output.library 保持一致
path: path.join(__dirname, 'dll', '[name]-manifest.json')
})
]
};
8.2 总配置方案
js
// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const { DllPlugin } = require('webpack');
const { DllReferencePlugin } = require('webpack');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
// 1. 创建单独的 DLL 配置文件 (webpack.dll.config.js)
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
// Webpack 基础配置
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename] // 配置文件变更时刷新缓存
}
},
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src')
}
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true, // Babel 缓存
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
]
}
]
},
plugins: [
// 引用预先构建的 DLL
new DllReferencePlugin({
context: __dirname,
manifest: require('./dll/vendor-manifest.json')
}),
// 将 DLL 文件添加到 HTML 中
new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, 'dll/vendor.dll.js'),
publicPath: '/dll', // 公共路径
outputPath: 'dll' // 输出目录
}),
// 其他插件...
],
// 生产环境特定配置
...(isProduction ? {
optimization: {
minimize: true,
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
} : {})
};
};
8.3 配置 package.json 脚本
json
{
"scripts": {
"build:dll": "webpack --config webpack.dll.config.js",
"dev": "npm run build:dll && webpack serve --mode development",
"build": "npm run build:dll && webpack --mode production"
}
}
小结
-
Loader vs Plugin 核心区别:
- Loader:文件加载时转换器(如转译 JSX、编译 SCSS)
- Plugin:扩展 Webpack 功能的钩子(如优化资源、生成 HTML)
-
减小打包体积(压缩):
- Tree Shaking:生产模式自动启用(需 ES6 模块语法
import { ... } from '...') - 资源压缩:图片使用
image-webpack-loader进一步压缩 - 按需加载:使用
import()动态导入路由组件 - JavaScript代码压缩:
terser-webpack-plugin - CSS代码压缩:
ss-minimizer-webpack-plugin
- Tree Shaking:生产模式自动启用(需 ES6 模块语法
-
提高打包速度
- 限制 Loader 范围:通过
include/exclude减少处理文件 - 多进程构建:使用
thread-loader(CPU 密集型操作) - DLL 预构建:对稳定库(如 React)提前打包
- 限制 Loader 范围:通过
-
LCP/FCP 专项优化
- 关键 CSS 内联:使用
critters-webpack-plugin首屏 CSS 内联 - 资源预加载:对关键字体/图片添加
<link rel="preload"> - 延迟非关键 JS:通过
async/defer延迟第三方脚本 - CDN 加速:将静态资源上传至 CDN
- 优化图片格式:使用 WebP 格式(通过
image-minimizer-webpack-plugin)
- 关键 CSS 内联:使用
-
Web Vitals 优化实践
-
LCP 优化:
- 使用 loading="eager" 优先加载 LCP 元素图片
- 服务端渲染(SSR)或静态站点生成(SSG)
- 移除渲染阻塞资源
-
FCP 优化:
- 内联关键 CSS(减少网络请求)
- 使用骨架屏(Skeleton Screen)
- 优化 Web 字体加载(font-display: swap)
-
验证工具:
- ighthouse(Chrome DevTools)
- Webpack 性能分析:
webpack --profile --json > stats.json+ Webpack Analyse
-
-
优化 Webpack 需结合:
- 现代工具:Webpack 5 内置资源模块/持久化缓存
- 按需处理:Loader 范围限制/代码分割
- 性能指标驱动:专注 LCP/FCP 等核心 Web Vitals