第五篇-Vue3项目中集成axios

什么是 axios?

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。开箱即用的工具

这也是 Vue 官方推荐使用的发送 ajax 请求的工具

axios有哪些特性

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

安装 axios

1
2
3
npm install axios --save
# or
yarn add axios --save

src/App.vue 中使用一下 axios,添加以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<el-config-provider :locale="zhCn">
<div>
<h1>请求的内容</h1>
<div>{{ result }}</div>
</div>
<!-- 忽略其他代码 -->
</el-config-provider>
</template>

<script lang="ts" setup>
// 忽略其他代码
import axios from "axios";
const result = ref("");
axios.get(location.href).then(({ data }) => {
result.value = data;
});
</script>

在浏览器中就可以查看到我们网站的代码了

image-20210908202223220

在日常项目的开发中,通常会有多个后端的服务,而每个服务会有自己的 url 地址、token之类的,通常是使用单独的 axios 的实例处理对应的服务,这就需要我们封装多个 axios 的实例

封装 axios

src 目录下新建一个 axios 文件夹,在其中新建一个 index.ts 文件,这个文件就是用来导出封装好的 axios

使用 axios.create() 方法就可以创建一个 axios 的实例

axios 可以设置全局默认的配置,这些配置会被每个实例共享,实例可以覆盖这些配置

设置全局的参数

  1. 设置全局的接口超时时间 timeout,这个时间是对所有实例通用的

src/axios/index.ts

1
2
import axios from "axios";
axios.defaults.timeout = 60 * 1000; // 设置超时时间是1分钟

创建 axios的实例

假设我们的项目中会用到两个服务(a, b)的接口

接口地址/环境development 开发环境t 测试环境production 生产环境
服务ahttp://a.dev.server.comhttp://a.test.server.comhttp://a.prod.server.com
服务bhttp://b.dev.server.comhttp://b.test.server.comhttp://b.prod.server.com

同一个服务根据不同的运行环境需要使用不同的接口地址,这种情况最好是把接口地址写在环境文件中

.env.development 中添加

1
2
VUE_APP_A_BASE_URL=http://a.dev.server.com
VUE_APP_B_BASE_URL=http://b.dev.server.com

.env.t 中添加

1
2
VUE_APP_A_BASE_URL=http://a.test.server.com
VUE_APP_B_BASE_URL=http://b.test.server.com

.env.production 中添加

1
2
VUE_APP_A_BASE_URL=http://a.prod.server.com
VUE_APP_B_BASE_URL=http://b.prod.server.com

src/axios/index.ts 文件中就可以通过 process.env.VUE_APP_A_BASE_URLprocess.env.VUE_APP_B_BASE_URL 取到对应的服务地址

src/axios/index.ts 添加

1
2
3
4
5
6
7
export const aService = axios.create({
baseURL: process.env.VUE_APP_A_BASE_URL,
});

export const bService = axios.create({
baseURL: process.env.VUE_APP_B_BASE_URL,
});

创建并导出的两个 axios 的服务分别用来处理对应的两个后端服务的接口

设置请求拦截器

请求拦截器可以处理哪些问题
  1. 在请求发送之前需要处理的事情,都可以在请求拦截器中处理

例如每个请求都要在请求头中添加 token

  1. 在请求发送之前遇到的错误都可以在请求拦截器中被处理
语法

axios 设置请求拦截器的语法,要为实例添加拦截器只要把 axios 替换成对应的实例就可以了

1
axios.interceptors.request.use(onFulfilled, onRejected);
  • onFulfilled 函数,接收一个 config 的参数,可以对 config 进行修改,最后返回这个 config
  • onRejected 函数,处理在请求发送之前的错误

请求拦截器的执行顺序是先添加的后执行

封装

src/axios 下新建文件夹 interceptorsinterceptors 新建一个 request 文件夹,这个文件夹中保存所有请求拦截器

  1. 请求错误处理的拦截器

把错误拦截器作为第一个拦截器,可以拦截到所有请求发出之前的错误,在这个也可以给服务器上报错误日志

同一个拦截器中的 onRejected 函数处理不到 onFulfilled 中的异常,所以最后一个请求拦截器的 onRejected 函数是不会被执行的

src/axios/interceptors/request 文件夹下新建 error.ts 文件,这个文件中做对请求开始之前的错误处理

src/axios/interceptors/request/error.ts

1
2
3
4
export default function handleRequestError(error: any): Promise<any> {
// 可以给服务器上报错误
return Promise.reject(error);
}

