Implantar sites Next.js híbridos nos Aplicativos Web Estáticos do Azure (versão prévia)

Neste tutorial, você aprenderá a implantar um site Next.js para os Aplicativos Web Estáticos do Azure, usando o suporte para os recursos do Next.js, como Componentes do React Server, Renderização do Servidor (SSR) e rotas da API.

Observação

O suporte híbrido do Next.js está em versão prévia.

Pré-requisitos

Recursos sem suporte na versão prévia

Os seguintes recursos dos Aplicativos Web Estáticos não têm suporte para o Next.js com renderização híbrida:

  • APIs vinculadas que usam o Azure Functions, Serviço de Aplicativo do Azure, Aplicativos de Contêiner do Azure ou o Gerenciamento de API do Azure.
  • Emulação e implantação locais da CLI da SWA.
  • Apenas suporte parcial para o arquivo staticwebapp.config.json.
    • O fallback de navegação não tem suporte.
    • As reescritas de rota para rotas dentro do aplicativo Next.js devem ser configuradas no next.config.js.
    • A configuração no arquivo staticwebapp.config.json tem precedência sobre a configuração no next.config.js.
    • A configuração do site Next.js deve ser tratada usando next.config.js para a compatibilidade completa do recurso.
  • skip_app_build e skip_api_build não pode ser usado na imagem de implantação Azure/static-web-apps-deploy@v1.
  • A Regeneração Estática Incremental (ISR) não dá suporte às imagens de cache.

Observação

O tamanho máximo do aplicativo Next.js híbrido é de 250 MB. Use o recurso autônomo do Next.js para tamanhos de aplicativo otimizados. Se isso não for suficiente, considere usar Next.js exportado com HTML Estático se o requisito do tamanho do aplicativo for superior a 250 MB.

Criar um repositório

Este artigo usa um repositório de modelos do GitHub para facilitar a introdução. O modelo apresenta um aplicativo inicial para implantar nos Aplicativos Web Estáticos do Azure.

  1. Navegue até o local a seguir para criar um novo repositório.

    https://github.com/staticwebdev/nextjs-hybrid-starter/generate

  2. Nomeie seu repositório my-first-static-web-app

  3. Selecione Criar repositório com base no modelo.

    Captura de tela do botão Criar repositório do modelo.

Criar um aplicativo Web estático

Agora que o repositório foi criado, você pode criar um aplicativo Web estático no portal do Azure.

  1. Acesse o portal do Azure.
  2. Selecione Criar um recurso.
  3. Pesquise Aplicativos Web Estáticos.
  4. Selecione Aplicativos Web Estáticos.
  5. Selecione Criar.

Na seção Informações Básicas, comece configurando seu novo aplicativo e vinculando-o a um repositório GitHub.

Captura de tela da seção básica no portal do Azure.

Configuração Valor
Subscription Selecione sua assinatura do Azure.
Grupo de recursos Selecione o link Criar novo e insira static-web-apps-bitbucket na caixa de texto.
Nome Insira my-first-static-web-app na caixa de texto.
Tipo de plano Selecione Gratuito.
Azure Functions e detalhes de preparo Selecione a região mais próxima de você.
Fonte Selecione GitHub.

Selecione Entrar com o GitHub e autentique-se no GitHub.

Depois de entrar no GitHub, insira as informações do repositório.

Configuração Valor
Organização Selecione sua organização.
Repositório Escolha my-first-web-static-app.
Branch Selecione main.

Captura de tela dos detalhes do repositório no portal do Azure.

Observação

Caso você não veja nenhum repositório:

  • Talvez seja necessário autorizar os Aplicativos Web Estáticos do Azure no GitHub. Navegue até o repositório do GitHub e vá para Configurações > Aplicativos > Aplicativos OAuth Autorizados, selecione Aplicativos Web Estáticos do Azure e Conceder.
  • Talvez seja necessário autorizar os Aplicativos Web Estáticos do Azure na sua organização do Azure DevOps. Você precisa ser um proprietário da organização para conceder as permissões. Solicite o acesso a aplicativos de terceiros por meio do OAuth. Para obter mais informações, confira Autorizar o acesso às APIs REST com o OAuth 2.0.

Na seção Detalhes do Build, adicione detalhes de configuração específicos à sua estrutura de front-end preferida.

  1. Selecione Next.js na lista suspensa Predefinições de Compilação.

  2. Mantenha o valor padrão na caixa Localização do aplicativo.

  3. Deixe a caixa Local da API vazia.

  4. Deixe a caixa Local do artefato do aplicativo vazia.

Selecione Examinar + criar.

Captura de tela do botão Criar.

Exibir o site

Há dois aspectos na implantação de um aplicativo estático. O primeiro cria os recursos subjacentes do Azure que compõem seu aplicativo. O segundo é um fluxo de trabalho que compila e publica seu aplicativo.

Para você acessar o novo site estático, primeiro, o build de implantação precisa concluir a execução.

A janela de Visão Geral de Aplicativos Web Estáticos exibe uma série de links que ajudam você a interagir com seu aplicativo Web.

Captura de tela da janela de visão geral dos Aplicativos Web Estáticos do Azure.

