Como usar a especificação de implantação do Amplify Hosting para configurar a saída da compilação
A especificação de implantação do Amplify Hosting é uma especificação baseada em sistema de arquivos que define a estrutura de diretórios que facilita as implantações no Amplify Hosting. Um framework pode gerar essa estrutura esperada de diretórios como saída do seu comando de compilação, permitindo que o framework aproveite as vantagens dos serviços primitivos do Amplify Hosting. A Amplify Hosting entende a estrutura do pacote de implantação e o implanta adequadamente.
Para ver uma demonstração em vídeo que explica como usar a especificação de implantação, consulte Como hospedar qualquer site usando o AWS Amplify no canal da Amazon Web Services no YouTube.
Veja a seguir um exemplo da estrutura de pastas que o Amplify espera para o pacote de implantação. Em um alto nível, ele tem uma pasta chamada static
, uma pasta chamada compute
e um arquivo de manifesto de implantação chamado deploy-manifest.json
.
.amplify-hosting/ ├── compute/ │ └── default/ │ ├── chunks/ │ │ └── app/ │ │ ├── _nuxt/ │ │ │ ├── index-xxx.mjs │ │ │ └── index-styles.xxx.js │ │ └── server.mjs │ ├── node_modules/ │ └── server.js ├── static/ │ ├── css/ │ │ └── nuxt-google-fonts.css │ ├── fonts/ │ │ ├── font.woff2 │ ├── _nuxt/ │ │ ├── builds/ │ │ │ └── latest.json │ │ └── entry.xxx.js │ ├── favicon.ico │ └── robots.txt └── deploy-manifest.json
Compatibilidade do Amplify com primitivo de SSR
A especificação de implantação do Amplify Hosting define um contrato que mapeia de perto os seguintes primitivos.
- Ativos estáticos
-
Fornece aos frameworks a capacidade de hospedar arquivos estáticos.
- Computação
-
Fornece aos framework a capacidade de executar um servidor HTTP Node.js na porta 3000.
- Otimização de imagem
-
Fornece aos framework um serviço para otimizar imagens em runtime.
- Regras de roteamento
-
Fornece aos framework um mecanismo para mapear caminhos de solicitação de entrada para destinos específicos.
O diretório .amplify-hosting/static
Você deve colocar no diretório .amplify-hosting/static
todos os arquivos estáticos acessíveis ao público que deverão ser oferecidos diretamente do URL da aplicação. Os arquivos dentro desse diretório serão oferecidos por meio do primitivo de ativos estáticos.
Os arquivos estáticos podem ser acessados na raiz (/) do URL da aplicação sem nenhuma alteração em seu conteúdo, nome de arquivo ou extensão. Além disso, os subdiretórios são preservados na estrutura do URL e aparecem antes do nome do arquivo. Por exemplo, .amplify-hosting/static/favicon.ico
será oferecido de https://myAppId.amplify-hostingapp.com/favicon.ico
, enquanto .amplify-hosting/static/_nuxt/main.js
será oferecido de
https://myAppId.amplify-hostingapp.com/_nuxt/main.js
.
Se um framework for compatível com a capacidade de modificar o caminho base da aplicação, ele deverá prefixar o caminho base aos ativos estáticos dentro do diretório .amplify-hosting/static
. Por exemplo, se o caminho base for /folder1/folder2
, a saída de compilação para um ativo estático chamado main.css
será .amplify-hosting/static/folder1/folder2/main.css
.
O diretório .amplify-hosting/compute
Um único recurso computacional é representado por um único subdiretório chamado default
contido no diretório .amplify-hosting/compute
. O caminho é .amplify-hosting/compute/default
. Esse recurso computacional é mapeado para o primitivo computacional do Amplify Hosting.
O conteúdo do subdiretório default
deve estar em conformidade com as regras a seguir.
-
É necessário ter um arquivo na raiz do subdiretório
default
para atuar como ponto de entrada para o recurso computacional. -
O arquivo do ponto de entrada deve ser um módulo Node.js e iniciar um servidor HTTP que escute na porta 3000.
-
Você pode colocar outros arquivos no subdiretório
default
e fazer referência a eles no código no arquivo do ponto de entrada. -
O conteúdo do subdiretório deve ser independente. O código no módulo de ponto de entrada não pode fazer referência a nenhum módulo fora do subdiretório. Observe que os frameworks podem agrupar seus servidores HTTP da maneira que quiserem. Se for possível iniciar o processo de computação com o comando
node server.js
, comserver.js is
indicando o nome do arquivo de entrada, diretamente do subdiretório, o Amplify vai considerar que a estrutura do diretório está em conformidade com a especificação de implantação.
O Amplify Hosting agrupa e implanta todos os arquivos dentro do subdiretório default
em um recurso computacional provisionado. Cada recurso computacional recebe 512 MB de armazenamento temporário. Esse armazenamento não é compartilhado entre instâncias de execução, mas é compartilhado entre invocações subsequentes na mesma instância de execução. As instâncias de execução estão limitadas a um tempo máximo de 15 minutos de execução, e o único caminho gravável dentro da instância de execução é o diretório /tmp
. O tamanho compactado de cada pacote de recursos computacionais não pode ultrapassar 220 MB. Por exemplo, o subdiretório .amplify/compute/default
não pode ultrapassar 220 MB quando compactado.
O arquivo .amplify-hosting/deploy-manifest.json
Use o arquivo deploy-manifest.json
para armazenar os detalhes da configuração e os metadados de uma implantação. Um arquivo deploy-manifest.json
deve incluir, no mínimo, um atributo version
, o atributo routes
com uma rota abrangente especificada e o atributo framework
com metadados de framework especificados.
A definição de objeto a seguir demonstra a configuração de um manifesto de implantação.
type DeployManifest = { version: 1; routes: Route[]; computeResources?: ComputeResource[]; imageSettings?: ImageSettings; framework: FrameworkMetadata; };
Os tópicos a seguir descrevem os detalhes e o uso de cada atributo no manifesto de implantação.
Como usar o atributo de versão
O atributo version
define a versão da especificação de implantação que você está implementando. No momento, a única versão da especificação de implantação do Amplify Hosting é a versão 1. O exemplo de JSON a seguir demonstra como usar o atributo version
.
"version": 1
Como usar o atributo routes
O atributo routes
permite que as estruturas aproveitem o primitivo de regras de roteamento do Amplify Hosting. As regras de roteamento fornecem um mecanismo para rotear os caminhos de solicitação de entrada para um destino específico no pacote de implantação. As regras de roteamento determinam somente o destino de uma solicitação recebida e são aplicadas depois que a solicitação é transformada pelas regras de regravação e redirecionamento. Para obter mais informações sobre como o Amplify Hosting processar regravações e redirecionamentos, consulte Configuração de redirecionamentos e regravações para uma aplicação do Amplify.
As regras de roteamento não regravam nem transformam a solicitação. Se uma solicitação recebida corresponder ao padrão de caminho de uma rota, a solicitação será roteada no estado em que se encontra para o destino da rota.
As regras de roteamento especificadas na matriz routes
devem obedecer às seguintes regras.
-
É necessário haver uma rota abrangente especificada. Uma rota abrangente tem o padrão
/*
que corresponde a todas as solicitações recebidas. -
A matriz
routes
pode conter no máximo 25 itens. -
É necessário especificar uma rota
Static
ou uma rotaCompute
. -
Se você especificar uma rota
Static
, o diretório.amplify-hosting/static
deverá existir. -
Se você especificar uma rota
Compute
, o diretório.amplify-hosting/compute
deverá existir. -
Se você especificar uma rota
ImageOptimization
, também deverá especificar uma rotaCompute
. Isso é necessário porque a otimização de imagem ainda não é compatível com aplicações puramente estáticas.
A definição de objeto a seguir demonstra a configuração para o objeto Route
.
type Route = { path: string; target: Target; fallback?: Target; }
A tabela a seguir descreve as propriedades do objeto Route
.
Chave | Tipo | Obrigatório | Descrição |
---|---|---|---|
caminho |
String |
Sim |
Define um padrão que corresponde aos caminhos da solicitação recebida (excluindo a string de consulta). O caminho pode ter até 255 caracteres. Um caminho deve começar com a barra Um caminho pode conter qualquer um dos seguintes caracteres: [A-Z], [a-z], [0-9],[ _-.*$/~"'@:+]. Somente os seguintes caracteres curinga são compatíveis para correspondência de padrão:
|
target |
Destino |
Sim |
Um objeto que define o destino para o qual rotear a solicitação correspondente. Se houver a especificação de uma rota Se houver a especificação de uma rota |
fallback |
Destino |
Não |
Um objeto que define o destino para o fallback se o destino original retornar um erro 404. O tipo |
A definição de objeto a seguir demonstra a configuração para o objeto Target
.
type Target = { kind: TargetKind; src?: string; cacheControl?: string; }
A tabela a seguir descreve as propriedades do objeto Target
.
Chave | Tipo | Obrigatório | Descrição |
---|---|---|---|
kind |
Targetkind |
Sim |
Um |
src |
String |
Sim para Não para outros primitivos |
Uma string que especifica o nome do subdiretório no pacote de implantação que contém o código executável do primitivo. Válido e necessário somente para o primitivo Compute. O valor deve apontar para um dos recursos computacionais presentes no pacote de implantação. No momento, o único valor compatível para esse campo é |
cacheControl |
String |
Não |
Uma string que especifica o valor do cabeçalho Cache-Control a ser aplicado à resposta. Válido somente para os primitivos Static e ImageOptimization. O valor especificado é substituído por cabeçalhos personalizados. Para obter mais informações sobre os cabeçalhos personalizados do Amplify Hosting, consulte Configuração de cabeçalhos personalizados para uma aplicação do Amplify. notaEsse cabeçalho Cache-Control é aplicado somente a respostas com êxito com um código de status definido como 200 (OK). |
A definição de objeto a seguir demonstra o uso da enumeração TargetKind
.
enum TargetKind { Static = "Static", Compute = "Compute", ImageOptimization = "ImageOptimization" }
A lista a seguir especifica os valores válidos para a enumeração TargetKind
.
- Estático
-
Roteia as solicitações para o primitivo de ativos estáticos.
- Computação
-
Roteia as solicitações para o primitivo de computação.
- ImageOptimization
-
Roteia as solicitações para o primitivo de otimização de imagem.
O exemplo de JSON a seguir demonstra como usar o atributo routes
com várias regras de roteamento especificadas.
"routes": [ { "path": "/_nuxt/image", "target": { "kind": "ImageOptimization", "cacheControl": "public, max-age=3600, immutable" } }, { "path": "/_nuxt/builds/meta/*", "target": { "cacheControl": "public, max-age=31536000, immutable", "kind": "Static" } }, { "path": "/_nuxt/builds/*", "target": { "cacheControl": "public, max-age=1, immutable", "kind": "Static" } }, { "path": "/_nuxt/*", "target": { "cacheControl": "public, max-age=31536000, immutable", "kind": "Static" } }, { "path": "/*.*", "target": { "kind": "Static" }, "fallback": { "kind": "Compute", "src": "default" } }, { "path": "/*", "target": { "kind": "Compute", "src": "default" } } ]
Para obter mais informações sobre como especificar regras de roteamento em seu manifesto de implantação, consulte Práticas recomendadas para a configuração de regras de roteamento.
Como usar o atributo computerResources
O atributo computeResources
permite que as estruturas forneçam metadados sobre os recursos computacionais provisionados. Cada recurso computacional deve ter uma rota correspondente associada.
A definição de objeto a seguir demonstra o uso do objeto ComputeResource
.
type ComputeResource = { name: string; runtime: ComputeRuntime; entrypoint: string; }; type ComputeRuntime = 'nodejs16.x' | 'nodejs18.x' | 'nodejs20.x';
A tabela a seguir descreve as propriedades do objeto ComputeResource
.
Chave | Tipo | Obrigatório | Descrição |
---|---|---|---|
name |
String |
Sim |
Especifica o nome do recurso de computação. O nome deve corresponder ao nome do subdiretório dentro de O único valor válido para a versão 1 da especificação de implantação é |
runtime |
ComputeRuntime |
Sim |
Define o runtime do recurso computacional provisionado. Os valores válidos são |
entrypoint |
String |
Sim |
Especifica o nome do arquivo inicial com base no qual o código será executado para o recurso computacional especificado. O arquivo deve existir dentro do subdiretório que representa um recurso computacional. |
Se você tiver uma estrutura de diretórios semelhante ao seguinte exemplo.
.amplify-hosting |---compute | |---default | |---index.js
O JSON para o atributo computeResource
será semelhante ao seguinte exemplo.
"computeResources": [ { "name": "default", "runtime": "nodejs16.x", "entrypoint": "index.js", } ]
Como usar o atributo imageSettings
O atributo imageSettings
permite que os frameworks personalizem o comportamento do primitivo de otimização de imagem, que fornece otimização sob demanda de imagens em runtime.
A definição de objeto a seguir demonstra o uso do objeto ImageSettings
.
type ImageSettings = { sizes: number[]; domains: string[]; remotePatterns: RemotePattern[]; formats: ImageFormat[]; minumumCacheTTL: number; dangerouslyAllowSVG: boolean; }; type ImageFormat = 'image/avif' | 'image/webp' | 'image/png' | 'image/jpeg';
A tabela a seguir descreve as propriedades do objeto ImageSettings
.
Chave | Tipo | Obrigatório | Descrição |
---|---|---|---|
sizes |
Number[] |
Sim |
Uma matriz de larguras de imagem compatíveis. |
domains |
String[] |
Sim |
Uma matriz de domínios externos permitidos que podem usar a otimização de imagem. Deixe a matriz vazia para permitir que somente o domínio de implantação use a otimização de imagem. |
remotePatterns |
RemotePattern[] |
Sim |
Uma matriz de padrões externos permitidos que podem usar a otimização de imagem. Semelhante aos domínios, mas fornece mais controle com expressões regulares (regex). |
formats |
ImageFormat[] |
Sim |
Uma variedade de formatos de imagem de saída permitidos. |
minimumCacheTTL |
Número |
Sim |
A duração do cache em segundos para as imagens otimizadas. |
dangerouslyAllowSVG |
Booleano |
Sim |
Permite URLs de imagem de entrada em SVG. Esse recurso está desabilitado por padrão para fins de segurança. |
A definição de objeto a seguir demonstra o uso do objeto RemotePattern
.
type RemotePattern = { protocol?: 'http' | 'https'; hostname: string; port?: string; pathname?: string; }
A tabela a seguir descreve as propriedades do objeto RemotePattern
.
Chave | Tipo | Obrigatório | Descrição |
---|---|---|---|
protocolo |
String |
Não |
O protocolo do padrão remoto permitido. Os valores válidos são |
hostname |
String |
Sim |
O nome de host do padrão remoto permitido. Você pode especificar um caractere literal ou curinga. Um “*” único corresponde a um único subdomínio. Um “**” duplo corresponde a qualquer número de subdomínios. O Amplify não permite curingas gerais que especifiquem apenas “**”. |
porta |
String |
Não |
A porta do padrão remoto permitido. |
pathname |
String |
Não |
O nome de caminho do padrão remoto permitido. |
O exemplo a seguir demonstra o atributo imageSettings
.
"imageSettings": { "sizes": [ 100, 200 ], "domains": [ "example.com" ], "remotePatterns": [ { "protocol": "https", "hostname": "example.com", "port": "", "pathname": "/**", } ], "formats": [ "image/webp" ], "minumumCacheTTL": 60, "dangerouslyAllowSVG": false }
Como usar o atributo framework
Use o atributo framework
para especificar os metadados do framework.
A definição de objeto a seguir demonstra a configuração para o objeto FrameworkMetadata
.
type FrameworkMetadata = { name: string; version: string; }
A tabela a seguir descreve as propriedades do objeto FrameworkMetadata
.
Chave | Tipo | Obrigatório | Descrição |
---|---|---|---|
name |
String |
Sim |
O nome do framework. |
versão |
String |
Sim |
A versão do framework. Ele deve ser uma string válida de versionamento semântico (semver). |
Práticas recomendadas para a configuração de regras de roteamento
As regras de roteamento fornecem um mecanismo para rotear os caminhos de solicitação de entrada para destinos específicos no pacote de implantação. Em um pacote de implantação, os criadores do framework podem emitir arquivos para a saída da compilação que são implantados em qualquer um dos seguintes destinos:
-
Primito de ativos estáticos: os arquivos estão contidos no diretório
.amplify-hosting/static
. -
Primitivo de computação: os arquivos estão contidos no diretório
.amplify-hosting/compute/default
.
Os criadores do framework também fornecem uma matriz de regras de roteamento no arquivo de manifesto de implantação. Cada regra na matriz é comparada com a solicitação recebida em ordem de passagem sequencial, até que haja uma correspondência. Quando houver uma regra correspondente, a solicitação será roteada para o destino especificado na regra correspondente. Como opção, é possível especificar um destino de fallback para cada regra. Se o destino original retornar um erro 404, a solicitação será roteada para o destino de fallback.
A especificação de implantação exige que a última regra na ordem de passagem seja uma regra abrangente. Uma regra abrangente é especificada com o caminho /*
. Se a solicitação recebida não corresponder a nenhuma das rotas anteriores na matriz de regras de roteamento, a solicitação será roteada para o destino da regra abrangente.
Para frameworks de SSR como Nuxt.js, o destino da regra abrangente deve ser a computação primitiva. Isso ocorre porque os aplicações de SSR têm páginas renderizadas no lado do servidor com rotas que não são previsíveis no momento da compilação. Por exemplo, se uma aplicação Nuxt.js tiver uma página em /blog/[slug]
na qual [slug]
esteja um parâmetro de rota dinâmica. O destino regra abrangente é a única maneira de rotear solicitações para essas páginas.
Por outro lado, é possível usar padrões de caminho específicos para direcionar rotas que sejam conhecidas no momento da compilação. Por exemplo, Nuxt.js fornece ativos estáticos do caminho /_nuxt
. Isso significa que o caminho /_nuxt/*
pode ser direcionado por uma regra específica de roteamento que roteia solicitações para o primitivo de ativos estáticos.
Roteamento de pasta pública
A maioria dos frameworks de SSR oferece a capacidade de fornecer ativos estáticos mutáveis diretamente de uma pasta public
. Em geral, arquivos como favicon.ico
e robots.txt
são mantidos dentro da pasta public
e são fornecidos diretamente do URL raiz da aplicação. Por exemplo, o arquivo favicon.ico
é fornecido diretamente de https://example.com/favicon.ico
. Observe que não há um padrão de caminho previsível para esses arquivos. Eles são quase que totalmente ditados pelo nome do arquivo. A única maneira de direcionar arquivos dentro da pasta public
é usar a rota abrangente. No entanto, o destino geral da rota precisa ser o primitivo de computação.
Recomendamos uma das seguintes abordagens para gerenciar sua pasta public
.
-
Use um padrão de caminho para direcionar caminhos de solicitação que contenham extensões de arquivo. Por exemplo, você pode usar
/*.*
para direcionar todos os caminhos de solicitação que contenham uma extensão de arquivo.Observe que essa abordagem pode não ser confiável. Por exemplo, se houver arquivos sem extensões de arquivo dentro da pasta
public
, eles não serão direcionados por essa regra. Outro problema a ser observado com essa abordagem é que a aplicação pode ter páginas com pontos em seus nomes. Por exemplo, uma página em/blog/2021/01/01/hello.world
será direcionada pela regra/*.*
. Isso não é ideal, pois a página não é um ativo estático. No entanto, você pode adicionar um destino alternativo a essa regra para garantir que a solicitação retorne para o primitivo computacional quando houver um erro 404 do primitivo estático.{ "path": "/*.*", "target": { "kind": "Static" }, "fallback": { "kind": "Compute", "src": "default" } }
-
Identifique os arquivos na pasta
public
no momento da compilação e emita uma regra de roteamento para cada arquivo. Essa abordagem não é escalável, pois há um limite de 25 regras imposto pela especificação de implantação.{ "path": "/favicon.ico", "target": { "kind": "Static" } }, { "path": "/robots.txt", "target": { "kind": "Static" } }
-
Recomende que os usuários do framework armazenem todos os ativos estáticos mutáveis dentro de uma subpasta dentro da pasta
public
.No exemplo a seguir, o usuário pode armazenar todos os ativos estáticos mutáveis dentro da pasta
public/assets
. Em seguida, é possível usar uma regra de roteamento com o padrão de caminho/assets/*
para direcionar todos os ativos estáticos mutáveis dentro da pastapublic/assets
.{ "path": "/assets/*", "target": { "kind": "Static" } }
-
Especifique um fallback estático para a rota abrangente. Essa abordagem tem desvantagens que são descritas com mais detalhes na próxima seção Roteamento abrangente de fallback.
Roteamento abrangente de fallback
Para frameworks de SSR como Nuxt.js, no qual uma rota abrangente é especificada para o destino primitivo de computação, os criadores do framework podem considerar a especificação de um fallback estático para a rota abrangente a fim de solucionar o problema de roteamento da pasta public
. No entanto, esse tipo de regra de roteamento interrompe as páginas 404 renderizadas no lado do servidor. Por exemplo, se o usuário final visitar uma página que não exista, a aplicação vai renderizar uma página 404 com um código de status 404. No entanto, se a rota abrangente tiver um fallback estático, a página 404 não será renderizada. Em vez disso, a solicitação retornará para o primitivo estático e ainda terminará com um código de status 404, mas a página 404 não será renderizada.
{ "path": "/*", "target": { "kind": "Compute", "src": "default" }, "fallback": { "kind": "Static" } }
Roteamento de caminho base
Espera-se que frameworks com a capacidade de modificar o caminho base da aplicação possam prefixar o caminho base aos ativos estáticos dentro do diretório .amplify-hosting/static
. Por exemplo, se o caminho base for /folder1/folder2
, a saída de compilação para um ativo estático chamado main.css será .amplify-hosting/static/folder1/folder2/main.css
.
Isso significa que também é necessário atualizar as regras de roteamento para refletir o caminho base. Por exemplo, se o caminho base for /folder1/folder2
, a regra de roteamento para os ativos estáticos na pasta public
terá a seguinte aparência.
{ "path": "/folder1/folder2/*.*", "target": { "kind": "Static" } }
Da mesma forma, também é necessário prefixar o caminho base nas rotas do lado do servidor. Por exemplo, se o caminho base for /folder1/folder2
, a regra de roteamento para a rota /api
terá a seguinte aparência.
{ "path": "/folder1/folder2/api/*", "target": { "kind": "Compute", "src": "default" } }
No entanto, o caminho base não deverá ser prefixado à rota abrangente. Por exemplo, se o caminho base for /folder1/folder2
, a rota abrangente permanecerá da seguinte maneira.
{ "path": "/*", "target": { "kind": "Compute", "src": "default" } }
Exemplos de rotas do Nuxt.js
Veja a seguir um exemplo de arquivo deploy-manifest.json
para uma aplicação Nuxt que demonstra como especificar regras de roteamento.
{ "version": 1, "routes": [ { "path": "/_nuxt/image", "target": { "kind": "ImageOptimization", "cacheControl": "public, max-age=3600, immutable" } }, { "path": "/_nuxt/builds/meta/*", "target": { "cacheControl": "public, max-age=31536000, immutable", "kind": "Static" } }, { "path": "/_nuxt/builds/*", "target": { "cacheControl": "public, max-age=1, immutable", "kind": "Static" } }, { "path": "/_nuxt/*", "target": { "cacheControl": "public, max-age=31536000, immutable", "kind": "Static" } }, { "path": "/*.*", "target": { "kind": "Static" }, "fallback": { "kind": "Compute", "src": "default" } }, { "path": "/*", "target": { "kind": "Compute", "src": "default" } } ], "computeResources": [ { "name": "default", "entrypoint": "server.js", "runtime": "nodejs18.x" } ], "framework": { "name": "nuxt", "version": "3.8.1" } }
Veja a seguir um exemplo de arquivo deploy-manifest.json
para Nuxt que demonstra como especificar regras de roteamento que incluem caminhos base.
{ "version": 1, "routes": [ { "path": "/base-path/_nuxt/image", "target": { "kind": "ImageOptimization", "cacheControl": "public, max-age=3600, immutable" } }, { "path": "/base-path/_nuxt/builds/meta/*", "target": { "cacheControl": "public, max-age=31536000, immutable", "kind": "Static" } }, { "path": "/base-path/_nuxt/builds/*", "target": { "cacheControl": "public, max-age=1, immutable", "kind": "Static" } }, { "path": "/base-path/_nuxt/*", "target": { "cacheControl": "public, max-age=31536000, immutable", "kind": "Static" } }, { "path": "/base-path/*.*", "target": { "kind": "Static" }, "fallback": { "kind": "Compute", "src": "default" } }, { "path": "/*", "target": { "kind": "Compute", "src": "default" } } ], "computeResources": [ { "name": "default", "entrypoint": "server.js", "runtime": "nodejs18.x" } ], "framework": { "name": "nuxt", "version": "3.8.1" } }
Para obter mais informações sobre o uso do atributo routes
, consulte Como usar o atributo routes.