eslint 提示 Unexpected any. Specify a different type. 在项目根目录下的 .eslintrc.js 文件中 rules 中添加一行 "@typescript-eslint/no-explicit-any": "off",

eslint 提示 Argument ‘error’ should be typed with a non-any type. 在项目根目录下的 .eslintrc.js 文件中 rules 中添加一行 "@typescript-eslint/explicit-module-boundary-types": "off",

src/axios/interceptors/request 文件夹下新建 index.ts 文件,这个文件提供两个添加请求拦截器的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { AxiosInstance, AxiosRequestConfig } from "axios";
import handleRequestError from "./error";

/**
* 给axios的实例添加拦截器
* @param axiosService axios 的实例
* @param requestInterceptorArray 需要添加在实例上的拦截器 二维数组[[拦截器的onFulfilled, 拦截器的onRejected],[...]]
* @returns 返回传入的axios的实例
*/
export function useBaseRequestInterceptor(
axiosService: AxiosInstance,
requestInterceptorArray: [
(config: AxiosRequestConfig) => AxiosRequestConfig,
((error: any) => any) | undefined
][]
): AxiosInstance {
requestInterceptorArray.forEach((interceptor) =>
axiosService.interceptors.request.use(...interceptor)
);
return axiosService;
}

/**
* 给axios的实例添加拦截器
* 在所有拦截器之前会添加一个错误拦截器
* @param axiosService axios 的实例
* @param requestInterceptorArray 需要添加在实例上的拦截器 一维数组,只处理onFulfilled函数
* @returns 返回传入的axios的实例
*/
export default function useRequestInterceptor(
axiosService: AxiosInstance,
requestInterceptorArray: Array<
(config: AxiosRequestConfig) => AxiosRequestConfig
> = []
) {
const interceptors: [
(config: AxiosRequestConfig) => AxiosRequestConfig,
undefined
][] = requestInterceptorArray.map((interceptor) => [interceptor, undefined]);

return useBaseRequestInterceptor(axiosService, [
[(config: AxiosRequestConfig) => config, handleRequestError],
...interceptors,
]);
}

aServicebService 添加拦截器

src/axios/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
import useRequestInterceptor from "./interceptors/request";

export const aService = useRequestInterceptor(
axios.create({
baseURL: process.env.VUE_APP_A_BASE_URL,
})
);

export const bService = useRequestInterceptor(
axios.create({
baseURL: process.env.VUE_APP_B_BASE_URL,
})
);
  1. headers 中添加 token 的请求拦截器

src/axios/interceptors/request 文件夹下新建 token.ts 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { AxiosRequestConfig } from "axios";

/**
* 处理 a 服务的token
* @param config 请求的axios参数
* @returns 处理后的请求的axios参数
*/
export function handleAServiceRequestToken(config: AxiosRequestConfig) {
const token = "a-service-token"; // 这里要根据项目获取真实的token,从vuex或者本地存储中获取
config.headers["token"] = token;
return config;
}

/**
* 处理 b 服务的token
* @param config 请求的axios参数
* @returns 处理后的请求的axios参数
*/
export function handleBServiceRequestToken(config: AxiosRequestConfig) {
const token = "b-service-token"; // 这里要根据项目获取真实的token,从vuex或者本地存储中获取
config.headers["token"] = token;
return config;
}

aServicebService 添加 token 拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import {
handleAServiceRequestToken,
handleBServiceRequestToken,
} from "./interceptors/request/token";

export const aService = useRequestInterceptor(
axios.create({
baseURL: process.env.VUE_APP_A_BASE_URL,
}),
[handleAServiceRequestToken]
);

export const bService = useRequestInterceptor(
axios.create({
baseURL: process.env.VUE_APP_B_BASE_URL,
}),
[handleBServiceRequestToken]
);

还有其他需要在请求拦截器做的,都可以按照这种方式添加

设置响应拦截器

响应拦截器可以处理哪些问题

响应拦截器会在请求成功或失败之后调用

  1. 请求的错误
  2. 在这里判断服务器返回的数据是否有效,无效数据可以当作异常处理
  3. 如果接口返回的是文件可以在这里完成文件的下载
  4. 等等。。。
语法

axios 设置响应拦截器的语法,要为实例添加拦截器只要把 axios 替换成对应的实例就可以了

1
axios.interceptors.response.use(onFulfilled, onRejected);
  • onFulfilled 函数,接收一个 AxiosResponse 的返回结果,可以对处理返回的接口进行修改,最后返回一个结果
  • onRejected 函数,处理请求异常的错误

响应拦截器的执行顺序是先添加的先执行

