# 问题
废话不多说,目的是将项目部署到xxx.com/app
路径下。
脚手架用的是vite,一开始什么都没有配置,base(如果是vue.config.js则是对应publicPath)是默认的(根目录),路由模式使用的是histroy,规则大致如下:
const routes = [
{ path: '/', component: () => import('@/views/Home.vue')},
{ path: '/About', component: () => import('@/views/About.vue')},
]
2
3
4
当时我的理解是,部署的时候将打包后的文件放在/app/
目录下,那么访问xxx.com/app
就能匹配到对应的路由。
当项目部署后,首先是出现两个文件404问题,分别是@vite/client.js和main.js。
当时在网上看到的解决方法是把base修改成'./',也就是相对路径,修改完一部署,果然没报404了,但是页面一片空白,并且控制台也没有任何报错(这时候并不知道nginx的配置和资源在服务器存放的路径)。
这就奇怪了,明明已经加载了main.js部分的内容,但却没有渲染出组件。然后就在同事的nginx上部署了一下,发现是可以正常访问的,但他的情况是没有加上子路径的,一加上/app
就不行了。其实这里就大致知道是nginx配置与前端打包配置没有配合好的原因了。
# 解决方法
后面了解了nginx的配置,试了许多方案,终于配置好了:
nginx conf
server {
# xxx其他配置
listen 80;
server_name xxx.com;
location /app {
alias xxx/nginx-1.20.2/html/app/;
try_files $uri $uri/ /app/index.html;
}
# xxx其他配置
}
vite.config.js
base: '/app'
routes
const routes = [
{ path: '/app/', component: () => import('@/views/Home.vue')},
{ path: '/app/About', component: () => import('@/views/About.vue')},
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
两个页面都能正常访问,经过测试发现,base需要和location保持一致(后面发现不一定,base可以有多种写法),而文件存放的路径不是关键,即使修改也可以正常访问到(文件需要放到对应的目录下):
nginx
server {
listen 80;
server_name xxx.com;
location /app {
# 将前端打包文件放到dist目录下
alias xxx/nginx-1.20.2/html/dist/;
try_files $uri $uri/ /dist/index.html;
}
}
2
3
4
5
6
7
8
9
10
那么我最开始设置成的base为'./'时,没有渲染组件是什么情况呢?
nginx
server {
listen 80;
server_name xxx.com;
location /app {
alias xxx/nginx-1.20.2/html/app/;
try_files $uri $uri/ /app/index.html;
}
}
vite.config.js
base: './'
routes
const routes = [
{ path: '/', component: () => import('@/views/Home.vue')},
{ path: '/About', component: () => import('@/views/About.vue')},
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
现在看来,确实是因为路由规则不对导致的,如果路由规则修改为如下:
const routes = [
{ path: '/app', component: () => import('@/views/Home.vue')},
{ path: '/app/About', component: () => import('@/views/About.vue')},
]
2
3
4
则可以正常访问,说明base不一定要与location一致,而是要保证路由前缀和location要匹配的上。
此外,看到有人说需要配置router中的base,会自动为路由加上前缀,如下:
const routes = [
{ path: '/', component: () => import('@/views/Home.vue')},
{ path: '/About', component: () => import('@/views/About.vue')},
]
const router = createRouter({
history: createWebHistory(),
base: '/app',
routes,
})
2
3
4
5
6
7
8
9
10
但我试了却没有生效,加与不加,访问xxx.com/app
都是空白页面,且不报错,说明就是没有匹配到对应的路由,可能还是我的写法有问题?
其中如果你某些地方没配置好还会出现访问xxx.com/app
正常,xxx.com/app/About
出现404的问题,可以检查下前端和nginx有没有对应配好。
# 总结
如果使用history模式,并且需要部署到子级目录下,需要配置好以下内容:
vite.config.js的base(vue.config.js对应publicPath)可以有三种设置方式:相对路径
'./'
、服务器存放资源的路径、nginx配置文件location的路径,设置有误可能出现404。nginx配置如下:
server { listen 80; server_name xxx.com; location /app { alias xxx/nginx-1.20.2/html/app/; try_files $uri $uri/ /app/index.html; } }
1
2
3
4
5
6
7
8
9alias就是匹配到location后去对应路径下找资源,try_files则是在url前缀包含location但却没有匹配的资源时会去使用的资源。
例如这里location没有配置
/app/About
,但是却可以访问到就是因为这条配置,如果删掉则会出现404,这是因为单页面应用只有一个入口文件,所以可以这么做。route规则中的路径前缀需要与location一致。
这三点如果都没错的话应该就能正确部署了,推荐base、路由前缀、location三者统一,方便配置,也可以减少出错。另外,前端打包后的文件也推荐放到对应级别的目录中,如在本例子中,存放的位置为/xxx/nginx/html/app/
。
# 其他
当你base设置为资源的绝对路径时(如/dist
),如果你跑本地服务的话,可能会访问不到资源,但是打包后部署上去是可以正常访问的。
看到网上有人说使用base使用'./'会出现刷新404的情况,但我这边没有遇到,如果大家遇到可以说明一下情况,共同探讨。
对于单页面应用,location路径的最后可以不带/。这样的好处是,假如你想要部署的地址是xxx.com/app
,那么你使用xxx.com/app
或者xxx.com/app/
都可以访问到,这是因为配置了try_files,即使找不到,但是由于前缀匹配到了location,可以去寻找默认的文件;
如果location最后携带了/
,则xxx.com/app
访问不到。这是因为location最后加了/
需要精确匹配到xxx.com/app/
前缀才能访问。
当然这也要根据项目需求来决定如何配置。
最后,这是本人初次接触nginx部署,如果有说的不对的地方欢迎指出,共同进步。