文章
从零搭建 Webpack 5 + Vue 3 项目:完整配置指南
从零搭建 Webpack 5 + Vue 3 项目:完整配置指南 一篇文章搞定 Webpack + Vue 项目配置,从基础搭建到生产优化,手把手教你每一个配置项的作用。 目录 一、核心概念:Webpack 是什么? 二...
从零搭建 Webpack 5 + Vue 3 项目:完整配置指南 #
一篇文章搞定 Webpack + Vue 项目配置,从基础搭建到生产优化,手把手教你每一个配置项的作用。
目录 #
一、核心概念:Webpack 是什么? #
1.1 大白话解释 #
想象你在做一道菜:
- 原材料 = 你的源代码(.vue、.js、.css、图片等)
- 厨具 = Webpack
- 成品菜 = 浏览器能运行的文件(.html、.js、.css)
Webpack 的工作就是:把你写的各种源代码,打包成浏览器认识的文件。
为什么需要打包?因为浏览器:
- 不认识
.vue文件 - 不认识
import './style.scss' - 不认识 TypeScript
- 不能直接用 ES6+ 新语法(老浏览器)
Webpack 把这些都"翻译"成浏览器能读懂的东西。
1.2 核心名词速查 #
| 名词 | 大白话解释 | 举例 |
|---|---|---|
| Entry(入口) | Webpack 从哪个文件开始打包 | main.js |
| Output(输出) | 打包后的文件放哪里、叫什么 | dist/bundle.js |
| Loader(加载器) | 翻译官,把非 JS 文件转成 JS | vue-loader 处理 .vue |
| Plugin(插件) | 增强功能,做 Loader 做不了的事 | 生成 HTML 文件 |
| Mode(模式) | 开发模式还是生产模式 | development / production |
| Module(模块) | 一个文件就是一个模块 | import App from './App.vue' |
| Bundle(包) | 打包后的文件 | bundle.js |
| Chunk(代码块) | 拆分出的代码片段 | 懒加载的组件 |
1.3 Webpack vs Vite #
| 对比项 | Webpack | Vite |
|---|---|---|
| 启动速度 | 较慢(需打包) | 极快(原生 ESM) |
| 热更新 | 较慢 | 极快 |
| 生态成熟度 | 非常成熟 | 快速发展 |
| 配置复杂度 | 较复杂 | 开箱即用 |
| 生产构建 | Webpack | Rollup |
| 适用场景 | 复杂企业项目 | 新项目、快速开发 |
为什么还要学 Webpack?
- 大量老项目在用 Webpack
- 复杂项目需要精细控制打包过程
- 面试必考
- 理解 Webpack 后,学其他构建工具更容易
二、项目初始化 #
2.1 创建项目目录 #
# 创建项目文件夹
mkdir webpack-vue-demo
# 进入项目
cd webpack-vue-demo
# 初始化 package.json
npm init -y2.2 安装 Webpack #
# 安装 webpack 核心和 CLI
npm install webpack webpack-cli -D
# 安装 webpack 开发服务器
npm install webpack-dev-server -D2.3 安装 Vue 相关依赖 #
# 安装 Vue 3
npm install vue
# 安装 Vue 单文件组件加载器
npm install vue-loader @vue/compiler-sfc -D
# 安装 Vue 模板编译器(Vue 3 需要单独安装)
# @vue/compiler-sfc 已经包含在上面2.4 安装其他必要依赖 #
# CSS 相关
npm install css-loader style-loader -D
# 处理 less/sass(可选,根据需要安装)
npm install less less-loader -D
# npm install sass sass-loader -D
# 处理图片等资源
npm install file-loader url-loader -D
# 注意:Webpack 5 内置了 Asset Modules,可以不用 file-loader
# 处理 Babel(ES6+ 转 ES5)
npm install babel-loader @babel/core @babel/preset-env -D
# 生成 HTML 文件
npm install html-webpack-plugin -D
# 清理 dist 目录
npm install clean-webpack-plugin -D2.5 项目结构 #
webpack-vue-demo/
├── public/
│ └── index.html # HTML 模板
├── src/
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── webpack.config.js # Webpack 配置
└── package.json三、基础配置:让项目跑起来 #
3.1 创建最简单的 Webpack 配置 #
创建 webpack.config.js:
// webpack.config.js
const path = require('path');
module.exports = {
// 1. 模式:开发模式
mode: 'development',
// 2. 入口:从哪个文件开始打包
entry: './src/main.js',
// 3. 输出:打包后的文件
output: {
filename: 'bundle.js', // 输出文件名
path: path.resolve(__dirname, 'dist'), // 输出目录(绝对路径)
},
// 4. 模块:配置各种 Loader
module: {
rules: [
// 处理 .vue 文件
{
test: /\.vue$/,
loader: 'vue-loader'
},
// 处理 CSS
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] // 从右往左执行
},
// 处理 JS(Babel)
{
test: /\.js$/,
exclude: /node_modules/, // 排除 node_modules
loader: 'babel-loader'
}
]
},
// 5. 插件
plugins: []
};3.2 创建入口文件和组件 #
创建 src/main.js:
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
// 创建 Vue 应用并挂载
createApp(App).mount('#app');创建 src/App.vue:
<!-- src/App.vue -->
<template>
<div class="app">
<h1>{{ message }}</h1>
<button @click="count++">点击次数: {{ count }}</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
name: 'App',
setup() {
const message = ref('Hello Webpack + Vue!');
const count = ref(0);
return {
message,
count
};
}
};
</script>
<style scoped>
.app {
text-align: center;
padding: 20px;
}
h1 {
color: #42b983; /* Vue 绿 */
}
button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border: 1px solid #42b983;
border-radius: 4px;
background: white;
color: #42b983;
}
button:hover {
background: #42b983;
color: white;
}
</style>创建 public/index.html:
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webpack + Vue Demo</title>
</head>
<body>
<!-- Vue 挂载点 -->
<div id="app"></div>
</body>
</html>3.3 配置 Babel #
创建 babel.config.js 或 .babelrc:
// babel.config.js
module.exports = {
presets: [
'@babel/preset-env' // 自动根据目标浏览器转换语法
]
};3.4 添加 npm scripts #
修改 package.json:
{
"scripts": {
"dev": "webpack serve --config webpack.config.js",
"build": "webpack --config webpack.config.js"
}
}3.5 运行项目 #
# 开发模式运行
npm run dev
# 浏览器打开 http://localhost:8080四、Vue 项目专属配置 #
4.1 添加 Vue Loader 插件 #
vue-loader 需要配合 VueLoaderPlugin 使用:
// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
// ... 其他配置
plugins: [
new VueLoaderPlugin() // 必须添加!
]
};4.2 生成 HTML 文件 #
使用 html-webpack-plugin 自动生成 HTML:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html', // 模板文件
filename: 'index.html', // 输出文件名
title: 'Webpack + Vue App', // 页面标题
inject: 'body' // JS 注入位置
})
]
};4.3 处理 Less/Sass 样式 #
如果使用 Less:
// webpack.config.js - module.rules 中添加
{
test: /\.less$/,
use: [
'style-loader', // 将 CSS 注入到 style 标签
'css-loader', // 处理 CSS 中的 @import 和 url()
'less-loader' // 将 Less 编译为 CSS
]
}如果使用 Sass:
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}4.4 处理图片和字体 #
Webpack 5 内置了 Asset Modules,推荐使用:
// webpack.config.js - module.rules 中添加
{
test: /\.(png|jpe?g|gif|svg|webp)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 小于 8KB 转 base64
}
},
generator: {
filename: 'images/[name].[hash:8][ext]' // 输出路径和文件名
}
},
{
test: /\.(woff2?|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash:8][ext]'
}
}在 Vue 中使用图片:
<template>
<div>
<!-- 方式1:直接引用 -->
<img src="../assets/logo.png" alt="Logo">
<!-- 方式2:动态绑定 -->
<img :src="logoUrl" alt="Logo">
</div>
</template>
<script>
import logoUrl from '../assets/logo.png';
export default {
data() {
return {
logoUrl
};
}
};
</script>五、开发体验优化 #
5.1 配置开发服务器 #
// webpack.config.js
module.exports = {
// ... 其他配置
devServer: {
static: {
directory: path.join(__dirname, 'public'), // 静态文件目录
},
compress: true, // 启用 gzip 压缩
port: 8080, // 端口号
open: true, // 自动打开浏览器
hot: true, // 热更新
historyApiFallback: true, // Vue Router history 模式支持
proxy: {
// 代理配置
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
};5.2 配置 source map(调试用) #
// webpack.config.js
module.exports = {
// 开发环境推荐:eval-cheap-module-source-map
// 生产环境推荐:source-map 或 false
devtool: 'eval-cheap-module-source-map'
};source map 类型对比:
| 类型 | 构建速度 | 重建速度 | 生产环境 | 品质 |
|---|---|---|---|---|
| (none) | 最快 | 最快 | 安全 | 无 |
| eval | 快 | 最快 | 不安全 | 生成代码 |
| eval-cheap-source-map | 较快 | 快 | 不安全 | 转换代码(行) |
| eval-cheap-module-source-map | 中等 | 快 | 不安全 | 源代码(行) |
| source-map | 慢 | 最慢 | 安全 | 源代码 |
5.3 配置别名(@ 符号) #
// webpack.config.js
const path = require('path');
module.exports = {
resolve: {
// 配置别名
alias: {
'@': path.resolve(__dirname, 'src'),
'components': path.resolve(__dirname, 'src/components'),
'views': path.resolve(__dirname, 'src/views'),
'assets': path.resolve(__dirname, 'src/assets')
},
// 省略后缀名
extensions: ['.js', '.vue', '.json']
}
};使用示例:
// 之前
import App from '../../src/App.vue';
// 配置别名后
import App from '@/App.vue';
import Header from '@/components/Header.vue';5.4 区分开发和生产环境 #
创建三个配置文件:
webpack/
├── webpack.common.js # 公共配置
├── webpack.dev.js # 开发环境配置
└── webpack.prod.js # 生产环境配置安装 webpack-merge:
npm install webpack-merge -D公共配置 webpack.common.js:
// webpack/webpack.common.js
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/main.js',
module: {
rules: [
{ test: /\.vue$/, loader: 'vue-loader' },
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset',
parser: { dataUrlCondition: { maxSize: 8 * 1024 } },
generator: { filename: 'images/[name].[hash:8][ext]' }
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, '../src')
},
extensions: ['.js', '.vue', '.json']
}
};开发配置 webpack.dev.js:
// webpack/webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
output: {
filename: 'js/[name].js',
path: path.resolve(__dirname, '../dist')
},
devtool: 'eval-cheap-module-source-map',
devServer: {
static: './dist',
hot: true,
port: 8080,
open: true,
historyApiFallback: true
}
});生产配置 webpack.prod.js:
// webpack/webpack.prod.js
const { merge } = require('webpack-merge');
const path = require('path');
const common = require('./webpack.common.js');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
output: {
filename: 'js/[name].[contenthash:8].js',
path: path.resolve(__dirname, '../dist'),
publicPath: '/'
},
devtool: 'source-map',
plugins: [
new CleanWebpackPlugin() // 每次构建前清理 dist
],
optimization: {
splitChunks: {
chunks: 'all' // 代码分割
}
}
});更新 package.json:
{
"scripts": {
"dev": "webpack serve --config webpack/webpack.dev.js",
"build": "webpack --config webpack/webpack.prod.js"
}
}六、生产环境优化 #
6.1 代码分割(Code Splitting) #
为什么要代码分割?
- 减小单个文件体积
- 利用浏览器缓存(第三方库单独打包)
- 按需加载(懒加载路由组件)
配置示例:
// webpack.prod.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 对所有模块进行分割
cacheGroups: {
// 第三方库单独打包
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10
},
// 公共代码提取
common: {
name: 'common',
minChunks: 2, // 至少被引用 2 次
chunks: 'all',
priority: 5,
reuseExistingChunk: true
}
}
},
// 运行时代码单独打包
runtimeChunk: {
name: 'runtime'
}
}
};打包结果:
dist/
├── js/
│ ├── runtime.[hash].js # Webpack 运行时
│ ├── vendors.[hash].js # 第三方库(vue、vue-router 等)
│ ├── common.[hash].js # 公共代码
│ └── main.[hash].js # 业务代码
└── index.html6.2 路由懒加载 #
配合 Vue Router 实现路由懒加载:
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{
path: '/',
name: 'Home',
// 懒加载:访问时才加载
component: () => import('@/views/Home.vue')
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue')
},
{
path: '/user/:id',
name: 'User',
component: () => import(/* webpackChunkName: "user" */ '@/views/User.vue')
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;魔法注释 /* webpackChunkName: "user" */ 可以指定 chunk 名称。
6.3 压缩代码 #
Webpack 5 生产模式默认使用 Terser 压缩 JS:
// webpack.prod.js
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // 移除 console
drop_debugger: true // 移除 debugger
}
}
})
]
}
};6.4 提取 CSS 到单独文件 #
安装 mini-css-extract-plugin:
npm install mini-css-extract-plugin -D配置:
// webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 替代 style-loader
'css-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[id].[contenthash:8].css'
})
]
};6.5 CSS 压缩 #
安装 css-minimizer-webpack-plugin:
npm install css-minimizer-webpack-plugin -D配置:
// webpack.prod.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
'...', // 保留默认的 JS 压缩
new CssMinimizerPlugin()
]
}
};6.6 Gzip 压缩 #
安装 compression-webpack-plugin:
npm install compression-webpack-plugin -D配置:
// webpack.prod.js
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionPlugin({
test: /\.(js|css|html)$/, // 压缩的文件类型
threshold: 10240, // 大于 10KB 才压缩
algorithm: 'gzip' // 压缩算法
})
]
};6.7 分析打包体积 #
安装 webpack-bundle-analyzer:
npm install webpack-bundle-analyzer -D配置:
// webpack.prod.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
plugins: [
// 打包后自动打开分析页面
new BundleAnalyzerPlugin({
analyzerMode: 'static', // 生成静态 HTML 文件
openAnalyzer: false // 不自动打开浏览器
})
]
};七、完整配置文件 #
7.1 公共配置 #
// webpack/webpack.common.js
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main: './src/main.js'
},
module: {
rules: [
// Vue 单文件组件
{
test: /\.vue$/,
loader: 'vue-loader'
},
// JavaScript + Babel
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
// CSS
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// Less
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
// 图片
{
test: /\.(png|jpe?g|gif|svg|webp)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 8KB
}
},
generator: {
filename: 'images/[name].[hash:8][ext]'
}
},
// 字体
{
test: /\.(woff2?|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash:8][ext]'
}
},
// 媒体文件
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)$/i,
type: 'asset/resource',
generator: {
filename: 'media/[name].[hash:8][ext]'
}
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
title: 'Vue App',
favicon: './public/favicon.ico',
minify: false
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, '../src'),
'components': path.resolve(__dirname, '../src/components'),
'views': path.resolve(__dirname, '../src/views'),
'assets': path.resolve(__dirname, '../src/assets'),
'api': path.resolve(__dirname, '../src/api'),
'utils': path.resolve(__dirname, '../src/utils'),
'store': path.resolve(__dirname, '../src/store')
},
extensions: ['.js', '.vue', '.json'],
symlinks: false
}
};7.2 开发配置 #
// webpack/webpack.dev.js
const { merge } = require('webpack-merge');
const path = require('path');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
output: {
filename: 'js/[name].js',
path: path.resolve(__dirname, '../dist'),
publicPath: '/'
},
devtool: 'eval-cheap-module-source-map',
devServer: {
static: {
directory: path.join(__dirname, '../public')
},
compress: true,
host: '0.0.0.0',
port: 8080,
open: true,
hot: true,
historyApiFallback: true,
client: {
overlay: {
errors: true,
warnings: false
}
},
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
},
cache: {
type: 'memory' // 内存缓存,加速构建
}
});7.3 生产配置 #
// webpack/webpack.prod.js
const { merge } = require('webpack-merge');
const path = require('path');
const common = require('./webpack.common.js');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = merge(common, {
mode: 'production',
output: {
filename: 'js/[name].[contenthash:8].js',
chunkFilename: 'js/[name].[contenthash:8].chunk.js',
path: path.resolve(__dirname, '../dist'),
publicPath: '/',
assetModuleFilename: 'assets/[name].[hash:8][ext]'
},
devtool: 'source-map',
module: {
rules: [
// 生产环境提取 CSS
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
}
]
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css'
}),
new CompressionPlugin({
test: /\.(js|css|html|svg)$/,
threshold: 10240,
algorithm: 'gzip'
}),
// 打包分析(按需开启)
// new BundleAnalyzerPlugin()
],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
parallel: true // 多进程并行
}),
new CssMinimizerPlugin()
],
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 20000,
maxSize: 244000,
cacheGroups: {
vue: {
test: /[\\/]node_modules[\\/](vue|vue-router|pinia|vuex)[\\/]/,
name: 'vue-vendors',
chunks: 'all',
priority: 20
},
elementPlus: {
test: /[\\/]node_modules[\\/](element-plus|@element-plus)[\\/]/,
name: 'element-plus',
chunks: 'all',
priority: 15
},
vendors: {
test: /[\\/]node_modules[\\/]/,
name(module) {
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
return `npm.${packageName.replace('@', '')}`;
},
chunks: 'all',
priority: 10
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
priority: 5,
reuseExistingChunk: true
}
}
},
runtimeChunk: {
name: 'runtime'
}
},
performance: {
hints: 'warning',
maxAssetSize: 512000, // 500KB
maxEntrypointSize: 512000 // 500KB
}
});八、常见问题 #
Q1: 为什么修改代码后页面没有更新? #
原因:热更新没生效或缓存问题
解决:
// 确保 devServer.hot 为 true
devServer: {
hot: true
}
// 或者在入口文件添加热更新代码
if (module.hot) {
module.hot.accept();
}Q2: 打包后图片/字体找不到? #
原因:publicPath 配置不正确
解决:
output: {
publicPath: process.env.NODE_ENV === 'production' ? '/你的部署路径/' : '/'
}Q3: Vue 组件样式不生效? #
原因:Loader 顺序错误或缺少配置
解决:
// Loader 执行顺序:从右到左,从下到上
// 正确顺序:style-loader -> css-loader -> less-loader
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}Q4: 打包后文件太大怎么办? #
解决步骤:
- 开启代码分割:
splitChunks - 路由懒加载:
() => import('./views/xxx.vue') - 第三方库按需引入:
// 全量引入 import _ from 'lodash'; // 按需引入 import debounce from 'lodash/debounce'; - 使用 Bundle Analyzer 分析:找出大文件
- 开启 Gzip 压缩
Q5: 开发环境跨域怎么解决? #
解决:配置 devServer 代理
devServer: {
proxy: {
'/api': {
target: 'https://example.com',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}Q6: 如何配置环境变量? #
方法1:使用 DefinePlugin
const webpack = require('webpack');
plugins: [
new webpack.DefinePlugin({
'process.env': JSON.stringify(process.env),
'process.env.API_URL': JSON.stringify('https://api.example.com')
})
]方法2:使用 .env 文件
# 安装 dotenv
npm install dotenv -D// webpack.config.js
const dotenv = require('dotenv');
dotenv.config({ path: './.env.development' });九、总结速记 #
Loader 速查表 #
| Loader | 作用 | 示例 |
|---|---|---|
vue-loader |
处理 .vue 文件 | { test: /\.vue$/, loader: 'vue-loader' } |
babel-loader |
ES6+ 转 ES5 | { test: /\.js$/, loader: 'babel-loader' } |
css-loader |
处理 CSS 文件 | 解析 @import 和 url() |
style-loader |
将 CSS 注入页面 | 配合 css-loader 使用 |
less-loader |
Less 转 CSS | 需要 less 依赖 |
sass-loader |
Sass 转 CSS | 需要 sass 依赖 |
file-loader |
处理文件(Webpack 4) | 输出文件到目录 |
url-loader |
小文件转 base64 | 需要配置 limit |
ts-loader |
处理 TypeScript | 需要 typescript |
Plugin 速查表 #
| Plugin | 作用 |
|---|---|
VueLoaderPlugin |
vue-loader 必需插件 |
HtmlWebpackPlugin |
生成 HTML 文件 |
CleanWebpackPlugin |
清理输出目录 |
MiniCssExtractPlugin |
提取 CSS 到单独文件 |
CssMinimizerPlugin |
压缩 CSS |
TerserPlugin |
压缩 JS |
CompressionPlugin |
Gzip 压缩 |
BundleAnalyzerPlugin |
分析打包体积 |
DefinePlugin |
定义环境变量 |
常用命令 #
| 命令 | 作用 |
|---|---|
npm run dev |
启动开发服务器 |
npm run build |
生产环境打包 |
webpack --config xxx.js |
指定配置文件 |
webpack --watch |
监听文件变化 |
webpack --profile --json > stats.json |
输出打包分析数据 |
最佳实践清单 #
| 项目 | 建议 |
|---|---|
| 模式 | 开发用 development,生产用 production |
| source map | 开发用 eval-cheap-module-source-map |
| 缓存 | 使用 [contenthash] 命名 |
| 代码分割 | 开启 splitChunks |
| 懒加载 | 路由组件懒加载 |
| 压缩 | 生产环境开启 JS/CSS 压缩 |
| 分析 | 定期使用 Bundle Analyzer 分析 |
附录:推荐资源 #
| 资源 | 链接 |
|---|---|
| Webpack 官方文档 | https://webpack.js.org |
| Webpack 中文文档 | https://webpack.docschina.org |
| Vue Loader 文档 | https://vue-loader.vuejs.org |
| Babel 文档 | https://babeljs.io |
最后更新:2026-03-28