Entre para a LISTA VIP da Black Friday

00

DIAS

00

HORAS

00

MIN

00

SEG

Clique para saber mais
Alura > Cursos de Front-end > Cursos de Next.JS > Conteúdos de Next.JS > Primeiras aulas do curso Next.js: gerando site estático com SSG

Next.js: gerando site estático com SSG

Criando Api Router e fazendo fetch - Apresentação

Boas-vindas a mais um curso Next! Me chamo Patricia Silva.

Audiodescrição: Patricia é uma mulher branca de cabelos cacheados. Usa óculos e veste uma camisa quadriculada azul.

O que vamos aprender?

Neste novo desafio, vamos implementar e evoluir uma aplicação existente, que é o Meteora.

3500-meteora-next-14.vercel.app

O Meteora já está aberto no meu navegador. Ele é um e-commerce e temos duas páginas. A primeira é a página que lista todos os produtos, onde temos imagens e botões. A segunda é a página de detalhes do produto, que é uma rota dinâmica.

Vamos enfrentar alguns desafios para tornar essa página, que é dinâmica, em uma página estática.

Estamos falando de uma página dinâmica, que renderiza do lado do servidor, mas que no final será puramente estática. O Next permite termos páginas dinâmicas e páginas estáticas na mesma aplicação. Um dos grandes pilares de vantagens de um site estático é a performance.

A pessoa usuária vai poder acessar a página de uma forma muito mais rápida. A carga do servidor vai diminuir, porque as páginas podem ser buscadas do cache. Elas são distribuídas pela CDN, então, dependendo da localização geográfica da pessoa usuária, ela vai receber essas páginas de uma forma muito mais rápida.

Portanto, o grande pilar da performance é o foco principal.

Pré-requisitos

Para aprender tudo isso, é necessário ter conhecimento em HTML, CSS, principalmente em JavaScript e React.

Vamos lá?

Criando Api Router e fazendo fetch - Demonstração layout e execução em localhost

Já baixei o projeto e o clonei em minha máquina, e ele está aberto no Visual Studio Code (VS Code).

Analisaremos a estrutura do projeto.

Estrutural Inicial do Projeto

No VS Code, do lado esquerdo, na barra de exploração de arquivos; temos, por exemplo, o package.json, que descreve as configurações do projeto e as bibliotecas importadas.

Temos também o next.config.mjs, onde configuramos um provedor externo de imagens. As imagens estão hospedadas em outro lugar, não dentro do projeto.

Temos a pasta src (source), os mocks do projeto, que são de produtos e categorias. É uma estrutura fixa, toda a estrutura está simulada aqui. Abrindo o arquivo produtos.js, podemos verificar todos os produtos. Fechando esse arquivo, temos o arquivo de categorias.js, onde estão todas as categorias.

Cada categoria tem uma estrutura de nome e a imagem que está hospedada em um outro servidor externo, no caso, o GitHub.

Fechando a pasta mocks, temos um diretório lib com um arquivo chamado api.js. Esse arquivo api é apenas para facilitar, para termos métodos para buscar os produtos, todas as categorias, ou buscar os produtos pelo id, pelo slug, etc. Por exemplo, desejamos apenas o produto 1 ou 2.

Na atual configuração do Next 14, a estrutura principal é a pasta app. Neste contexto, abandonamos a utilização do app router e das pages. Em vez disso, centralizamos todos os elementos necessários na pasta app, que inclui diversos componentes como categorias, Footer, Header, Produto, detalhe do produto, listagem completa de produtos, bem como os ícones associados.

Fechamos a pasta componentes.

Temos a pasta produto/[slug], que é uma página dinâmica, onde vamos especificar qual é o produto que queremos acessar, e conseguiremos renderizar os detalhes daquele produto.

Agora, precisamos rodar o projeto localmente no navegador.

Rodando o projeto

Já estamos com o terminal aberto e estamos usando o yarn. Duas coisas que vamos fazer são: instalar as dependências do projeto e garantir que estamos usando o node 18.19. Recomendamos usar 18.17+.

Vamos limpar o terminal e rodar yarn dev, porque no package.json, o yarn dev sobe o servidor do Next. Digitamos no terminal yarn dev, que vai abrir o localhost na porta 3000.

yarn dev

Obtemos:

http://localhost:3000

Indo para o navegador e colocando o http://localhost:3000, a página renderiza corretamente.