建议在拦截器中返回 result ,方便后续插拔拦截器的处理,可以考虑在错误拦截器之前的最后一个拦截器中返回 result.data
封装

src/axios/interceptors 下新建一个 response 文件夹,这个文件夹中保存所有响应拦截器

同一个拦截器中的 onRejected 函数处理不到 onFulfilled 中的异常,所以第一个响应拦截器的 onRejected 函数是不会被执行的

  1. 响应错误处理的拦截器

src/axios/interceptors/response 文件夹下新建 error.ts 文件,这个文件中做对请求响应之后的错误拦截

把错误拦截器作为最后一个拦截器,可以拦截到所有响应拦截器中的错误

src/axios/interceptors/response/error.ts

1
2
3
4
5
6
7
8
9
10
11
12
import { ElMessage } from "element-plus";

/**
* 处理 axios 实例的响应错误
* @param error 响应错误消息
* @returns rejected 状态的promise
*/
export default function handleResponseError(error: any): Promise<any> {
// 给服务器上传错误日志
ElMessage.error(error);
return Promise.reject(error);
}

src/axios/interceptors/response 文件夹下新建 index.ts 文件,这个文件提供两个添加响应拦截器的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import { AxiosInstance, AxiosResponse } from "axios";
import handleResponseError from "./error";

/**
* 给axios的实例添加拦截器
* @param axiosService axios 的实例
* @param responseInterceptorArray 需要添加在实例上的拦截器 二维数组[[拦截器的onFulfilled, 拦截器的onRejected],[...]]
* @returns 返回传入的axios的实例
*/
export function useBaseResponseInterceptor(
axiosService: AxiosInstance,
responseInterceptorArray: [
(result: AxiosResponse) => any,
((error: any) => any) | undefined
][]
): AxiosInstance {
responseInterceptorArray.forEach((interceptor) =>
axiosService.interceptors.response.use(...interceptor)
);
return axiosService;
}

/**
* 给axios的实例添加拦截器
* 在所有拦截器之前会添加一个错误拦截器
* @param axiosService axios 的实例
* @param responseInterceptorArray 需要添加在实例上的拦截器 一维数组,只处理onFulfilled函数
* @returns 返回传入的axios的实例
*/
export default function useResponseInterceptor(
axiosService: AxiosInstance,
responseInterceptorArray: Array<(result: AxiosResponse) => any> = []
) {
const interceptors: [(result: AxiosResponse) => any, undefined][] =
responseInterceptorArray.map((interceptor) => [interceptor, undefined]);

return useBaseResponseInterceptor(axiosService, [
...interceptors,
[(res: AxiosResponse) => res, handleResponseError],
]);
}

aServicebService 添加响应拦截器

src/axios/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import useResponseInterceptor from "./interceptors/response";

export const aService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: process.env.VUE_APP_A_BASE_URL,
}),
[]
),
[handleAServiceRequestToken]
);

export const bService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: process.env.VUE_APP_B_BASE_URL,
}),
[]
),
[handleBServiceRequestToken]
);
  1. 处理后端返回的数据,假设后端返回的 json 中有 code 字段,且只有 200 表示成功,其他的全部按照异常处理,如果异常的话会有 message 字段返回异常信息,在 src/axios/interceptors/response 下新建 filterResponse.ts 文件

src/axios/interceptors/response/filterResponse.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { AxiosResponse } from "axios";
import { ElMessage } from "element-plus";

/**
* 对服务端返回的数据处理
* code !== 200 的都是有异常的
* @param response axios 响应消息
* @returns
*/
export default function handleResponseFilter(
response: AxiosResponse
): AxiosResponse | Promise<AxiosResponse> {
const { data } = response;
if (data.code !== 200) {
ElMessage.error(data.message);
return Promise.reject(response);
}
return response;
}

src/axios/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import handleResponseFilter from "./interceptors/response/filterResponse";

export const aService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: process.env.VUE_APP_A_BASE_URL,
}),
[handleResponseFilter]
),
[handleAServiceRequestToken]
);

export const bService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: process.env.VUE_APP_B_BASE_URL,
}),
[handleResponseFilter]
),
[handleBServiceRequestToken]
);

其他响应拦截器也可以使用这种方式添加

接口请求中展示loading

根据具体项目看要不要添加这个拦截器,这里用来做演示

在请求发出后 500ms 内如果收到了响应就不展示 loading,如果超过 500ms 就展示 loading,在接口响应之后关闭 loading。

src/axios 下创建一个 utils 文件夹,在其中新建一个 loading.ts 文件,用来显示和关闭 loading

src/axios/utils/loading.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { ElLoading, ILoadingInstance } from "element-plus";

