前端部署踩坑记录

2024/8/2 前端vitevuenginx

# 问题

废话不多说,目的是将项目部署到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')},
]
1
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')},
]
1
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;
    }
}
1
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')},
]
1
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')},
]
1
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,
})
1
2
3
4
5
6
7
8
9
10

但我试了却没有生效,加与不加,访问xxx.com/app都是空白页面,且不报错,说明就是没有匹配到对应的路由,可能还是我的写法有问题?

其中如果你某些地方没配置好还会出现访问xxx.com/app正常,xxx.com/app/About出现404的问题,可以检查下前端和nginx有没有对应配好。

# 总结

如果使用history模式,并且需要部署到子级目录下,需要配置好以下内容:

  1. vite.config.js的base(vue.config.js对应publicPath)可以有三种设置方式:相对路径'./'、服务器存放资源的路径、nginx配置文件location的路径,设置有误可能出现404。

  2. 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
    9

    alias就是匹配到location后去对应路径下找资源,try_files则是在url前缀包含location但却没有匹配的资源时会去使用的资源。

    例如这里location没有配置/app/About,但是却可以访问到就是因为这条配置,如果删掉则会出现404,这是因为单页面应用只有一个入口文件,所以可以这么做。

  3. 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部署,如果有说的不对的地方欢迎指出,共同进步。

Last Updated: 2024/10/7 15:51:07