O desenvolvimento web evoluiu significativamente desde os primeiros dias dos simples sites pessoais de página única. Hoje, temos à disposição uma variedade de linguagens, frameworks e sistemas de gerenciamento de conteúdo, cada um projetado para atender a uma infinidade de necessidades específicas.

É neste cenário que o Astro se destaca, sendo um dos mais recentes e empolgantes frameworks JavaScript.

Criado por Fred K. Schott e um grupo de outros colaboradores, o Astro rapidamente se tornou um favorito na comunidade de desenvolvimento. É um framework completo que funciona muito como um gerador de sites estáticos.

Neste artigo, exploraremos por que tantos desenvolvedores estão optando pelo Astro em vez de outras alternativas e mostraremos como criar um blog baseado em markdown usando este framework.

O que é o Astro?

Astro
Astro

O Astro, ou Astro.js, é um gerador de sites estáticos popular, concebido para quem deseja criar sites ricos em conteúdo, que sejam executados de forma rápida e suave. Sua natureza leve, estrutura intuitiva e curva de aprendizado suave o tornam atraente para desenvolvedores de todos os níveis de experiência.

Apesar de seu pequeno tamanho, o Astro vem com ferramentas poderosas que aumentam drasticamente a flexibilidade do seu site, economizando horas em gerenciamento de conteúdo e temas. Além disso, ele oferece aos desenvolvedores a opção de trabalhar com seus frameworks preferidos em conjunto com o Astro — uma perspectiva atraente para programadores experientes que já têm uma série de favoritos.

Aqui estão alguns dos motivos pelas quais o Astro se destaca dos demais:

  • Arquitetura de ilhas: O Astro extrai sua interface de usuário (UI) em componentes menores e isolados, conhecidos como “Astro Islands”, que podem ser usados em qualquer página. O JavaScript não utilizado é substituído por HTML leve.
  • Zero JavaScript (por padrão): Embora você possa usar todo o JavaScript que quiser para criar seus sites, o Astro tentará implementar zero JavaScript na produção, transcrevendo o código para você. Essa é uma abordagem perfeita se você se concentrar na velocidade do site.
  • SSG e SSR incluídos: O Astro começou como um gerador de sites estáticos, mas, ao longo do caminho, tornou-se um framework que usa tanto a geração de sites estáticos (SSG) quanto a renderização do lado do servidor (SSR). E você pode escolher quais páginas usarão cada abordagem.
  • Agnóstico em relação ao framework: Ao usar o Astro, você pode usar qualquer framework JavaScript que desejar, até mesmo vários frameworks ao mesmo tempo. (Falaremos sobre isso com mais detalhes mais tarde neste artigo.)

Além disso, o Astro está pronto para o Edge, o que significa que ele pode ser implantado em qualquer lugar, a qualquer momento, com facilidade.

Você está pronto para saber mais? Vamos nos aprofundar em como o Astro funciona.

Estrutura do Astro

Antes de avançarmos, é importante entender como o Astro é configurado para que você possa usá-lo de forma eficaz. Vamos dar uma olhada na estrutura de arquivos principal do Astro:

├── dist/
├── src/
│   ├── components/
│   ├── layouts/
│   └── pages/
│       └── index.astro
├── public/
└── package.json

Como você pode ver, a estrutura em si é bastante simples. No entanto, existem alguns pontos-chave que você deve lembrar:

  • A maior parte do nosso projeto está na pasta src. Você pode organizar seus componentes, layouts e páginas em subpastas. Você pode adicionar outras pastas para facilitar a navegação no seu projeto.
  • A pasta public é para todos os arquivos que ficam fora do processo de build, como fontes, imagens ou um arquivo robots.txt.
  • A pasta dist conterá todo o conteúdo que você deseja implementar no servidor de produção.

A seguir, vamos nos aprofundar nos principais componentes do Astro: componentes, layouts e páginas.

Componentes

Os componentes são partes reutilizáveis de código que podem ser incluídas em todo o site, de forma semelhante aos códigos de acesso no WordPress. Por padrão, eles têm a extensão de arquivo .astro, mas você também pode usar componentes não Astro criados com Vue, React, Preact ou Svelte.