Clicando em "Ver mais" de um produto, por exemplo, nessa camiseta, abre a página de detalhe do produto. Perceba que a URL também muda, é /produto/1, porque o 1 é o ID desse produto, e é dessa forma que recuperamos o detalhe desse produto.

Mudando para a aba do GitHub, é onde criamos um projeto chamado Meteora Assets. Nele adicionamos todas as imagens de produto e categorias. Clicando em produtos, temos as imagens de produto aqui, e categorias.

Por que decidimos colocar esses assets em um projeto separado e não incorporá-los dentro do projeto do Meteora em si? Porque temos uma facilidade maior de gerenciar essas imagens.

Na hora de fazer o build do projeto, que é pegar todo aquele código e empacotar para que ele se torne estático, será muito mais rápido, o projeto terá um tamanho muito menor, porque as imagens não estão lá dentro.

Além disso, quando as imagens estão em um host externo, não teremos gasto de servidor quando hospedarmos esse projeto no final. Para gerenciar melhor essas imagens, achamos muito mais fácil dividir essa complexidade, deixar as imagens em um projeto só cuidando delas lá, e então usamos apenas por meio de links as imagens dentro do projeto, é muito mais simples de gerenciá-las.

Criando Api Router e fazendo fetch - Mostrar o build e criar uma API router

Agora, precisamos evoluir essa aplicação e aplicar estratégias a cada passo que avançamos. Estamos mais perto de completar essa Static Site Generation (Geração de Site Estático), pois basicamente temos que aplicar estratégias para que, no final, consigamos atingir o resultado.

Retornamos ao VSCode, navegamos na estrutura de diretórios dentro de "src > app". Temos o arquivo page.js. Esta é a página inicial do site, onde listamos todos os produtos.

page.js

// código omitido

