基础篇
1.创建vue项目
npm init vue@latest
2. 删除package.json中不用的依赖
官方创建的项目一般没有问题,不放心的可以根据提示命令,启动服务
2.1 删除devDependencies
中以下的内容
{
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"vite": "^4.3.5"
}
2.2 删除index.html 中的引入
<script type="module" src="/src/main.js"></script>
3. 安装 webpack 相关依赖
npm install webpack webpack-cli webpack-dev-server -D
完成后package.json
的devDependencies
中会增加以下内容
{
"webpack": "^5.85.1",
"webpack-cli": "^5.1.3",
"webpack-dev-server": "^4.15.0"
}
4. 创建webpack配置文件,并写入代码
// build/webpack.base.conf.js
const path = require("path");
module.exports = {
entry: path.resolve(__dirname, "../src/main.js"), // 入口文件,打包从这个文件开始
output: {
publicPath: '/',
path: path.resolve(__dirname, "../dist"), // 出口文件,打包生成的文件放置到这个文件夹下
filename: "./js/[name].[chunkhash.6].js" //打包成的文件名。name取的原始文件名,chunkhash生成哈希值,这样每次打包出来不一样,避免浏览器缓存读取旧文件。
},
mode: "development" //开发模式
};
5. 修改package.json
的script
"scripts": {
"dev": "webpack --config ./build/webpack.base.conf.js --progress --color -w --host 0.0.0.0"
}
//--progress: 启用在构建过程中打印编译进度
//--color: 启用控制台颜色
//--watch或-w: 监听文件变化
//--host 0.0.0.0 通过ip可以访问前端服务
6. 配置本地开发服务
6.1 在webpack.base.conf.js中添加devServer配置
devServer: {
hot: true, //模块的热替换
open: true, // 编译结束后自动打开浏览器
port: 8080, // 设置本地端口号
host: "localhost" //设置本地url
}
6.2 修改package.json文件中的script命令配置
"scripts": {
"dev": "webpack server --config ./build/webpack.base.conf.js --progress --color --host 0.0.0.0"
}
7. 配置html插件
7.1 安装依赖
npm install html-webpack-plugin -D
7.2 在 webpack.base.conf.js 中引入依赖,并配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...其他配置
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html", //用来做模板的html的文件路径(从项目根目录开始)
filename: "index.html", //生成的html的名字
title:'vue3+webpack5',//这个就对应上文的title
inject: "body" //打包出来的那个js文件,放置在生成的body标签内
})
]
}
7.3 根据插件配置, 将index.html移入public文件夹中,并将title修改为
<%= htmlWebpackPlugin.options.title %>
8. 配置vue
8.1 安装依赖
npm i vue-loader @vue/compiler-sfc -D
8.2 在 webpack.base.conf.js 中引入依赖,并配置
const {VueLoaderPlugin} = require("vue-loader/dist/index")
module.exports = {
// ...其他配置
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader"
}
]
},
plugins: [
new VueLoaderPlugin()
]
}
9. 配置babel ,解决浏览器不支持ES6
9.1 安装依赖
// 将js代码转换成浏览器能识别的代码
npm i babel-loader @babel/core @babel/preset-env -D
// babel/runtime 可以通过引用babel/runtime中的方法补全 当前运行环境中并没有实现的一些方法
// babel/plugin-transform-runtime 自动引入babel/runtime中的方法,不需手动引入
npm install @babel/runtime @babel/plugin-transform-runtime -D
9.2 修改 webpack.base.conf.js
中的配置
module.exports = {
// ...其他配置
module: {
rules: [
{
test: /\.(js)$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
plugins: ["@babel/plugin-transform-runtime"],
cacheDirectory: true
}
},
exclude: /node_modules/
}
]
}
}
10. 配置css-loader
10.1 安装依赖
npm install style-loader css-loader -D
// sass 和 less 可二选一(本文以sass为例)
npm i sass sass-loader -D
npm i less less-loader -D
// postcss-loader & autoprefixer 自动补全浏览器前缀
npm i postcss-loader autoprefixer -D
// postcss-loader 配合 postcss-pxtorem 也可实现自动将px转换成rem
10.2 修改 webpack.base.conf.js 中的配置
module.exports = {
// ...其他配置
module: {
rules: [
{
test: /\.css$/,
// 放在最后面,最早执行
use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', "sass-loader", "postcss-loader"]
}
]
}
}
10.3 创建postcss-loader配置文件(postcss.config.js)
module.exports = {
plugins: {
"autoprefixer": {
"overrideBrowserslist": [
"ie >= 8", // 兼容IE7以上浏览器
"Firefox >= 3.5", // 兼容火狐版本号大于3.5浏览器
"chrome >= 35", // 兼容谷歌版本号大于35浏览器,
"opera >= 11.5", // 兼容欧朋版本号大于11.5浏览器
]
}
}
};
10.4 package.json 添加浏览器限制
"browserslist": [
"> 0.1%",
"last 2 versions"
]
11. 配置图片访问
// webpack.base.conf.js
module.exports = {
// ...其他配置
output: {
assetModuleFilename: "assets/img/[name][ext]" // 自定义asset module资源打包后的路径和名字
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/,
type: 'asset', // asset 资源类型可以根据指定的图片大小来判断是否需要转化为 base64
generator: {
filename: 'assets/img/[hash][ext][query]'// 局部指定输出位置,这里配置的文件输出路径优先级比第一步的配置高
},
parser: {
dataUrlCondition: {
maxSize: 30 * 1024 // 限制于 30kb
}
}
}
]
}
}
12. 配置静态资源访问
// webpack.base.conf.js
function resolve(dir) {
return path.join(__dirname, "..", dir)
}
module.exports = {
// ...其他配置
resolve: {
// 快捷访问路径配置
alias: {
"@": resolve("src"),
"@components": resolve("src/components"),
"@assets": resolve("src/assets"),
"@img": resolve("src/assets/img")
}
}
}
13. 修改router/index.js
删除 import.meta.env.BASE_URL
14.字体文件解析配置(没有字体文件,可忽略这一步)
module.exports = {
// ...其他配置
module: {
rules: [
{
test: /\.(eot|svg|ttf|woff|woff2|)$/,
type: "asset/resource",
generator: {
filename: "assets/fonts/[hash:8].[name][ext]"
}
}
]
}
}
此时 启动项目 npm run dev
, 则可以看到vue 官方示例的页面
15.css打包优化
15.1 安装依赖
// 将css抽离为文件, 以link的方式引入
npm i mini-css-extract-plugin -D
// 压缩css
npm i css-minimizer-webpack-plugin -D
15.2 修改webpack.base.conf.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
// ...其他配置
optimization: {
minimizer: [
new CssMinimizerPlugin(),
]
},
module: {
// 将style-loader修改为MiniCssExtractPlugin.loader
rules: [
// 将css 和scss 合并为一个
{
test: /\.s[ac]ss|css$/i,
// 放在最后面,最早执行
use: [MiniCssExtractPlugin.loader, 'css-loader', "sass-loader", "postcss-loader"]
}
]
},
plugins: {
new MiniCssExtractPlugin({
filename: "assets/styles/[contenthash].css" // 配置css打包之后的存放路径(这个配置contenthash在开发环境会导致更新css报错,开发环境用name)
})
}
}
16. JS打包优化
16.1 安装依赖
npm install terser-webpack-plugin -D
16.2 修改webpack.base.conf.js
module.exports = {
// ...其他配置
optimization: {
minimizer: [
// ...其他配置
new TerserWebpackPlugin()
]
}
}
17. 配置打包
17.1 安装依赖
npm i webpack-merge -D
17.2 webpack.base.conf.js 删除devServer配置项,删除HtmlWebpackPlugin 配置
// const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...其他配置
// devServer: {
// hot: true, // 模块热加载
// open: true, // 编译结束后,自动打开浏览器
// port: 8081, // 设置本地端口
// host: "localhost" // 设置本地url
// }
plugins: [
// new HtmlWebpackPlugin({
// template: "./public/index.html", //用来做模板的html的文件路径(从项目根目录开始)
// filename: "index.html", //生成的html的名字
// title: 'vue3+webpack5',//这个就对应上文的title
// inject: "body" //打包出来的那个js文件,放置在生成的body标签内
// })
]
}
17.3 新建文件webpack.dev.conf.js
const { merge } = require("webpack-merge")
const BaseWebpackConf = require("./webpack.base.conf")
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = merge(BaseWebpackConf, {
mode: "development", // 开发模式
devServer: {
hot: true, // 模块热加载
open: true, // 编译结束后,自动打开浏览器
port: 8081, // 设置本地端口
host: "localhost" // 设置本地url
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html", //用来做模板的html的文件路径(从项目根目录开始)
filename: "index.html", //生成的html的名字
title: 'vue3+webpack5',//这个就对应上文的title
inject: "body" //打包出来的那个js文件,放置在生成的body标签内
})
]
})
17.4 修改package.json 配置
"scripts": {
"dev": "webpack server --config ./build/webpack.dev.conf.js --progress --color --host 0.0.0.0"
}
17.5 新建文件 webpack.build.conf.js
const path = require("path");
const { merge } = require("webpack-merge")
const BaseWebpackConf = require("./webpack.base.conf")
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserWebpackPlugin = require("terser-webpack-plugin")
const consoleObj = function () {
if (process.env.NODE_ENV === "production") {
return {
// 多进程
parallel: true,
// 删除注释
extractComments: false,
terserOptions: {
compress: {
// 生产环境去除console
drop_console: true,
drop_debugger: true
}
}
};
} else {
return {
// 多进程
parallel: true
};
}
};
function resolve(dir) {
return path.join(__dirname, "..", dir)
}
module.exports = merge(BaseWebpackConf, {
mode: "production", // 发布模式
devtool: "nosources-source-map",
output: {
path: path.resolve(__dirname, "../dist"),
filename: "assets/js/[name].[contenthash:6].js",
clean: true
},
optimization: {
minimize: true,
minimizer: [
new TerserWebpackPlugin(consoleObj())
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html", // 用来做模板的html的文件路径
filename: "index.html", // 生成的html的名字
title: "vue3+webpack5", // 这个就对应上文的title
inject: "body", // 打包出来的那个js文件,放置在生成的body标签内
minify: {
collapseWhitespace: true, // 去掉空格
removeComments: true // 去掉注释
}
})
]
})
17.6 配置静态资源输出
17.6.1 安装依赖
npm i copy-webpack-plugin -D
17.6.2 修改webpack.build.conf.js
const copyWebpackPlugin = require("copy-webpack-plugin")
module.exports = merge(BaseWebpackConf, {
// ...其他配置
mode: "production", // 发布模式
plugins: [
// ...其他配置
//静态资源输出到根目录
new copyWebpackPlugin({
patterns: [
{
from: resolve("/public"),
to: resolve("/dist"), //放到output文件夹下
globOptions: {
dot: true,
gitignore: false,
ignore: [
// 配置不用copy 的文件, public中没有index.html时,可以不用忽略
"**/index.html"
]
}
}
]
})
]
})
17.6.3 配置package.json 脚本命令
"scripts": {
"build": "webpack --config ./build/webpack.build.conf.js --color"
}
这一步配置完,可以执行命令 npm run build
,执行完会生成dist文件夹
下载地址
高级篇
1. 区分环境
1.1 安装依赖
npm install cross-env -D
npm i dotenv -D
1.2 新建.env、.env.dev、.env.prod文件
// .env
# 公共环境配置
VUE_APP_TITLE = "webpack5 + vue3"
//.env.dev
NODE_ENV = "development"
VUE_APP_BASE_URL = "/api"
VUE_APP_WEBSERVER = "http://localhost:8080"
//.env.prod
NODE_ENV = "production"
VUE_APP_BASE_URL = "/api"
VUE_APP_WEBSERVER = "http://192.168.1.1:8080"
1.3 修改webpack.dev.conf.js
和webpack.build.conf.js
中的HtmlWebpackPlugin
配置
module.exports = {
// ...其他配置
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html", //用来做模板的html的文件路径(从项目根目录开始)
filename: "index.html", //生成的html的名字
title: process.env.VUE_WEB_TITLE, //这个就对应.env 文件中的变量
inject: "body" //打包出来的那个js文件,放置在生成的body标签内
})
]
}
1.4 修改webpack.base.conf.js
const webpack = require("webpack");
const envMode = process.env.envMode;
require("dotenv").config({ path: `.env` }) // 执行 .env 文件, 将变量放到process.env上
require("dotenv").config({ path: `.env.${envMode}` }) // 执行 .env.${envMode} 文件, 可覆盖和.env文件相同的部分
// 正则匹配VUE_APP_开头的变量
const prefixRe = /^VUE_APP_/;
let env = {};
for (const key in process.env) {
// 只有 NODE_ENV, BASE_URL 和以 VUE_APP_ 开头的变量可以通过 webpack.DefinePlugin 静态嵌入到代码文件中
if (key == "NODE_ENV" || key == "BASE_URL" || prefixRe.test(key)) {
env[key] = JSON.stringify(process.env[key])
}
}
module.exports = {
// ...其他配置
optimization: {
// ...其他配置
nodeEnv: false // 以DefinePlugin设置为准, 避免mode存在时,NODE_ENV冲突
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
...env
},
__VUE_OPTIONS__: false, // 避免控制台警告信息
__VUE_PROD_DEVTOOLS__: false
})
]
}
1.5 修改package.json
{
// 这里的envMode的值对应.env文件的后缀名,在webpack.base.conf.js中根据envMode读取不同环境的变量
"dev": "cross-env envMode=dev webpack serve --config ./build/webpack.dev.conf.js --color --host 0.0.0.0",
"prod": "cross-env envMode=prod webpack serve --config ./build/webpack.dev.conf.js --color --host 0.0.0.0",
"build:dev": "cross-env envMode=dev webpack --config ./build/webpack.build.conf.js --color",
"build:prod": "cross-env envMode=prod webpack --config ./build/webpack.build.conf.js --color"
}
若prod有不同于dev的配置,也可单独写一个webpack.prod.conf.js文件配置, package.json也修改要执行的文件。
1.6 验证区分环境
1.6.1 修改AboutView.vue
<template>
<div class="about">
<h1>This is an about page</h1>
<div> {{ webUrl }}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const webUrl = ref(process.env.VUE_APP_WEBSERVER)
</script>
1.6.2 执行 npm run dev
,页面webUrl
显示为"http://localhost:8080"
,对应.env.dev
中的VUE_APP_WEBSERVER
1.6.3 执行 npm run prod
,页面webUrl
显示为"http://192.168.1.1:8080"
,对应.env.prod
中的VUE_APP_WEBSERVER
2. "/about"
页面下刷新,页面显示 “Cannot GET /about”
解决方案: devServer
添加historyApiFallback
配置
// webpack.base.conf.js
module.exports = {
devServer: {
hot: true, //模块的热替换
open: true, // 编译结束后自动打开浏览器
port: 8081, // 设置本地端口号
host: "localhost", //设置本地url
historyApiFallback: {
rewrites: [{
from: /.*/g,
to: '/index.html'
}]
}
}
}