let loadingCount = 0;
let loading: ILoadingInstance | null = null;

/**
* 500ms 之后展示loading
*/
export function showLoading(): NodeJS.Timeout {
loadingCount++;
return setTimeout(() => {
if (!loading && loadingCount) {
loading = ElLoading.service();
}
}, 500);
}

/**
* 如果没有loading中的接口,就关闭loading
*/
export function hideLoading() {
loadingCount--;
if (loadingCount === 0 && loading) {
loading.close();
loading = null;
}
}

src/axios/interceptors/requestsrc/axios/interceptors/response 文件夹下新建 loading.ts 文件,在 src/axios/utils 下新建 constants.ts 文件,用来存放常量

src/axios/utils/constants.ts

1
export const HEADER_NO_LOADING = "NO-LOADING"; // 请求头中添加请求不展示loading的字段

src/axios/interceptors/request/loading.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { AxiosRequestConfig } from "axios";
import { showLoading } from "../../utils/loading";
import { HEADER_NO_LOADING } from "../../utils/constants";

/**
* 处理 请求时展示 loading 的拦截器
* @param config
* @returns
*/
export default function handleRequestLoading(
config: AxiosRequestConfig
): AxiosRequestConfig {
const { headers } = config;
// 如果 headers 中有 "NO-LOADING": true 就不展示loading
if (!headers[HEADER_NO_LOADING]) {
showLoading();
}
return config;
}

src/axios/interceptors/response/loading.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { AxiosResponse } from "axios";
import { hideLoading } from "../../utils/loading";
import { HEADER_NO_LOADING } from "../../utils/constants";

/**
* 处理响应成功之后关闭loading的拦截器
* @param result
* @returns
*/
export default function handleResponseLoading(
result: AxiosResponse
): AxiosResponse {
const {
config: { headers },
} = result;
// 如果 headers 中有 "NO-LOADING": true 就不处理loading
if (!headers[HEADER_NO_LOADING]) {
hideLoading();
}
return result;
}

如果带有loading的请求出现了异常,要在 error 拦截器中关闭 loading

src/axios/interceptors/response/error.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { AxiosError } from "axios";
import { ElMessage } from "element-plus";
import { hideLoading } from "../../utils/loading";
import { HEADER_NO_LOADING } from "@/axios/utils/constants";

/**
* 处理 axios 实例的响应错误
* @param error 响应错误消息
* @returns rejected 状态的promise
*/
export default function handleResponseError(
error: AxiosError
): Promise<AxiosError> {
if (!error.config.headers[HEADER_NO_LOADING]) {
hideLoading();
}
// 给服务器上传错误日志
ElMessage.error(error.message);
return Promise.reject(error);
}

src/axios/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import handleRequestLoading from "./interceptors/request/loading";
import handleResponseLoading from "./interceptors/response/loading";

/**
* 给a服务器发送请求的axios实例
*/
export const aService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: process.env.VUE_APP_A_BASE_URL,
}),
[handleResponseLoading, handleResponseFilter]
),
[handleAServiceRequestToken, handleRequestLoading]
);

/**
* 给b服务器发送请求的axios实例
*/
export const bService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: process.env.VUE_APP_B_BASE_URL,
}),
[handleResponseLoading, handleResponseFilter]
),
[handleBServiceRequestToken, handleRequestLoading]
);

loading的拦截器就加完了,其他的项目中需要的拦截器也可以按照这种方式加入

配置反向代理

如果项目开发中,后端的接口提供了跨域请求的支持,那这一步就可以不做了。

但是通常在项目开发中,后端的接口不会提供跨域请求的支持,这个时候就需要我们对请求做一个反向代理,webpack 通过 devServer.proxy 内置了这样的服务。

在根目录的 vue.config.js 文件中添加配置即可

例:给 a、b 服务配置代理 / 代理到 http://localhost:8082 (本地的服务启动的是多少就代理到多少)

首先把 a、b 两个服务的 axios 实例创建时的 baseURL 改成唯一的前缀

src/axios.index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 给a服务器发送请求的axios实例
*/
export const aService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: "/aServer",
}),
[handleResponseLoading, handleResponseFilter]
),
[handleAServiceRequestToken, handleRequestLoading]
);

/**
* 给b服务器发送请求的axios实例
*/
export const bService = useRequestInterceptor(
useResponseInterceptor(
axios.create({
baseURL: "/bServer",
}),
[handleResponseLoading, handleResponseFilter]
),
[handleBServiceRequestToken, handleRequestLoading]
);

然后在 vue.config.js 中配置对应的代理