A seguir, você verá um exemplo da aparência de um componente simples – nesse caso, uma tag classificada div contendo h2:

<!-- src/components/Kinsta.astro -->
<div class="kinsta_component">
    <h2>Hello, Kinsta!</h2>
</div>

E aqui está como podemos incorporar esse componente em nosso site:

---
import KinstaComponent from ../components/Kinsta.astro
---
<div>
    <KinstaComponent />
</div>

Conforme demonstrado acima, primeiro você precisa importar o componente. Só então ele poderá ser incluído na página.

Agora é hora de adicionar algumas propriedades ao nosso componente. Vamos começar com uma propriedade {title}:

---
const { title = 'Hello' } = Astro.props
---

<div class="kinsta_component">
    <h2>{title}</h2>
</div>

E aqui está como nossa propriedade seria implementada:

---
import KinstaComponent from ../components/Kinsta.astro
---

<div>
    <!-- This shows "Good day" -->
    <KinstaComponent title="Good day"/>

    <!-- This shows "Hello" -->
    <KinstaComponent />
 </div>

Simples, certo?

Como você provavelmente já percebeu, o verdadeiro poder dos componentes do Astro está em sua natureza global e reutilizável. Eles permitem que você faça alterações radicais em todo o seu site editando apenas algumas linhas de código, o que pode economizar inúmeras horas que, de outra forma, seriam gastas em substituições de texto tediosas e meticulosas.

Layouts

Agora, vamos falar sobre layouts. Além de sua função de tema familiar, os layouts no Astro também são componentes reutilizáveis, mas são usados como invólucros de código.

Dê uma olhada neste exemplo:

---
// src/layouts/Base.astro
const { pageTitle = 'Hello world' } = Astro.props
---

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>{pageTitle}</title>
</head>
<body>
    <main>
        <slot />
    </main>
</body>
</html>

Observe a tag <slot /> aqui. O elemento <slot /> no Astro funciona como um espaço reservado para tags e conteúdo HTML reais.

Vamos ver isso em ação.

O código abaixo mostra nossa tag <slot /> sendo substituída pelo código desejado, tudo isso envolvido pelo nosso layout Base.astro:

---
import Base from '../layouts/Base.astro';
---

<Base title="Hello world">
    <div>
        <p>Some example text.</p>
    </div>
</Base>

Como você pode ver, nossa tag <slot /> foi substituída pelo HTML que ela representa, que é:

<div>
    <p>Some example text.</p>
</div>

Como você pode ver, os layouts, assim como os componentes, permitem que você reutilize partes do código em todo o site, simplificando o desafio de atualizar o conteúdo e o design global.

Páginas

As páginas são um tipo especial de componente responsável pelo roteamento, carregamento de dados e criação de templates.

O Astro usa roteamento baseado em arquivos para gerar páginas, em vez de roteamento dinâmico. O método baseado em arquivos não apenas consome menos largura de banda, mas também evita que você tenha de importar os componentes manualmente.

Aqui está um exemplo de rotas definidas:

src/pages/index.astro => yourdomain.com
src/pages/test.astro => domain.com/test
src/pages/test/subpage => domain.com/test/subpage

Com essas rotas, nossa página inicial resultante seria renderizada da seguinte forma:

<!-- src/pages/index.astro -->
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Hello World</title>
</head>
<body>
    <h1>Hello, Kinsta</h1>
</body>
</html>

Mas já sabemos como usar layouts, então vamos converter isso em algo que seja acessível globalmente:

---
import Base from '../layouts/Base.astro';
---

<Base>
    <h1>Hello, Kinsta</h1>
</Base>

Pronto, ficou muito mais limpo.

Discutiremos o roteamento no Astro com mais detalhes mais adiante neste artigo, mas por agora, vamos seguir para a parte divertida: construção e personalização do site.

Personalização e extensão do Astro

Chegou a hora de você aprender a personalizar seu site do Astro! Vamos usar coleções Markdown, roteamento, manipulação de imagens e uma integração com o React para criar e personalizar nosso site estático.

Coleções Markdown

Com a versão 2.0, o Astro introduziu uma maneira muito melhor de manter o conteúdo Markdown do que antes. Graças às coleções, podemos ter certeza de que todos os nossos dados de frontmatter estão incluídos e têm o tipo correto de associação.

Recentemente, na versão 2.5, eles adicionaram a possibilidade de gerenciar também arquivos JSON e YAML como coleções.

Pronto para colocar a mão na massa?

Primeiro, coloque todos os seus artigos Markdown na pasta src/content/collection_name. Vamos criar uma coleção de blogs para este projeto, portanto, em nossa demonstração, a pasta será src/content/blog.

Agora é hora de definir todos os campos necessários do frontmatter em nosso arquivo src/content/config.ts. Nosso blog precisará do seguinte:

  • title (string)
  • tags (array)
  • publishDate (hora)
  • image (string, opcional)

Resultado:

import { z, defineCollection } from 'astro:content';

const blogCollection = defineCollection({ 
    schema: z.object({
        title: z.string(),
        tags: z.array(z.string()),
        image: z.string().optional(),
        publishDate: z.date(),
    }),
});

export const collections = {
    'blog': blogCollection,
};

E é isso que o nosso arquivo Markdown article-about-astro.md contém:

---
title: Article about Astro
tags: [tag1, tag3]
publishDate: 2023-03-01
---
## Tamen risit

Lorem *markdownum flumina*, laceraret quodcumque Pachyne, **alter** enim
cadavera choro.

É verdade, não há nada de especial em nosso arquivo Markdown. Mas há uma mágica oculta aqui que se manifestará se cometermos um erro de digitação.

Digamos, por exemplo, que em vez de digitar publishDate, digitamos acidentalmente publishData. No caso de um erro de digitação como esse, o Astro lançará um erro:

blog → article-about-astro.md frontmatter does not match collection schema.
  "publishDate" is required.

Incrível, não é? Esse recurso pode nos ajudar a encontrar erros relacionados ao frontmatter em questão de segundos.

A última coisa que precisamos adicionar é uma página que mostre nossos dados. Vamos criar um arquivo em src/page/blog/[slug].astro com o seguinte código:

---
import Base from '../../layouts/Base.astro';
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
    const blogEntries = await getCollection('blog');
    return blogEntries.map(entry => ({
        params: { slug: entry.slug }, props: { entry },
  }));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<Base>
    <h1>{entry.data.title} </h1>
    <Content />
</Base>

Graças ao getStaticPaths, o Astro criará todas as páginas estáticas para cada artigo na coleção de blogs.

A única coisa que está faltando agora é uma listagem de todos os nossos artigos:

---
import Base from '../../layouts/Base.astro';

import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog');
---
<Base>
<ul>
    {blogEntries.map(item => <li> <strong><a href={'/blog/' + item.slug}>{item.data.title}</a></strong></li>)}
</ul>
</Base>

Como você pode ver, o uso de coleções torna essa tarefa extremamente simples.

Agora, vamos criar uma coleção de tipos de dados. Primeiro, precisamos abrir o arquivo src/content/config.ts novamente e adicionar uma nova coleção de dados:

import { z, defineCollection, referenece } from 'astro:content';

const blogCollection = defineCollection({ 
	type: 'content',
    schema: z.object({
        title: z.string(),
        tags: z.array(z.string()),
        image: z.string().optional(),
        publishDate: z.date(),
	    author: reference('authors')
    }),
});

const authorsCollection = defineCollection({ 
	type: 'data',
    schema: z.object({
        fullName: z.string(),
        country: z.string()
    }),
});


export const collections = {
    'blog': blogCollection,
'authors': authorsCollection,
};

Além de criar uma nova coleção, também adicionamos a referência ao autor na blogCollection.

É hora de criar um novo autor. Devemos criar um arquivo chamado maciek-palmowski.json em content/authors.json:

{
    "fullName": "Maciek Palmowski",
    "country": "Poland"
}

A última coisa que falta é pegar esses dados em nosso artigo. Para isso, precisaremos usar getEntry:

---
import Base from '../../layouts/Base.astro';
import { getCollection, getEntry } from 'astro:content';
export async function getStaticPaths() {
  const blogEntries = await getCollection('blog');
  return blogEntries.map(entry => ({
    params: { slug: entry.slug }, props: { entry },
  }));
}
const { entry } = Astro.props;
const author = await getEntry(entry.data.author);
const { Content } = await entry.render();
---
<Base>
<h1>{entry.data.title}</h1>
<h2>Author: {author.data.fullName}</h2>
<Content />
</Base>