export default async function Home () {
    const produtos = getTodosProdutos(); 
    const categorias = getCategorias();

// código omitido

Na linha 7, fazemos um getTodosProdutos(), entramos nesse método nele clicando sobre ele. Ele está localizado dentro de "lib > api.js". Mais ou menos na linha 5, esse método retorna um mock de produtos.

api.js

import { produtos } from "../mocks/produtos";
import { categorias } from "../mocks/categorias";

export function getTodos Produtos () { 
    return produtos; 
}

// código omitido

Nós acessamos o mock de produtos na primeira linha do arquivo através do caminho "../mocks/produtos". Somos redirecionados para o arquivo produtos.js. Note que este mock consiste em um array estático de objetos que representam produtos.

Retornando ao método no arquivo api.js, ele é bastante simples e não é assíncrono; simplesmente fazemos uma chamada para obter os mocks dos produtos. Agora que concluímos a exposição da estrutura desta api.js, vamos passar para o arquivo page.js, na linha 7, onde substituiremos essa operação getTodosProdutos() por uma rota de API (api route).

page.js

// código omitido

export default async function Home () {
    const produtos = getTodosProdutos(); 
    const categorias = getCategorias();

// código omitido

Vamos realizar um fetch em uma API route de produtos que criaremos agora, pois isso nos aproximará da nossa estratégia de geração de um site estático.

Primeiro, criaremos essa API route de produtos.

Então, dentro do diretório app, criaremos um subdiretório chamado api. Dentro deste, criaremos outro diretório chamado produtos, e dentro de produtos, criaremos um arquivo chamado route.js.

Seremos redirecionados para o arquivo route.js.

Primeiro, iremos importar alguns facilitadores, como o NextResponse, que vem do nextServer e nos ajuda a retornar respostas de forma mais eficiente. Também iremos importar o método getTodosProdutos, que já está retornando nosso objeto de produtos.

route.js

import { NextResponse } from "next/server";
import { getTodos Produtos } from "@/lib/api";

Por enquanto, esses dados serão mockados dentro do projeto, já que ainda não temos um back-end ou qualquer serviço externo que retorne os produtos. No entanto, isso é algo que esperamos ter no futuro.

Criamos uma função que será exportada como assíncrona: export async function. O nome dela será GET(){}. Dentro dessa função, criamos uma constante chamada produtos, na qual chamamos o método getTodosProdutos(), obtendo assim todos os produtos disponíveis. Agora, vamos retornar utilizando return NextResponse.json({}), passando como argumento um objeto contendo os produtos.

route.js

import { NextResponse } from "next/server";
import { getTodos Produtos } from "@/lib/api";

export async function GET() {
    const produtos = getTodosProdutos();

    return NextResponse.json({ produtos });
}

Assim, temos uma API route de produtos.

Testaremos esse get no navegador. Voltamos para o navegador, e já vamos inserir o endereço localhost:3000/api/produtos.

localhost:3000/api/produtos

Retornou um objeto de produtos que tem um array de produtos. Nossa API route de produtos está funcionando corretamente.

Agora, voltamos para o VS Code. Fechamos o arquivo route.ja. Aqui na página page.js, criamos um método que vai fazer um fetch para aquela API route.

Criamos após o import uma async function fetchProductosApi(). No corpo dessa função, criamos uma constante que vai receberá o resultado do fetch. Portanto, após o const res colocamos um await fetch, o fetch vamos fazer para http://localhost:3000/api/produtos.

page.js

// código omitido

async function fetchProductosApi() {
    const res = await fetch("http://localhost:3000/api/produtos");

}

// código omitido

Agora, criamos uma condição onde, se essa resposta não for ok (if(!res.ok)), vamos lançar um throw New Error(). Passamos "não foi possível obter os dados" para esse erro.

page.js

// código omitido

async function fetchProductosApi() {
    const res = await fetch("http://localhost:3000/api/produtos");

    if(!res.ok) {
        throw new Error("Não foi possível obter os dados")
    }
}

// código omitido

Criando uma constante de produtos

Nossa próxima etapa é estabelecer uma variável constante para os produtos. Nessa variável, vamos receber a resposta em formato JSON com await res.json(). Feito isso, vamos retornar os produtos utilizando return produtos.

page.js

// código omitido

async function fetchProductosApi() {
    const res = await fetch("http://localhost:3000/api/produtos");

    if(!res.ok) {
        throw new Error("Não foi possível obter os dados")
    }
    
    const produtos = await res.json();
    
    return produtos;
}

// código omitido

Agora que temos a fetchProductosApi() pronta, dentro do método da página, na linha 19, onde anteriormente estávamos fazendo um getTodosProdutos(), chamamos o fetch.

Utilizamos o await fetchProductosApi(). No entanto, em produtos, ao invés de atribuir o resultado diretamente à constante, faremos uma desestruturação para extrair apenas a propriedade produtos do objeto retornado. Dessa forma, teremos apenas o array de produtos, que será passado como argumento para o componente de produtos na linha 26.

page.js

// código omitido

export default async function Home () {
    const produtos = await fetchProductosApi() 
    const categorias = getCategorias();

// código omitido

Vamos voltar no navegador, na página localhost:3000, teclamos "F5". Continua funcionando corretamente.

Voltamos para o VSCode, estamos consumindo API route. Agora, estamos fazendo uma requisição HTTP para uma API. Paramos o servidor com ^C no terminal, vamos limpar com clear, e rodar o yarn build.

yarn build

O yarn build é um comando que compila todo o projeto para gerar um projeto estático, para gerar HTML, CSS e Javascript, que é o que o navegador entende.

Queremos mostrar para vocês uma coisa: no output do yarn build, reparem que a rota barra (/) é estática, esse círculo é o símbolo de estático, e o nosso /api/produtos também é estático.

No entanto, ainda temos a página de detalhes do produto, /produto/[slug], que vai receber o ID do produto e vai renderizar o detalhe do produto. Ele está marcado como dinâmico, é uma URL, uma rota dinâmica.

Mas esse símbolo de dinâmico (lambda) significa que a rota está sendo renderizada no servidor, é SSR. No entanto, precisamos trabalhar nisso, precisamos fazer com que essa rota também seja estática.

Conclusão e Próximos Passos

Portanto, daqui para frente, vamos seguir os passos para nos aproximarmos da geração deste site estático e vamos verificar no output do yarn build se conseguimos atingir esse objetivo.

Então, o que buscamos é uma página que está acessando os produtos através de uma API, ou seja, estamos fazendo uma requisição HTTP e recuperando esses dados. Isso faz parte da progressão da nossa estratégia para gerar o site estático no final.

Portanto, acompanhem-nos, pois ainda não terminamos; precisamos implementar outras estratégias.

Sobre o curso Next.js: gerando site estático com SSG

O curso Next.js: gerando site estático com SSG possui 96 minutos de vídeos, em um total de 32 atividades. Gostou? Conheça nossos outros cursos de Next.JS em Front-end, ou leia nossos artigos de Front-end.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Next.JS acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas