一、开发步骤
1.1 安装依赖
# 初始化项目
npm init -y
# webpack相关
npm install webpack webpack-cli webpack-dev-server -D
# 相关插件
npm install html-webpack-plugin copy-webpack-plugin cross-env -D
# css相关
npm install css-loader style-loader less-loader sass-loader sass stylus-loader -D
npm install postcss postcss-loader postcss-preset-env -D
npm install mini-css-extract-plugin -D
# eslint相关 @babel/eslint-parser: 解析最新js语法如(箭头函数,异步函数等)eslint版本不同,配置不同
npm install eslint@7.32.0 eslint-plugin-vue@7.20.0 @babel/eslint-parser@7.27.5 -D
# vue相关
npm install vue vue-router pinia --save
npm install vue-loader@next vue-style-loader @vue/compiler-sfc -D
# 压缩插件
npm install css-minimizer-webpack-plugin -D
npm install terser-webpack-plugin -D
npm i image-minimizer-webpack-plugin@3.8.3 imagemin@8.0.1 imagemin-mozjpeg@9.0.0 imagemin-pngquant@9.0.0 imagemin-gifsicle@7.0.0 imagemin-svgo@10.0.1 -D
1.2 webpack.config.js
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const EslintWebpackPlugin = require('eslint-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
const { DefinePlugin } = require('webpack');
const isProduction = process.env.NODE_ENV == 'production';
function getStyleLoader(loaderType) {
return [
isProduction ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
// 处理css兼容性问题,配合package.json中的browserslist使用
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
loaderType
].filter(Boolean)
}
module.exports = {
// 1.入口文件
entry: './src/main.js',
// 2.输出文件
output: {
path: isProduction ? path.resolve(__dirname, '../dist') : undefined,
filename: isProduction ? 'static/js/[name].[contenthash:10].js' : 'static/js/[name].js', // 输出文件目录
chunkFilename: isProduction ? 'static/js/[name].[contenthash:10].chunk.js' : 'static/js/[name].chunk.js', // 通过import动态导入,或npm安装到node_module中使用的,打包成单独文件
assetModuleFilename: 'static/media/[hash:10][ext][query]', // 图片视频等资源
clean: true
},
// 3.loader加载器(处理非JS资源,如:vue文件,css/less/scss,图片,字体,js-> babel转译)
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
// 处理css
{
test: /\.css$/i,
use: getStyleLoader()
},
// 处理less
{
test: /\.less$/i,
use: getStyleLoader('less-loader')
},
// 处理scss
{
test: /\.s[ac]ss$/i,
use: getStyleLoader('sass-loader')
},
// 处理stylus
{
test: /\.styl$/i,
use: getStyleLoader('stylus-loader')
},
// 图片等资源
{
test: /\.(png|jpe?g|gif|webp|svg)/,
type: 'asset',
parser: {
dataUrlCondition: {
// 小于10kb的图片转base64
// 优点:减少请求数量。缺点:体积会更大
maxSize: 10 * 1024 // 10kb
}
}
},
// 字体视频等
{
test: /\.(ttf|woff2?|mp3|mp4|avi)$/i,
type: 'asset/resource', // 原生不动输出
},
// 处理js文件
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_module中的js
loader: 'babel-loader',
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存压缩
},
},
]
},
// 4.插件(拓展功能:生成html,eslint,提取css单独文件)
plugins: [
new VueLoaderPlugin(),
// 生成HTML文件并注入资源
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
new EslintWebpackPlugin({
context: path.resolve(__dirname, '../src'),
exclude: 'node_modules',
cache: true, // 开启缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'),
}),
// 明确设置 Vue 3 特性标志
new DefinePlugin({
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false
}),
isProduction && new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist'),
globOptions: {
ignore: ['**/index.html'], // 忽略index.html文件
}
}
]
}),
// 提取css到单独文件
isProduction && new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css', // 动态导入css的命名
}),
].filter(Boolean),
// 5.模式
mode: isProduction ? 'production' : 'development',
// 优化
optimization: {
// 是否压缩
minimize: isProduction,
minimizer: [
new CssMinimizerPlugin(),
// 默认的Terser配置已足够,除非需要特殊处理(多线程,删除console)
new TerserWebpackPlugin({
terserOptions: {
compress: {
defaults: true, // 启用基础压缩
drop_console: true, // 删除console
},
}
}),
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminMinify,
options: {
plugins: [
// JPEG 压缩(有损)
['imagemin-mozjpeg', {
quality: 85,
progressive: true
}],
// PNG 压缩(有损)
['imagemin-pngquant', {
quality: [0.65, 0.9],
speed: 4
}],
// GIF 压缩
['imagemin-gifsicle', {
interlaced: true
}],
// SVG 压缩
['imagemin-svgo', {
plugins: [
{ name: 'removeViewBox', active: false },
{ name: 'cleanupIDs', active: false }
]
}]
]
}
},
severityError: 'warning' // 错误降级为警告
})
],
splitChunks: {
chunks: 'all', // 对所有模块进行分割
},
runtimeChunk: { name: (entry) => `runtime-${entry.name}.js` }
},
// 开发服务器
devServer: {
host: 'localhost', // 域名
port: '8000', // 端口号
open: true, // 是否自动打开浏览器
historyApiFallback: true, // 将所有404请求重定向到入口文件(通常是 index.html),让前端路由接管URL解析
},
// 解析器
resolve: {
extensions: ['.vue', '.js', '.json'], // 添加拓展名,默认['.js', '.json', '.wasm']
alias: {
'@': path.resolve(__dirname, 'src'), // 别名
}
},
// 源代码与构建代码的映射-提升开发体验
devtool: isProduction ? 'source-map' : 'cheap-module-source-map',
}
1.3 .eslintrc.js
module.exports = {
root: true,
env: {
node: true, // 启动node中全局变量(console)
},
extends: ['plugin:vue/vue3-recommended', 'eslint:recommended'],
// 语法环境
parserOptions: {
parser: '@babel/eslint-parser',
},
rules: {
"no-var": 2, // 禁止使用var定义变量
},
}
1.4 babel.config.js
module.exports = {
presets: ['@vue/cli-plugin-babel/preset']
}
// 内部等效配置(简化版)
// module.exports = {
// presets: [
// [
// '@babel/preset-env',
// {
// useBuiltIns: 'usage', // 按需加载 polyfill
// corejs: 3,
// targets: '> 0.5%, last 2 versions, not dead'
// }
// ]
// ],
// plugins: [
// '@babel/plugin-transform-runtime',
// // Vue 特定的 JSX 支持
// '@vue/babel-plugin-jsx'
// ]
// }
1.5 package.json
{
"name": "webpack-vue3-cli",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config config/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config config/webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@babel/eslint-parser": "^7.27.5",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/compiler-sfc": "^3.5.17",
"copy-webpack-plugin": "^13.0.0",
"cross-env": "^7.0.3",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.2",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^7.20.0",
"eslint-webpack-plugin": "^3.1.1",
"html-webpack-plugin": "^5.6.3",
"image-minimizer-webpack-plugin": "^3.8.3",
"imagemin": "^8.0.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-mozjpeg": "^9.0.0",
"imagemin-pngquant": "^9.0.0",
"imagemin-svgo": "^10.0.1",
"less-loader": "^12.3.0",
"mini-css-extract-plugin": "^2.9.2",
"postcss": "^8.5.6",
"postcss-loader": "^8.1.1",
"postcss-preset-env": "^10.2.3",
"sass": "^1.89.2",
"sass-loader": "^16.0.5",
"style-loader": "^4.0.0",
"stylus-loader": "^8.1.1",
"terser-webpack-plugin": "^5.3.14",
"vue-loader": "^17.3.1",
"vue-style-loader": "^4.1.3",
"webpack": "^5.99.9",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.2"
},
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
],
"dependencies": {
"vue": "^3.5.17"
}
}
二、注意事项
2.1 环境依赖
- 生产环境依赖(dependencies)
- 定义:项目运行时必须的包
- 安装命令:npm install
<package> –save
- 示例:
- vue相关(vue,vue-router,pinia,axios,element-ui等)
- 工具库(lodash-es, dayjs)
- 开发环境依赖(devDependencies)
- 定义:仅在开发/构建阶段需要
- 安装命令:npm install
<package> –save-dev | npm install <package> -D
- 示例:
- 构建工具(webpack,webpack-cli,webpack-dev-server)
- Loaders(vue-loader, babel-loader, css-loader)
- CSS 预处理器(sass,less,postcss)
- 插件类(html-webpack-plugin, mini-css-extract-plugin)
- 模拟生产环境
rm -rf node_modules package-lock.json
npm install --production
2.2 部署静态资源
# 查看全局安装
npm list -g --depth=0
# 安装serve
npm install serve -g
# 启动
serve dist
2.3 相关概念
- css相关
- scss-loader: 将Sass编译成CSS
- css-loader: 将CSS转化成CommonJS模块
- style-loader: 将JS字符串生成为style节点
- vue-style-loader:原生支持 Vue 特性。浏览器中打开开发者工具,查看
<head> 中的 <style> 标签与style-loader不同
- postcss-loader: 解决样式兼容性问题如: display: flex;
- 插件相关
- html-webpack-plugin: 生成HTML文件并注入资源
- mini-css-extract-plugin: 将css抽离成单独模块
- css-minimizer-webpack-plugin: css压缩
- terser-webpack-plugin: js压缩(默认使用,额外配置需添加)
- image-minimizer-webpack-plugin: 图片压缩
- eslint-webpack-plugin: 将ESLint嵌入Webpack
- eslint-plugin-vue: Vue专属规则(模板语法、SFC 结构)
- @babel/eslint-parser: 处理最新的js特性(箭头函数、异步函数、模块化)
- cross-env 强制锁定环境,避免玄学问题