返回

Nuxt 3 部署 AWS Amplify 子目录:解决 404 路径问题

vue.js

Nuxt 3 应用部署在 AWS Amplify 子文件夹下的路径问题解决

基于 Nuxt 3 开发的应用,需要将其部署至 AWS Amplify 的指定子文件夹,这个过程会出现一些特定的路径问题。这个问题与路由,以及 Nuxt 3 的构建输出配置息息相关。了解如何去分析产生的原因,解决它并不困难。

一、问题解析:根源在何处?

将 Nuxt 3 应用部署到 AWS Amplify 子目录下,例如 /v2,当访问形如 /v2/validate/xxxx 动态路由时,会出现 404 错误。出错的根源在于 AWS Amplify 的路由处理机制与 Nuxt 3 动态路由的构建输出方式之间的不匹配。当构建的目标目录设置为.dist/v2 且基础路径 baseURL 设置为/v2时,虽然静态资源可以正确访问,但由 Nitro 处理的服务器端路由,尤其是动态路由[...id].vue,会出现路径识别问题。

Nuxt 3 构建时会将文件生成到指定目录,即设置的输出目录 .dist/v2 。访问 /v2 可以正常访问,此时请求的是 /v2/index.html 文件。访问 /v2/validate/xxx 时,理论上应该查找 /v2/validate/[...id].html,然而实际没有这个文件,导致返回 404。这是因为动态路由需要服务器端的支持才能正常渲染。简单讲,就是构建过程不会生成这个文件,服务器又处理不了。

二、解决方案:打通路径障碍

处理这个部署路径问题,思路是调整服务器端的路由处理,使 AWS Amplify 能识别/v2下的动态路由。结合 nuxt.config.ts 配置与 Amplify 的重定向规则来实现。具体有三种:

方案1: 调整 Nitro 预设和重定向

利用 Nitro 的 aws-amplify 预设可以更精准地匹配 Amplify 的环境。这种方法调整的配置会减少部署步骤中的一些麻烦。

  1. 调整 nuxt.config.ts

    // https://nuxt.com/docs/api/configuration/nuxt-config
    export default defineNuxtConfig({
      compatibilityDate: '2024-04-03',
      devtools: { enabled: true },
      app: {
        baseURL: '/v2/', 
      },
      nitro: {
        preset: 'aws-amplify',
        serveStatic: false,
        output: {
          publicDir: './dist/v2',
          dir: './.amplify-build',
        },
      },
    });
    

    baseURL设置为了 /v2/。将构建产物存放在 .amplify-build 目录,给 Amplify 使用。/v2下的静态资源会生成到 dist/v2 下,让它可以访问。

  2. 设置 Amplify 重定向规则

    AWS Amplify 控制台中找到应用,转到 "Rewrites and redirects" 。修改规则,使其能够正确地进行重写:

    • Source address: </v2/<*>
    • Target address: /v2/index.html
    • Type: 200 (Rewrite)

    添加这条规则保证所有的请求都可以正常。这条规则作用,将所有 /v2 下的请求都重定向到 /v2/index.html,交由 Nuxt 3 应用进行路由处理。

方案2: 修改构建输出目录并使用自定义构建命令

此种方法对项目结构影响相对较大,需要在根目录下操作,不够方便,可以作为方案一失败后的备选。

  1. 调整 nuxt.config.ts

    // https://nuxt.com/docs/api/configuration/nuxt-config
    export default defineNuxtConfig({
      compatibilityDate: '2024-04-03',
      devtools: { enabled: true },
      app: {
        baseURL: '/v2/',
      },
      nitro: {
        // preset: 'aws-amplify',
        static: false,
        output: {
          publicDir: './dist', 
          dir: './.output',
        },
      },
    });
    

    这个方案的关键在于保持输出文件夹与原本类似,然后把 publicDir 设置为 ./dist,同时为了区分把 dir 修改为了 ./.output.

  2. 修改 amplify/project-config.json

    {
      "projectName": "test",
      "version": "3.1",
      "frontend": "javascript",
      "javascript": {
        "framework": "vue",
        "config": {
          "SourceDir": "src",
          "DistributionDir": "dist/v2",
          "BuildCommand": "npm run generate && mv dist v2 && mv .output dist",
          "StartCommand": "npm run dev"
        }
      },
      "providers": [
        "awscloudformation"
      ]
    }
    

    注意:这里 "StartCommand": "npm run dev",测试环境下可以使用dev,但是生产环境中不能使用。

    这个配置的作用是将静态资源打包进 dist/v2 中,Amplify 构建产物也打包进 dist,并且在部署时候识别. npm run generate && mv dist v2 && mv .output dist 。使用该指令,先运行原本的 npm run generate 命令。 然后使用 mv 指令修改 .outputdist ,再修改 ./distdist/v2.

  3. 配置 Amplify 重定向规则

    使用与方案 1 中同样的重定向规则配置 Amplify 控制台:

    • Source address: </v2/<*>
    • Target address: /v2/index.html
    • Type: 200 (Rewrite)
      这条规则跟方案一的目的相同。

方案3: 使用 NITRO_PRESET 环境变量

此方案直接通过设置NITRO_PRESET,不需要修改配置代码,在Amplify的环境下相对容易维护,但是设置较麻烦,需要频繁更改环境。可以放在方案一跟方案二都失败了再去使用。

  1. 保留 nuxt.config.ts 原有配置,调整 app.baseURL :
    保留 nuxt.config.ts中原有配置,可以仅修改app.baseURL

    // https://nuxt.com/docs/api/configuration/nuxt-config
    export default defineNuxtConfig({
     compatibilityDate: '2024-04-03',
     devtools: { enabled: true },
     app: {
       baseURL: '/v2/',
     },
     nitro: {
       // preset: 'aws-amplify',
       static: false,
       output: {
         publicDir: './dist/v2',
         dir: './dist/v2',
       },
     },
    });
    
  2. 设置 NITRO_PRESET 环境变量

    在 AWS Amplify 控制台,转到应用的 "Environment variables" 设置。添加一个环境变量:

    • Key : NITRO_PRESET
    • Value : aws_amplify

    NITRO_PRESETaws_amplify 将会改变 Nitro 构建的行为,适配 Amplify 环境。

  3. 配置 Amplify 重定向规则
    与上述两种方法相同:

    • Source address: </v2/<*>
    • Target address: /v2/index.html
    • Type: 200 (Rewrite)

    /v2下路由交给/v2/index.html处理。

三种解决方案在调整后都需要重新部署 。这些配置能正确地将对/v2 下资源的请求路由给 Nuxt 3 应用处理。选择哪个方案,需要根据具体的项目结构和个人习惯做出选择,三个方案最终结果是类似的。三个方案建议按照先后顺序使用,一个方法解决,没有必要继续设置剩下的方案。

注意:不同的 AWS Amplify 的账号环境下,具体配置可能有一些差异,所以一定要结合自己控制台进行部署。另外注意安全方面:不要直接暴露内部文件结构,避免使用过于明显的路径,定期查看服务器日志。