Se você escolher a barra de notificação que indica Clique aqui para verificar o status das suas execuções do GitHub Actions, será levado ao GitHub Actions em execução no repositório. Depois de verificar se o trabalho de implantação foi concluído, acesse o site por meio da URL gerada.

Depois que o fluxo de trabalho do GitHub Actions for concluído, selecione o link URL para abrir o site na nova guia.

Configure seu projeto do Next.js localmente para realizar alterações

  1. Clone o novo repositório para sua máquina. Certifique-se de substituir <YOUR_GITHUB_ACCOUNT_NAME> pelo nome da sua conta.

    git clone http://github.com/<YOUR_GITHUB_ACCOUNT_NAME>/my-first-static-web-app
    
  2. Abra o projeto no Visual Studio Code ou no editor de código preferido.

Adicione dados renderizados pelo servidor com um componente do servidor

Para adicionar dados renderizados pelo servidor no seu projeto do Next.js usando o Roteador de Aplicativo, edite um componente Next.js para adicionar operações do lado do servidor para renderizar dados no componente. Por padrão, os componentes Next.js são Componentes do Servidor que podem ser renderizados pelo servidor.

  1. Abra o arquivo app/page.tsx e adicione uma operação que define o valor de uma variável, a qual é computada no lado do servidor. Os exemplos incluem a busca de dados ou outras operações de servidor.

    export default function Home() {
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            ...
        );
    }
    
  2. Importe unstable_noStore de next/cache e chame-o no componente Home para garantir que a rota seja renderizada dinamicamente.

    import { unstable_noStore as noStore } from 'next/cache';
    
    export default function Home() {
        noStore();
    
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            ...
        );
    }
    

    Observação

    Esse exemplo força a renderização dinâmica desse componente para demonstrar a renderização do servidor da hora atual do servidor. O modelo do Roteador de Aplicativo do Next.js recomenda armazenar em cache as solicitações de dados individuais para otimizar o desempenho do aplicativo Next.js. Leia mais sobre busca e cache de dados no Next.js.

  3. Atualize o componente Home em app/pages.tsx para renderizar os dados do lado do servidor.

    import { unstable_noStore as noStore } from 'next/cache';
    
    export default function Home() {
        noStore();
    
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            <main className="flex min-h-screen flex-col items-center justify-between p-24">
                <div>
                    This is a Next.js application hosted on Azure Static Web Apps with 
                    hybrid rendering. The time on the server is <strong>{timeOnServer}</strong>.
                </div>
            </main>
        );
    }
    

Adicionando uma rota de API

Além dos Componentes do Servidor, o Next.js fornece Manipuladores de Rota que você pode usar para criar rotas de API para seu aplicativo Next.js. Essas APIs podem ser buscadas nos Componentes do Cliente.

Comece adicionando uma rota de API.

  1. Crie um novo arquivo em app/api/currentTime/route.tsx. Esse arquivo contém o Manipulador de Rotas do novo ponto de extremidade da API.

  2. Adicione uma função de manipulador para retornar dados da API.

    import { NextResponse } from 'next/server';
    
    export const dynamic = 'force-dynamic';
    
    export async function GET() { 
        const currentTime = new Date().toLocaleTimeString('en-US');
    
        return NextResponse.json({ 
            message: `Hello from the API! The current time is ${currentTime}.`
        });
    }
    
  3. Crie um novo arquivo em app/components/CurrentTimeFromAPI.tsx. Esse componente cria um contêiner para o Componente Cliente que busca a API do navegador.

  4. Adicione um componente cliente que busca a API nesse arquivo.

    'use client';
    
    import { useEffect, useState } from 'react';
    
    export function CurrentTimeFromAPI(){
        const [apiResponse, setApiResponse] = useState('');
        const [loading, setLoading] = useState(true);
    
        useEffect(() => {
            fetch('/api/currentTime')
                .then((res) => res.json())
                .then((data) => {
                setApiResponse(data.message);
                setLoading(false);
                });
            }, 
        []);
    
        return (
            <div className='pt-4'>
                The message from the API is: <strong>{apiResponse}</strong>
            </div>
        )
    }
    

Esse Componente Cliente busca a API com um gancho do React useEffect para renderizar o componente depois de concluir a carga. A diretiva 'use client' identifica esse elemento como um Componente Cliente. Para obter mais informações, consulte Componentes Cliente.

  1. Edite app/page.tsx para importar e renderizar o Componente Cliente CurrentTimeFromAPI.

    import { unstable_noStore as noStore } from 'next/cache';
    import { CurrentTimeFromAPI } from './components/CurrentTimeFromAPI';
    
    export default function Home() {
        noStore();
    
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            <main className="flex min-h-screen flex-col items-center justify-between p-24">
                <div>
                    This is a Next.js application hosted on Azure Static Web Apps with 
                    hybrid rendering. The time on the server is <strong>{timeOnServer}</strong>.
                </div>
                <CurrentTimeFromAPI />
            </main>
        );
    }
    
  2. O resultado da rota da API será exibido na página.

Captura de tela mostrando a exibição da saída da rota da API.