Roteamento

O Astro tem dois modos de roteamento diferentes. Já aprendemos sobre o primeiro – roteamento estático (baseado em arquivos) – quando abordamos as páginas anteriormente.

Agora vamos mudar nosso foco para o roteamento dinâmico.

Usando parâmetros de rota dinâmica, você pode instruir um arquivo de página do Astro para automatizar a criação de várias páginas com a mesma estrutura. Isso é útil quando você tem uma grande quantidade de um tipo específico de página (pense em biografias de autores, perfis de usuários, artigos de documentação e assim por diante).

No próximo exemplo, trabalharemos na geração de páginas de biografia para nossos autores.

No modo de saída estático padrão do Astro, essas páginas são geradas no momento da build, o que significa que você deve predeterminar a lista de autores que recebem um arquivo correspondente. No modo dinâmico, por outro lado, as páginas são geradas mediante solicitação para qualquer caminho que corresponda.

Se você quiser passar uma variável como nome de arquivo, adicione colchetes ao redor dela:

pages/blog/[slug].astro -> blog/test, blog/about-me 

Vamos nos aprofundar nisso usando o código do nosso arquivo src/page/blog/[slug]:

---
import Base from '../../layouts/Base.astro';
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
    const blogEntries = await getCollection('blog');
    return blogEntries.map(entry => ({
        params: { slug: entry.slug }, props: { entry },
  }));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<Base>
    <h1>{entry.data.title}</h1>
    <Content />
</Base>

O caminho getStaticPaths é responsável por gerar todas as páginas estáticas. Ela retorna dois objetos:

  • params: Usado para preencher os colchetes em nossas URLs
  • props: Todos os valores que estamos passando para a página

E com isso, a criação da sua página está resolvida.

Manuseio de imagens

Não podemos falar de sites de alto desempenho sem mencionar formatos de imagem modernos, métodos de redimensionamento corretos e carregamento lento.

Felizmente, o Astro também nos dá cobertura nesse ponto. Graças ao pacote @astrojs/image, podemos introduzir todos os itens acima em questão de minutos.

Após instalar o pacote, você terá acesso a dois componentes: Image e Picture.

O componente Image é usado para criar uma tag <img /> otimizada. Aqui está um exemplo:

---
import { Image } from '@astrojs/image/components';
import heroImage from '../assets/hero.png';
---

<Image src={heroImage} format="avif" alt="descriptive text" />
<Image src={heroImage} width={300} alt="descriptive text" />
<Image src={heroImage} width={300} height={600} alt="descriptive text" />

Da mesma forma, o componente Picture cria um componente <picture/> otimizado:

---
import { Picture } from '@astrojs/image/components';
import hero from '../assets/hero.png';
---
<Picture src={hero} widths={[200, 400, 800]} sizes="(max-width: 800px) 100vw, 800px" alt="descriptive text" />

SSG vs SSR

Por padrão, o Astro é executado como um gerador de site estático. Isso significa que todo o conteúdo é convertido em páginas HTML estáticas.

Embora essa seja uma abordagem perfeita em muitas perspectivas (especialmente relacionadas à velocidade), às vezes você pode preferir uma abordagem mais dinâmica. Se você quiser uma página de perfil separada para cada usuário, por exemplo, ou se tiver milhares de artigos em seu site, renderizar tudo novamente a cada vez consumiria muito tempo.

Felizmente, o Astro também pode funcionar como um framework totalmente renderizado no lado do servidor ou em um modo híbrido entre os dois.

Para ativar o SSR lateral, precisamos adicionar o seguinte código ao astro.config.mjs:

import { defineConfig } from 'astro/config';

export default defineConfig({
    output: 'server'
});

Essa é a abordagem padrão.

A abordagem híbrida significa que, por padrão, tudo é gerado dinamicamente, exceto as páginas com export const prerender = true adicionado.

Com o Astro 2.5, você também pode definir a renderização estática como padrão e selecionar rotas dinâmicas manualmente.

Graças a isso, podemos, por exemplo, criar um site totalmente gerado estaticamente com páginas dinâmicas de login e perfil.

