O Next.js permite que você crie aplicativos da Web de pilha completa, estendendo os recursos mais recentes do React e integrando poderosas ferramentas JavaScript baseadas em Rust para compilações mais rápidas. Podemos trabalhar nele com aplicações SSR(Server Side Rendering) e SSG(Static Site Generator).
SPA traz o conceito de uma página única, ou seja, a aplicação web roda em uma página única ela é construída basicamente em HTML, CSS e JavaScript. Essa mágica acontece porque quando você faz a requisição do ‘website’ no servidor, todo o conteúdo e carregado uma única vez, na primeira vez que a requisição é feita.
Sempre que você alterna entre os "menus" deste site, o navegador não faz uma nova requisição no servidor, apenas alterna entre os conteúdos, essas páginas são carregadas através do JavaScript, sendo assim não é necessário novas requisições ao servidor para renderizar o novo conteúdo; Netflix e gmail são exemplos de ‘websites’ que usam o conceito SPA.
Pelo fato de não ser necessário fazer novas requisições no servidor, é possível interagir com a aplicação sem recarregar a página, trazendo uma melhor experiência para o usuário.
Como em uma SPA você precisa carregar o JavaScript para então fazer requisições, você acaba não tendo conteúdo para ser indexado por motores de busca. Hoje, já existem maneiras de auxiliar o SEO em aplicações SPA, mas ainda assim, esse é um possível ponto de atenção.
SSR é a renderização do lado do servidor, ele mantém as principais vantagens do SPA e corrige um problema ocasionado por ela. Fazendo a renderização de aplicações SPA no servidor, traz ao usuário um carregamento mais eficiente da aplicação, possibilidade de melhorar a performance e corrige o problema com indexação nos motores de busca já que parte do conteúdo e carregado no servidor; Next e Gatsby são exemplos de servidores que podem ser usados com esse objetivo.
SSG é uma página que não é gerada em tempo de execução de uma aplicação web, diferente das páginas dinâmicas o conteúdo é fixo; SSG é a geração de páginas estáticas.
Com SSG você pode configurar de quanto em quanto tempo será feita uma nova requisição ao servidor, vejamos um exemplo: imagine um site que recebe poucas alterações(Landing page de sua empresa), ou alterações de tempos em tempos; quando a sua aplicação é requisitada por um cliente(usuário final), não existe a necessidade de regerar a aplicação em tempo de execução já que não houve mudanças no ‘website’, resumindo caso seu site mude apenas a cada 5 dias, a primeira requisição feita ao seu ‘website’ será feita normalmente, e as outras infinitas requisições que forem feitas por infinitos clientes dentro desse intervalo serão buscadas em uma espécie de "cache da sua aplicação no servidor".
- Dentro da pasta do projeto, vamos rodar o comando(mais recomendado atualmente usar o npx):
> npx create-next-app@latest
npx: Comando que vai se encarregar de baixar uma dependência que vamos usar apenas de forma temporária. Ele baixa essa dependência, executa o que tem que ser executado e depois exclui ela. Desse modo, não instalamos as dependências de forma global, evitando ocupar espaço na máquina.
create-next-app: Dependência para criar um projeto.
- Ao finalizar a criação ele informa no terminal os próximos passos. Primeiro, entrar na pasta da aplicação:
> cd ignite-shop
[nome-pasta-aplicação]
- Segundo, rodar o comando para iniciar o projeto:
> npm run dev
Dentro do vscode, podemos notar que foram criados os seguintes diretórios no projeto:
.next
node_modules
public
pages
styles
Vamos criar uma pasta src na raiz do projeto. E mover as pastas pages e styles para dentro de src
- Agora, vamos parar a aplicação
> ctrl + c
- E rodar novamente, para que a página seja recarregada:
> npm run dev
- Vamos criar também a pasta
components
dentro desrc
;
Agora vamos entender sobre o roteamento do NextJS, como podemos utilizar o sistema de arquivos para criar rotas a partir do nome dos nossos arquivos no NextJS.
- Para isso, dentro de
src/pages
vamos criar um arquivo com o nome da nossa rota(product e Success) que vai poder ser acessada através delocalhost:3000/[nome-arquivo]
. E o conteúdo desse arquivo será um componente:
import React from "react";
const Product = () => {
return <h1>Product</h1>;
};
export default Product;
- Se quisermos receber parâmetros nessa url, podemos criar uma pasta com o nome do arquivo(product e Success) e adicionar
[nome-parâmetro]
no nome do arquivo tsx(ex.:src/pages/product/[id].tsx
).
- No Next não temos um arquivo chamado
index.html
, as configurações de carregamento de fontes do nosso app são colocadas dentro do arquivo_document.tsx
. Como é feito a seguir:
import { Html, Head, Main, NextScript } from "next/document";
const Document = () => {
return (
<Html>
<Head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin="anonymous"
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
rel="stylesheet"
/>
</Head>
<body>
<Main />
<NextScript /> {/* Essa TAG indica o local onde iremos carregar o script da aplicação*/}
</body>
</Html>
);
}
export default Document;
Ferramenta CSS-in-JS com foco em performance e experiencia de desenvolvimento que utilizaremos para estilizar a nossa aplicação.
- Para configurar Stitches, iremos criar um arquivo
styles/index.ts
(.js
funciona também) e importar a funçãocreateStitches
:
import { createStitches } from "@stitches/react";
Esta função recebe um objeto de configuração:
theme
: defina seu tema de design , que mapeia para as propriedades CSS.media
: Definir pontos de interrupção responsivos reutilizáveis .utils
: crie utilitários personalizados para melhorar sua experiência de desenvolvedor.prefix
: Prefixe nomes de classe e variáveis CSS para evitar conflitos.themeMap
: Defina o mapeamento personalizado de propriedades CSS para tokens de tema.
E retorna todas as funções disponíveis acima:
import { createStitches } from "@stitches/react";
export const {
config,
styled,
css,
globalCss,
keyframes,
getCssText,
theme,
createTheme
} = createStitches({
theme: {
colors: {
rocketseat: "#8257e6"
}
}
});
- Deste ponto em diante, iremos importar
styled
e outras funções do arquivostyles/index.ts
(mas como não precisa especificar o index.ts - vamos importar direto da pasta styles):
import { styled } from "../styles";
const Button = styled("button", {
display: "flex",
backgroundColor: "$rocketseat",
borderRadius: 4,
border: 0,
gap: "0.5rem",
padding: "4px 8px",
span: {
fontWeight: "bold"
},
"&:hover": {
filter: "brightness(0.8)"
}
});
const Home = () => {
return (
<Button>
<span>Teste</span>
Enviar
</Button>
);
}
export default Home;
- Para configurar os estilos globais com Stitches, iremos criar um arquivo
styles/global.ts
(.js
funciona também) e importar a funçãoglobalCss
e dentro iremos definir os estilos globais do projeto:
import { globalCss } from ".";
export const globalStyles = globalCss({
"*": {
margin: 0,
padding: 0
},
body: {
backgroundColor: "$gray900",
color: "$gray100",
"-webkit-font-smoothing": "antialiased"
},
"body, input, textarea, button": {
fontFamily: "Roboto",
fontWeight: 400
}
});
- Feito isso, iremos importar o
globalStyles
dentro de_app.tsx
:
import { AppProps } from "next/app";
import { globalStyles } from "../styles/global";
globalStyles();
const App = ({ Component, pageProps }: AppProps) => {
return (
<Component {...pageProps} />
);
}
export default App;
Agora entenderemos sobre as formas de se buscar dados no NextJS, como por exemplos chamadas à API e chamadas HTTP.
Entenderemos a diferença de fazer chamadas HTTP no lado do cliente e também no lado do servidor, e as chamadas do lado do servidor podem nos beneficiar em alguns casos.
- O next não devolve nada para o front-end antes que tudo esteja carregado (princípio de aplicações SSR), o código que colocarmos dentro não ficar visível para o usuário final, desse modo, podemos colocar código sensível (código de autenticaçao, de banco de dados...):
export const getServerSideProps: GetServerSideProps = async () => {
// o next não devolve nada para o front end antes que tudo esteja carregado (princípio de aplicações SSR)
// o código que colocarmos aqui dentro não ficar visível para o usuário final, desse modo, podemos colocar código sensível (código de autenticaçao, de banco de dados...)
const response = await stripe.products.list({
expand: ["data.default_price"] // acessando a tabela de relacionada a tabela de products - default_price
});
// console.log(response.data); // só aparece no console do node(terminal)
const products = response.data.map((product) => {
const price = product.default_price as Stripe.Price;
return {
id: product.id,
name: product.name,
imageUrl: product.images[0],
price: price.unit_amount / 100
};
});
return {
props: {
products
}
};
};
Podemos usar o SSG para criar uma versão estática da nossa página que fica cacheada para acelerar o carregamento e até diminuir o número de requisições à API.
- Roda somente no momento que next criar a versão de cache da página (na build) - aplicações SSG, dentro não temos acesso ao contexto da aplicação (usuário logado por exemplo):
export const getStaticProps: GetStaticProps = async () => { // roda somente no momento que next criar a versão de cache da página (na build) - SSG
// aqui dentro não temos acesso ao contexto da aplicação (usuário logado por exemplo)
const response = await stripe.products.list({
expand: ["data.default_price"]
});
const products = response.data.map((product) => {
const price = product.default_price as Stripe.Price;
return {
id: product.id,
name: product.name,
imageUrl: product.images[0],
price: price.unit_amount / 100
};
});
return {
props: {
products
},
revalidate: 60 * 60 * 2 // essa página será recriada a cada 2 horas
};
};