vue.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module.exports = {
// ... 其他配置
devServer: {
// ...
proxy: {
"/aServer": {
target: process.env.VUE_APP_A_BASE_URL,
changeOrigin: true,
secure: false,
pathRewrite: {
"/aServer": "",
},
},
"/bServer": {
target: process.env.VUE_APP_B_BASE_URL,
changeOrigin: true,
secure: false,
pathRewrite: {
"/bServer": "",
},
},
},
},
}

这样在启动开发环境的时候,就对我们的请求做了反向代理,避免了跨域问题的产生

在项目上线的时候,一般会用一个静态资源服务器做前端入口,比如 nginx,那就可以在 nginx 上做反向代理

上线时候的反向代理

nginx 做反向代理,一般会在项目根目录有一个 deployment 的文件夹,会存放一项目上线用到的配置文件,比如 nginx 的配置文件

在项目根目录下新建 deployment 文件夹,并在其中新建 testprod 两个文件夹,在建立一个 nginx.conf.tmp 文件,这个文件作为我们生成 nginx.conf 的模版文件,需要根据自己项目的部署情况修改参数。

deployment/nginx.conf.tmp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 80;

root /usr/share/nginx/html/dist; # 上线服务器存放的位置

# 默认请求
location / {
try_files $uri $uri/ /index.html; # 解决history路由刷新404的问题
}

location ~ .*\.(js|css)$ {
expires 30d; # 静态资源设置强缓存
}
# proxy_pass placeholder
# 禁止访问 .htxxx 文件
location ~ /.ht {
deny all;
}
}

在新建一个 genNginxConf.js 这个文件可以根据第一个参数创建对应环境的 default.conf 文件,这是部署项目用到的 nginx 的配置文件

deployment/genNginxConf.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require("fs");
const path = require("path");
const dotenv = require("dotenv");
const dotenvExpand = require("dotenv-expand");

const configFile = path.join(__dirname, "../vue.config.js");
const nginxFileName = "default.conf";
const configBaseFile = path.join(__dirname, "./nginx.conf.tmp");
const mode = process.argv[2];

let filePath;
let envPath;
if (mode === "t" || mode === "test") {
filePath = path.join(__dirname, "test", nginxFileName);
envPath = path.join(__dirname, "../.env.t");
} else if (mode === "prod") {
filePath = path.join(__dirname, "prod", nginxFileName);
envPath = path.join(__dirname, "../.env.production");
} else {
console.log(`没有对应的模式:${mode}`);
process.exit(1);
}

// 加载环境变量
const env = dotenv.config({ path: envPath });
dotenvExpand(env);

let proxyPass = `
# 配置反向代理`;

if (fs.statSync(configFile).isFile()) {
const webpackConfig = require(configFile);
const proxy = webpackConfig?.devServer?.proxy;
if (proxy) {
for (const [k, { target, pathRewrite }] of Object.entries(proxy)) {
let metaPath = k;
if (pathRewrite) {
Object.keys(pathRewrite).forEach((p) => {
metaPath = metaPath.replace(p, pathRewrite[p]);
});
}
proxyPass += `
location ${k} {
proxy_pass ${target}${metaPath};
}
`;
}
} else {
console.log("没有配置 devServer.proxy,不需要设置代理");
}
} else {
console.log("没有 vue.config.js 文件,不需要设置代理");
}

const tmpStr = fs.readFileSync(configBaseFile, { encoding: "utf8" });

fs.writeFileSync(
filePath,
tmpStr.replace("# proxy_pass placeholder", proxyPass)
);

console.log("nginx 配置文件生成");

命令行执行

1
node ./deployment/genNginxConf.js t

就可以看到 deployment/test/default.conf 文件被创建出来

image-20210909230515354

把刚才的命令添加到 package.json 中的 scripts 中,方便之后的执行

1
2
"gennginx:t": "node ./deployment/genNginxConf.js t",
"gennginx:prod": "node ./deployment/genNginxConf.js prod"

执行一下下面的命令,在 deployment/prod 下也会生层 default.conf 文件

1
2
3
npm run gennginx:prod
# or
yarn gennginx:prod

修改一下 buildbuild:t 命令,在执行这个命令的时候,可以同时生成新的 nginx 配置文件

1
2
"build": "vue-cli-service build && npm run gennginx:prod",
"build:t": "vue-cli-service build --mode t && npm run gennginx:t",

完结

项目已经上传到 github 和 gitee

GitHub: https://github.com/wukang0718/cli-create-project

Gitee: https://gitee.com/wu_kang0718/cli-create-project

下一篇:页面基本框架