一、Webpack是什么?
Webpack 是一个静态模块打包工具,它把项目中的所有资源(JS、CSS、图片、字体等)都当成 "模块",然后根据依赖关系打包成浏览器能运行的静态文件。
二、Webpack解决了什么问题?
2.1 原始时代的痛点
<!-- 手动管理多个脚本 -->
<script src="jquery.js"></script>
<script src="utils.js"></script>
<script src="app.js"></script>
痛点:
- 多个JS文件,HTTP请求多,加载慢
- 依赖顺序必须手动控制
- 浏览器不认识ES Module、TypeScript、Sass
- 代码没有压缩、混淆,暴露源码
2.2 Webpack的解决方案
开发时(多个文件) → Webpack打包 → 生产环境(少量文件)
src/
├── index.js
├── utils.js
├── style.css
└── logo.png
↓
Webpack打包
↓
dist/
├── bundle.js # 所有JS合并、压缩
├── bundle.css # CSS提取、压缩
└── logo.[hash].png # 图片重命名、优化
好处:
- 所有资源统一管理
- 自动处理依赖关系
- 代码压缩、混淆、Tree Shaking
- 支持各种预处理器(TypeScript、Sass、Less)
- 开发时热更新(HMR)
三、Webpack的核心概念
Webpack 有5 个核心概念,搞懂它们就搞懂了 Webpack。
3.1 Entry(入口)
打包的起点,Webpack 从这个文件开始分析所有依赖。
// webpack.config.js
module.exports = {
// 单入口(SPA应用)
entry: './src/index.js',
// 多入口(多页面应用)
entry: {
home: './src/home.js',
about: './src/about.js'
}
};
3.2 Output(输出)
打包后的文件输出位置和文件名。
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), // 输出目录
filename: 'bundle.[contenthash].js', // 文件名(带hash缓存)
clean: true // 打包前清空dist
}
};
3.3 Loader(加载器)
将非 JS 文件转换为 JS 能识别的模块。Webpack 默认只认识 JS 和 JSON,其他文件需要用 Loader 处理。
module.exports = {
module: {
rules: [
// CSS Loader
{
test: /\.css$/, // 匹配.css文件
use: ['style-loader', 'css-loader'] // 从右到左执行
},
// TypeScript Loader
{
test: /\.ts$/,
use: 'ts-loader'
},
// 图片Loader
{
test: /\.(png|jpg|gif)$/,
type: 'asset/resource' // Webpack5内置
}
]
}
};
Loader 执行顺序:从右到左,从下到上
use: ['style-loader', 'css-loader', 'sass-loader']
// 执行顺序:sass-loader → css-loader → style-loader
// 1. sass-loader:Sass → CSS
// 2. css-loader:CSS → JS模块
// 3. style-loader:JS模块 → style标签插入HTML
3.4 Plugin(插件)
扩展 Webpack 功能,在打包的各个阶段做一些事情。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
// 自动生成HTML,并引入打包后的JS
new HtmlWebpackPlugin({
template: './public/index.html'
}),
// 提取CSS为单独文件(代替style-loader)
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash].css'
})
]
};
3.5 Mode(模式)
module.exports = {
mode: 'development', // 开发模式:快,不压缩,有source-map
// mode: 'production' // 生产模式:慢,压缩,优化
};
四、完整的Webpack配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// 1. 入口
entry: './src/index.js',
// 2. 输出
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[contenthash].js',
clean: true
},
// 3. 模式
mode: 'development',
// 4. 开发服务器
devServer: {
port: 3000,
hot: true,
open: true
},
// 5. Loaders
module: {
rules: [
// CSS处理
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 提取为CSS文件
'css-loader' // CSS转JS
]
},
// Sass处理
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
},
// Babel处理(JS/JSX)
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},
// 图片处理
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset/resource',
generator: {
filename: 'images/[name].[hash:8][ext]'
}
},
// 字体处理
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash:8][ext]'
}
}
]
},
// 6. Plugins
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash].css'
})
],
// 7. 解析配置
resolve: {
extensions: ['.js', '.jsx', '.json'], // 导入时可省略扩展名
alias: {
'@': path.resolve(__dirname, 'src') // 路径别名
}
},
// 8. 优化(生产模式启用)
optimization: {
splitChunks: {
chunks: 'all', // 提取公共依赖
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
五、开发 vs 生产环境配置
实际项目中通常区分开发和生产配置。
// webpack.common.js(公共配置)
module.exports = {
entry: './src/index.js',
output: { /* ... */ },
module: { /* 基础loaders */ },
plugins: { /* 基础plugins */ }
};
// 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', // 快速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', // 完整source-map
optimization: {
minimize: true, // 压缩代码
splitChunks: { /* 分割代码 */ }
}
});
// package.json
{
"scripts": {
"dev": "webpack serve --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
}
}
六、Webpack的核心工作流程
1. 读取配置(webpack.config.js)
↓
2. 从 Entry 开始解析
↓
3. 遇到 import/require,递归分析所有依赖
↓
4. 根据文件的扩展名,匹配 Loader
↓
5. Loader 转换文件内容(Sass → CSS,TS → JS)
↓
6. 应用 Plugin 做额外处理(压缩、提取、生成HTML)
↓
7. 输出打包结果到 Output 目录
七、常用Loader和Plugin速查
7.1 常用Loader
| Loader | 作用 |
|---|---|
babel-loader | 转换ES6+、JSX |
css-loader | 处理CSS中的@import和url() |
style-loader | 把CSS注入HTML的<style>标签 |
sass-loader | Sass → CSS |
less-loader | Less → CSS |
postcss-loader | CSS后处理(autoprefixer等) |
ts-loader | TypeScript → JavaScript |
vue-loader | 解析.vue文件 |
file-loader | 处理文件,输出到目录 |
url-loader | 小文件转Base64 |
7.2 常用Plugin
| Plugin | 作用 |
|---|---|
HtmlWebpackPlugin | 生成HTML,自动注入JS/CSS |
MiniCssExtractPlugin | 提取CSS为单独文件 |
CleanWebpackPlugin | 打包前清空输出目录 |
DefinePlugin | 定义全局常量(环境变量) |
CopyWebpackPlugin | 复制静态文件 |
CompressionWebpackPlugin | Gzip压缩 |
BundleAnalyzerPlugin | 分析打包体积 |
八、工程化中的最佳实践
8.1 Tree Shaking(去掉无用代码)
// package.json
{
"sideEffects": false // 所有代码无副作用,可安全Tree Shaking
}
// 或指定文件有副作用
{
"sideEffects": ["*.css", "*.scss"]
}
8.2 代码分割(Code Splitting)
// 动态导入(按需加载)
import('./module.js').then(module => {
// 使用模块
});
// 提取第三方库
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
}
}
}
}
8.3 缓存优化
output: {
filename: '[name].[contenthash].js' // 内容变化时hash变化
}
8.4 环境变量注入
// webpack.config.js
const webpack = require('webpack');
plugins: [
new webpack.DefinePlugin({
'process.env.API_URL': JSON.stringify('https://api.example.com'),
'process.env.NODE_ENV': JSON.stringify('production')
})
]
// 代码中使用
console.log(process.env.API_URL); // https://api.example.com
九、总结
- Webpack是打包工具:把所有资源当模块,根据依赖关系打包
- Loader转换文件:非JS文件转成JS能识别的格式
- Plugin扩展功能:在打包生命周期中做各种事情
Webpack 的核心公式:
Entry + Loader + Plugin + Output = Bundle