Você pode ler mais sobre isso na documentação oficial.

Integração de outros frameworks JavaScript

Outro recurso incrível do Astro permite que você traga seu framework favorito e o use em conjunto com o Astro. Você pode misturar o Astro com React, Preact, Svelte, Vue, Solid ou Alpine (para todas as integrações, consulte a documentação “Adicionar integrações” do Astro).

Digamos que você queira usar o React. Primeiro, precisamos instalar a integração executando o seguinte no npm:

npx astro add react

Agora que o React foi integrado, podemos criar um componente React. No nosso caso, ele será o componente contador em src/components/ReactCounter.tsx:

import { useState } from 'react';

/** A counter written with React */
export function Counter({ children }) {
    const [count, setCount] = useState(0);
    const add = () => setCount((i) => i + 1);
    const subtract = () => setCount((i) => i - 1);

    return (
        <>
            <div className="counter">
                <button onClick={subtract}>-</button>
                <pre>{count}</pre>
                <button onClick={add}>+</button>
                </div>
            <div className="counter-message">{children}</div>
        </>
    );
}

Por último, mas não menos importante, precisamos colocar o contador em nossa página com o seguinte código:

---
import * as react from '../components/ReactCounter';
---
<main>
    <react.Counter client:visible />
</main>

E pronto: seu componente React foi integrado perfeitamente ao site.

Como implantar o Astro usando a Kinsta

Agora é hora de colocar nosso site Astro na web. Felizmente, a Kinsta é a hospedagem perfeita para uma Hospedagem de Site Estático rápida e sem complicações.

Comece criando um repositório GitHub para os arquivos do seu site. Se não estiver pronto para usar seus próprios arquivos, você pode clonar este template de site inicial do Astro que nossa equipe criou.

Uma vez que seu repositório esteja pronto, siga estes passos para implantar seu site estático na Kinsta:

    1. Faça login ou crie uma conta para visualizar o painel do MyKinsta.
    2. Autorize a Kinsta com o seu provedor Git.
    3. Clique em Sites Estáticos na barra lateral à esquerda, e depois clique em Adicionar site.
    4. Selecione o repositório e o branch do qual deseja fazer a implantação.
    5. Atribua um nome único ao seu site.
    6. Adicione as configurações de build no seguinte formato:
      • Comando build: npm run build
      • Versão do Node: 18.16.0
      • Diretório de publicação: dist
    7. Por fim, clique em Criar site.

E é isso! Agora você tem um site estático ativo e totalmente funcional criado com o framework do Astro.

A dark page with the Kinsta logo in white in the center above the words
Nossa página inicial do Astro em ação.

Você pode encontrar a URL em tempo real e outros detalhes da implantação na aba Implantações.

Como alternativa à Hospedagem de Site Estático, você pode optar por implantar seu site estático com a Hospedagem de Aplicativos da Kinsta, que oferece maior flexibilidade de hospedagem, uma gama mais ampla de benefícios e acesso a recursos mais robustos. Por exemplo, escalonamento, implantação personalizada usando um Dockerfile e análises abrangentes que incluem dados em tempo real e históricos.

Resumo

A estrutura clara, a sintaxe simples e os componentes globais do Astro tornam a criação e a execução de um aplicativo realmente fácil. Sua natureza leve e o uso duplo de roteamento estático e dinâmico aumentam drasticamente a capacidade de resposta do site, enquanto sua capacidade de cooperar com e ao lado de outras frameworks de JavaScript o torna ainda mais atraente para programadores experientes.

Se o seu objetivo é criar um site rico em conteúdo que carregue rapidamente, conceda funcionalidade modular e forneça geração estática e dinâmica, então o Astro pode ser a escolha certa para você.

Você pode hospedar seu site estático com a Hospedagem de Site Estático da Kinsta gratuitamente.

O que você acha do gerador de sites estáticos Astro? Você já o usou em algum projeto seu? Conte-nos na seção de comentários abaixo.

Maciek Palmowski

Maciek é um desenvolvedor web atuando na Kinsta como Analista de Advocacia de Desenvolvimento. Quando não está trabalhando, ele se dedica principalmente à programação, à busca de notícias relevantes para suas newsletters.