Configure a versão do runtime no Next.js

Determinadas versões do Next.js exigem versões específicas do Node.js. Para configurar uma versão específica do Node, você pode definir a propriedade “mecanismo” do seu arquivo package.json para designar uma versão.

{
  ...
  "engines": {
    "node": "18.17.1"
  }
}

Defina variáveis de ambiente do Next.js

O Next.js usa variáveis de ambiente no momento da compilação e da solicitação para oferecer suporte à geração de páginas estáticas e dinâmicas com renderização no lado do servidor. Por isso, defina as variáveis de ambiente na tarefa de compilação e implantação e nas Variáveis de ambiente do seu recurso de Aplicativos Web Estáticos do Azure.

...
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
          action: "upload"
          app_location: "/" 
          api_location: ""
          output_location: "" 
        env:
          DB_HOST: ${{ secrets.DB_HOST }}
          DB_USER: ${{ secrets.DB_USER }}
          DB_DATABASE: ${{ secrets.DB_DATABASE }}
          DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
          DB_PORT: ${{ secrets.DB_PORT }}
...

Habilitar funcionalidade autônoma

Quando o tamanho do aplicativo excede 250Mb, o recurso Next.js Rastreamento de Arquivo de Saída ajuda a otimizar o tamanho do aplicativo e a melhorar o desempenho.

O Rastreamento de Arquivo de Saída cria uma versão compactada de todo o aplicativo com as dependências de pacote necessárias incorporadas em uma pasta chamada .next/standalone. Essa pasta deve ser implantada por conta própria sem dependências node_modules adicionais.

Para habilitar a funcionalidade standalone, adicione a seguinte propriedade adicional ao seu next.config.js:

module.exports ={
    output:"standalone",
}

Você também precisará configurar o comando build no arquivo package.json para copiar os arquivos estáticos para sua saída autônoma.

{
  ...
  "scripts": {
    ...
    "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/"
    ...
  }
  ...
}

Configurar o roteamento Next.js e o middleware para implantação nos Aplicativos Web Estáticos do Azure

Seu projeto de Next.js pode ser configurado para ter o tratamento personalizado de rotas com redirecionamentos, regravações e middleware. Esses manipuladores geralmente são usados para autenticação, personalização, roteamento e internacionalização. A manipulação personalizada afeta o roteamento padrão de seu site de Next.js e a configuração deve ser compatível com a hospedagem nos Aplicativos Web Estáticos.

Os Aplicativos Web Estáticos validam que seu site Next.js foi implantado com sucesso adicionando uma página ao seu site no momento da compilação. A página é nomeada public/.swa/health.html e os Aplicativos Web Estáticos verificam a inicialização e a implantação bem-sucedidas do seu site navegando até /.swa/health.html e verificando uma resposta bem-sucedida. O middleware e o roteamento personalizado, que inclui redirecionamentos e regravações, podem afetar o acesso do caminho /.swa/health.html, o que pode impedir a validação da implantação dos Aplicativos Web Estáticos. Para configurar o middleware e o roteamento para uma implantação bem-sucedida para Aplicativos Web Estáticos, siga estas etapas:

  1. Exclua rotas começando com .swa no arquivo middleware.ts (ou .js) na configuração do middleware.

    export const config = {
      matcher: [
        /*
         * Match all request paths except for the ones starting with:
         * - .swa (Azure Static Web Apps)
         */
        '/((?!.swa).*)',
      ],
    }
    
  2. Configure seus redirecionamentos em next.config.js para excluir rotas começando com .swa

    module.exports = {
        async redirects() {
            return [
              {
                source: '/((?!.swa).*)<YOUR MATCHING RULE>',
                destination: '<YOUR REDIRECT RULE>', 
                permanent: false,
              },
            ]
        },
    };
    
  3. Configure suas regravações em next.config.js para excluir rotas começando com .swa

    module.exports = {
        async rewrites() {
            return {
                beforeFiles: [
                    {
                        source: '/((?!.swa).*)<YOUR MATCHING RULE>',
                        destination: '<YOUR REWRITE RULE>', 
                    }
                ]
            }
        },
    };
    

Esses snippets de código excluem caminhos que começam com .swa de serem manipulados pelo seu roteamento personalizado ou middleware. Essas regras garantem que os caminhos sejam resolvidos conforme o esperado durante a validação da implantação.

Habilitar registro em log para Next.js

Seguindo as melhores práticas para solução de problemas da API do servidor Next.js, adicione o registro em log à API para capturar esses erros. O registro em log no Azure usa o Application Insights. Para pré-carregar esse SDK, você precisa criar um script de inicialização personalizado. Para saber mais:

Limpar os recursos

Se você não quiser continuar usando esse aplicativo, poderá excluir a instância do Aplicativo Web Estático do Azure com as seguintes etapas:

  1. Abra o portal do Azure.
  2. Pesquise my-first-web-static-app na barra de pesquisa superior.
  3. Selecione o nome do aplicativo.
  4. Selecione Excluir.
  5. Selecione Sim para confirmar a ação de exclusão (essa ação pode levar alguns minutos para ser concluída).

Próximas etapas