Simplifique sua pilha com um gerador de site estático personalizado

Publicados: 2022-03-10
Resumo rápido ↬ No desenvolvimento moderno, existem muitas ferramentas excelentes para o desenvolvimento de sites, mas muitas vezes elas são mais do que o necessário para um determinado projeto. Neste artigo, vamos explorar como pegar uma humilde página HTML e tornar seu conteúdo editável em um CMS sem frameworks e sem JavaScript do lado do cliente.

Com o advento do movimento Jamstack, os sites servidos estaticamente tornaram-se a moda novamente. A maioria dos desenvolvedores que atendem a HTML estático não está criando HTML nativo. Para ter uma experiência de desenvolvedor sólida, muitas vezes recorremos a ferramentas chamadas Static Site Generators (SSG).

Essas ferramentas vêm com muitos recursos que tornam a criação de sites estáticos em grande escala agradável. Se eles fornecem ganchos simples em APIs de terceiros, como as fontes de dados do Gatsby, ou fornecem configurações detalhadas, como a enorme coleção de mecanismos de modelo da 11ty, há algo para todos na geração de sites estáticos.

Como essas ferramentas são criadas para diversos casos de uso, elas precisam ter muitos recursos. Esses recursos os tornam poderosos. Eles também os tornam bastante complexos e opacos para novos desenvolvedores. Neste artigo, vamos reduzir o SSG aos seus componentes básicos e criar o nosso próprio.

O que é um gerador de site estático?

Em sua essência, um gerador de site estático é um programa que realiza uma série de transformações em um grupo de arquivos para convertê-los em ativos estáticos, como HTML. Que tipo de arquivos ele pode aceitar, como os transforma e quais tipos de arquivos saem diferenciam os SSGs.

Jekyll, um SSG antigo e ainda popular, usa Ruby para processar modelos Liquid e arquivos de conteúdo Markdown em HTML.

Gatsby usa React e JSX para transformar componentes e conteúdo em HTML. Em seguida, ele vai um passo adiante e cria um aplicativo de página única que pode ser servido estaticamente.

11ty renderiza HTML de mecanismos de modelagem como Liquid, Handlebars, Nunjucks ou literais de modelo JavaScript.

Cada uma dessas plataformas possui recursos adicionais para facilitar nossas vidas. Eles fornecem temas, pipelines de construção, arquitetura de plugins e muito mais. Com cada recurso adicional vem mais complexidade, mais magia e mais dependências. Eles são recursos importantes, com certeza, mas nem todo projeto precisa deles.

Entre esses três SSGs diferentes, podemos ver outro tema comum: dados + templates = site final. Esta parece ser a funcionalidade principal dos sites estáticos do gerador. Esta é a funcionalidade em que basearemos nosso SSG.

Em sua essência, um gerador de site estático é um programa que realiza uma série de transformações em um grupo de arquivos para convertê-los em ativos estáticos, como HTML.

Nossa nova pilha de tecnologia do gerador de site estático: guidão, sanity.io e netlify

Para construir nosso SSG, precisaremos de um mecanismo de modelo, uma fonte de dados e um host que possa executar nosso SSG e construir nosso site. Muitos geradores usam Markdown como fonte de dados, mas e se dermos um passo adiante e conectarmos nativamente nosso SSG a um CMS?

  • Fonte de dados: Sanity.io
  • Busca e modelagem de dados: Node e Handlebars
  • Host e implantação: Netlify.

Pré-requisitos

  • NodeJS instalado
  • conta Sanity.io
  • Conhecimento em Git
  • Conhecimento básico de linha de comando
  • Conhecimento básico de implantação em serviços como Netlify.

Nota : Para acompanhar, você pode encontrar o código neste repositório no GitHub.

Mais depois do salto! Continue lendo abaixo ↓

Configurando nossa estrutura de documento em HTML

Para iniciar nossa estrutura de documentos, vamos escrever HTML simples. Não há necessidade de complicar as coisas ainda.

Em nossa estrutura de projeto, precisamos criar um local para nossos arquivos de origem viverem. Neste caso, criaremos um diretório src e colocaremos nosso index.html dentro dele.

Em index.html , descreveremos o conteúdo que queremos. Esta será uma página sobre relativamente simples.

 <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Title of the page!</title> </head> <body> <h1>The personal homepage of Bryan Robinson</h1> <p>Some pagraph and rich text content next</p> <h2>Bryan is on the internet</h2> <ul> <li><a href="linkURL">List of links</a></li> </ul> </body> </html>

Vamos manter isso simples. Começaremos com um h1 para nossa página. Seguiremos com alguns parágrafos de informações biográficas e ancoraremos a página com uma lista de links para ver mais.

Converter nosso HTML em um modelo que aceita dados

Depois de ter nossa estrutura básica, precisamos configurar um processo para combinar isso com uma certa quantidade de dados. Para fazer isso, usaremos o mecanismo de modelo Handlebars.

Em sua essência, o Handlebars pega uma string semelhante a HTML, insere dados por meio de regras definidas no documento e, em seguida, gera uma string HTML compilada.

Para usar Handlebars, precisaremos inicializar um package.json e instalar o pacote.

Execute npm init -y para criar a estrutura de um arquivo package.json com algum conteúdo padrão. Uma vez que temos isso, podemos instalar o Handlebars.

 npm install handlebars

Nosso script de construção será um script Node. Este é o script que usaremos localmente para construir, mas também o que nosso fornecedor de implantação e host usarão para construir nosso HTML para o site ativo.

Para iniciar nosso script, criaremos um arquivo index.js e exigiremos dois pacotes na parte superior. O primeiro é Handlebars e o segundo é um módulo padrão no Node para acessar o sistema de arquivos atual.

 const fs = require('fs'); const Handlebars = require('handlebars');

Usaremos o módulo fs para acessar nosso arquivo de origem, bem como para gravar em um arquivo de distribuição. Para iniciar nossa compilação, criaremos uma função main para que nosso arquivo seja executado quando chamado e uma função buildHTML para combinar nossos dados e marcação.

 function buildHTML(filename, data) { const source = fs.readFileSync(filename,'utf8').toString(); const template = Handlebars.compile(source); const output = template(data); return output } async function main(src, dist) { const html = buildHTML(src, { "variableData": "This is variable data"}); fs.writeFile(destination, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); } main('./src/index.html', './dist/index.html');

A função main() aceita dois argumentos: o caminho para nosso template HTML e o caminho que queremos que nosso arquivo construído viva. Em nossa função principal, executamos buildHTML no caminho de origem do modelo com uma certa quantidade de dados.

A função build converte o documento de origem em uma string e passa essa string para o Handlebars. Handlebars compila um modelo usando essa string. Em seguida, passamos nossos dados para o modelo compilado e o Handlebars renderiza uma nova string HTML substituindo qualquer variável ou lógica do modelo pela saída de dados.

Retornamos essa string em nossa função main e usamos o método writeFile fornecido pelo módulo do sistema de arquivos do Node para gravar o novo arquivo em nosso local especificado se o diretório existir.

Para evitar um erro, adicione um diretório dist em seu projeto com um arquivo .gitkeep nele. Não queremos submeter nossos arquivos compilados (nosso processo de compilação fará isso), mas queremos ter certeza de ter esse diretório para nosso script.

Antes de criarmos um CMS para gerenciar esta página, vamos confirmar se está funcionando. Para testar, modificaremos nosso documento HTML para usar os dados que acabamos de passar para ele. Usaremos a sintaxe da variável Handlebars para incluir o conteúdo variableData .

 <h1>{{ variableData }}</h1>

Agora que nosso HTML tem uma variável, estamos prontos para executar nosso script de nó.

 node index.js

Quando o script terminar, devemos ter um arquivo em /dist/index.html . Se lermos open this em um navegador, veremos nossa marcação renderizada, mas também nossa string “This is variable data”.

Conectando a um CMS

Temos uma maneira de juntar dados com um modelo, agora precisamos de uma fonte para nossos dados. Esse método funcionará com qualquer fonte de dados que tenha uma API. Para esta demonstração, usaremos o Sanity.io.

Sanity é uma fonte de dados que prioriza a API que trata o conteúdo como dados estruturados. Eles têm um sistema de gerenciamento de conteúdo de código aberto para tornar o gerenciamento e a adição de dados mais conveniente para editores e desenvolvedores. O CMS é o que muitas vezes é chamado de CMS “Headless”. Em vez de um sistema de gerenciamento tradicional em que seus dados são fortemente acoplados à sua apresentação, um CMS headless cria uma camada de dados que pode ser consumida por qualquer front-end ou serviço (e possivelmente muitos ao mesmo tempo).

O Sanity é um serviço pago, mas eles têm um plano “Padrão” que é gratuito e tem todos os recursos que precisamos para um site como esse.

Configurando a Sanidade

A maneira mais rápida de começar a trabalhar com um novo projeto Sanity é usar o Sanity CLI. Começaremos instalando isso globalmente.

 npm install -g @sanity/cli

A CLI nos dá acesso a um grupo de auxiliares para gerenciamento, implantação e criação. Para começar, executaremos o sanity init . Isso nos levará a um questionário para ajudar a inicializar nosso Studio (o que a Sanity chama de CMS de código aberto).

 Select a Project to Use: Create new project HTML CMS Use the default dataset configuration? Y // this creates a "Production" dataset Project output path: studio // or whatever directory you'd like this to live in Select project template Clean project with no predefined schemas

Esta etapa criará um novo projeto e conjunto de dados em sua conta Sanity, criará uma versão local do Studio e vinculará os dados e o CMS para você. Por padrão, o diretório studio será criado na raiz do nosso projeto. Em projetos de maior escala, você pode configurar isso como um repositório separado. Para este projeto, não há problema em manter isso unido.

Para executar nosso Studio localmente, mudaremos o diretório para o diretório studio e executaremos sanity start . Isso executará o Studio em localhost:3333 . Ao fazer login, você verá uma tela para informar que tem "Esquema vazio". Com isso, é hora de adicionar nosso esquema, que é como nossos dados serão estruturados e editados.

Criando Esquema de Sanidade

A maneira de criar documentos e campos no Sanity Studio é criar esquemas no arquivo schemas/schema.js .

Para nosso site, criaremos um tipo de esquema chamado "Sobre detalhes". Nosso esquema fluirá de nosso HTML. Em geral, poderíamos transformar a maior parte de nossa página da Web em um único campo de rich text, mas é uma prática recomendada estruturar nosso conteúdo de maneira desacoplada. Isso fornece maior flexibilidade em como podemos usar esses dados no futuro.

Para nossa página da Web, queremos um conjunto de dados que inclua o seguinte:

  • Título
  • Nome completo
  • Biografia (com edição de rich text)
  • Uma lista de sites com um nome e URL.

Para definir isso em nosso esquema, criamos um objeto para nosso documento e definimos seus campos. Uma lista anotada de nosso conteúdo com seu type campo:

  • Título — sequência
  • Nome Completo — string
  • Biografia — matriz de “blocos”
  • Lista de sites — array de objetos com campos de string de nome e URL.
 types: schemaTypes.concat([ /* Your types here! */ { title: "About Details", name: "about", type: "document", fields: [ { name: 'title', type: 'string' }, { name: 'fullName', title: 'Full Name', type: 'string' }, { name: 'bio', title: 'Biography', name: 'content', type: 'array', of: [ { type: 'block' } ] }, { name: 'externalLinks', title: 'Social media and external links', type: 'array', of: [ { type: 'object', fields: [ { name: 'text', title: 'Link text', type: 'string' }, { name: 'href', title: 'Link url', type: 'string' } ] } ] } ] } ])

Adicione isso aos seus tipos de esquema, salve e seu Studio recompilará e apresentará seus primeiros documentos. A partir daqui, adicionaremos nosso conteúdo ao CMS criando um novo documento e preenchendo as informações.

Estruturando seu conteúdo de forma reutilizável

Neste ponto, você pode estar se perguntando por que temos um “nome completo” e um “título”. Isso porque queremos que nosso conteúdo tenha o potencial de ser multiuso. Ao incluir um campo de nome em vez de incluir o nome apenas no título, damos mais uso a esses dados. Podemos então usar as informações neste CMS para também alimentar uma página de currículo ou PDF. O campo biografia pode ser usado programaticamente em outros sistemas ou sites. Isso nos permite ter uma única fonte de verdade para grande parte desse conteúdo, em vez de ser ditado pelo caso de uso direto desse site específico.

Puxando nossos dados para nosso projeto

Agora que disponibilizamos nossos dados por meio de uma API, vamos colocá-los em nosso projeto.

Instalar e configurar o cliente JavaScript Sanity

Em primeiro lugar, precisamos de acesso aos dados no Node. Podemos usar o cliente JavaScript Sanity para forjar essa conexão.

 npm install @sanity/client

Isso irá buscar e instalar o SDK do JavaScript. A partir daqui, precisamos configurá-lo para buscar dados do projeto que configuramos anteriormente. Para fazer isso, configuraremos um script de utilitário em /utils/SanityClient.js . Fornecemos ao SDK o ID do projeto e o nome do conjunto de dados e estamos prontos para usá-lo em nosso script principal.

 const sanityClient = require('@sanity/client'); const client = sanityClient({ projectId: '4fs6x5jg', dataset: 'production', useCdn: true }) module.exports = client;

Buscando nossos dados com o GROQ

De volta ao nosso arquivo index.js , criaremos uma nova função para buscar nossos dados. Para fazer isso, usaremos a linguagem de consulta nativa da Sanity, o GROQ de código aberto.

Construiremos a consulta em uma variável e, em seguida, usaremos o cliente que configuramos para buscar os dados com base na consulta. Nesse caso, construímos um objeto com uma propriedade chamada about . Neste objeto, queremos retornar os dados para nosso documento específico. Para isso, consultamos com base no documento _id que é gerado automaticamente quando criamos nosso documento.

Para encontrar o _id do documento, navegamos até o documento no Studio e o copiamos da URL ou passamos para o modo “Inspecionar” para visualizar todos os dados do documento. Para entrar no Inspect, clique no menu “kabob” no canto superior direito ou use o atalho Ctrl + Alt + I . Essa visualização listará todos os dados deste documento, incluindo nosso _id . Sanity retornará uma matriz de objetos de documento, então, para simplificar, retornaremos a 0th entrada.

Em seguida, passamos a consulta para o método fetch do nosso cliente Sanity e ele retornará um objeto JSON de todos os dados em nosso documento. Nesta demonstração, retornar todos os dados não é grande coisa. Para implementações maiores, o GROQ permite uma “projeção” opcional para retornar apenas os campos explícitos que você deseja.

 const client = require('./utils/SanityClient') // at the top of the file // ... async function getSanityData() { const query = `{ "about": *[_id == 'YOUR-ID-HERE'][0] }` let data = await client.fetch(query); }

Convertendo o campo Rich Text para HTML

Antes de podermos retornar os dados, precisamos fazer uma transformação em nosso campo de rich text. Enquanto muitos CMSs usam editores de rich text que retornam HTML diretamente, o Sanity usa uma especificação de código aberto chamada Portable Text. Portable Text retorna uma matriz de objetos (pense em rich text como uma lista de parágrafos e outros blocos de mídia) com todos os dados sobre o estilo de rich text e propriedades como links, notas de rodapé e outras anotações. Isso permite que seu texto seja movido e usado em sistemas que não suportam HTML, como assistentes de voz e aplicativos nativos.

Para nosso caso de uso, significa que precisamos transformar o objeto em HTML. Existem módulos NPM que podem ser usados ​​para converter texto portátil em vários usos. No nosso caso, usaremos um pacote chamado block-content-to-html.

 npm install @sanity/block-content-to-html

Este pacote renderizará toda a marcação padrão do editor de rich text. Cada tipo de estilo pode ser substituído para se adequar a qualquer marcação necessária para seu caso de uso. Nesse caso, deixaremos o pacote fazer o trabalho por nós.

 const blocksToHtml = require('@sanity/block-content-to-html'); // Added to the top async function getSanityData() { const query = `{ "about": *[_type == 'about'][0] }` let data = await client.fetch(query); data.about.content = blocksToHtml({ blocks: data.about.content }) return await data }

Usando o conteúdo do Sanity.io no guidão

Agora que os dados estão em uma forma que podemos usá-los, passaremos isso para nossa função buildHTML como o argumento de dados.

 async function main(src, dist) { const data = await getSanityData(); const html = buildHTML(src, data) fs.writeFile(dist, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); }

Agora, podemos alterar nosso HTML para usar os novos dados. Usaremos mais chamadas de variáveis ​​em nosso modelo para extrair a maioria de nossos dados.

Para renderizar nossa variável de content de rich text, precisaremos adicionar uma camada extra de chaves à nossa variável. Isso dirá ao Handlebars para renderizar o HTML em vez de exibir o HTML como uma string.

Para nosso array externalLinks , precisaremos usar a funcionalidade de loop integrada do Handlebars para exibir todos os links que adicionamos ao nosso Studio.

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ about.title }}</title> </head> <body> <h1>The personal homepage of {{ about.fullName }}</h1> {{{ about.content }}} <h2>Bryan is on the internet</h2> <ul> {{#each about.externalLinks }} <li><a href="{{ this.href }}">{{ this.text }}</a></li> {{/each}} </ul> </body> </html>

Configurando a implantação

Vamos fazer isso ao vivo. Precisamos de dois componentes para fazer isso funcionar. Primeiro, queremos um host estático que construa nossos arquivos para nós. Em seguida, precisamos acionar uma nova compilação do nosso site quando o conteúdo é alterado em nosso CMS.

Implantando no Netlify

Para hospedagem, usaremos o Netlify. Netlify é um host de site estático. Ele atende ativos estáticos, mas possui recursos adicionais que farão com que nosso site funcione sem problemas. Eles têm uma infraestrutura de implantação integrada que pode executar nosso script de nó, webhooks para acionar compilações e uma CDN distribuída globalmente para garantir que nossa página HTML seja atendida rapidamente.

A Netlify pode assistir nosso repositório no GitHub e criar uma compilação baseada em um comando que podemos adicionar em seu painel.

Primeiro, precisaremos enviar esse código para o GitHub. Então, no Dashboard do Netlify, precisamos conectar o novo repositório a um novo site no Netlify.

Uma vez conectado, precisamos dizer ao Netlify como construir nosso projeto. No painel, iremos para Configurações > Compilar e implantar > Configurações de compilação. Nesta área, precisamos alterar nosso “comando Build” para “node index.js” e nosso “diretório de publicação” para “./dist”.

Quando o Netlify construir nosso site, ele executará nosso comando e, em seguida, verificará a pasta que listamos para obter conteúdo e publicará o conteúdo.

Configurando um Webhook

Também precisamos dizer à Netlify para publicar uma nova versão quando alguém atualizar o conteúdo. Para fazer isso, configuraremos um Webhook para notificar a Netlify de que precisamos que o site seja reconstruído. Um Webhook é uma URL que pode ser acessada programaticamente por um serviço diferente (como Sanity) para criar uma ação no serviço de origem (neste caso, Netlify).

Podemos configurar um “gancho de compilação” específico em nosso painel Netlify em Configurações> Construir e implantar> Ganchos de compilação. Adicione um gancho, dê um nome e salve. Isso fornecerá uma URL que pode ser usada para acionar remotamente uma compilação no Netlify.

Em seguida, precisamos dizer à Sanity para fazer uma solicitação para esta URL quando você publicar as alterações.

Podemos usar o Sanity CLI para fazer isso. Dentro do nosso diretório /studio , podemos executar o sanity hook create para conectar. O comando solicitará um nome, um conjunto de dados e um URL. O nome pode ser o que você quiser, o conjunto de dados deve ser de production para nosso produto e o URL deve ser o URL fornecido pela Netlify.

Agora, sempre que publicarmos conteúdo no Studio, nosso site será atualizado automaticamente. Sem necessidade de enquadramento.

  • O código pode ser encontrado neste repositório GitHub →

Próximos passos

Este é um pequeno exemplo do que você pode fazer quando cria suas próprias ferramentas. Embora SSGs mais completos possam ser o que você precisa para a maioria dos projetos, criar seu próprio mini-SSG pode ajudá-lo a entender mais sobre o que está acontecendo no gerador de sua escolha.

  • Este site publica apenas uma página, mas com um pouco mais em nosso script de construção, poderíamos fazer com que ele publicasse mais páginas. Poderia até publicar um post no blog.
  • A “experiência do desenvolvedor” está um pouco ausente no repositório. Poderíamos executar nosso script Node em qualquer arquivo salvo implementando um pacote como Nodemon ou adicionar “recarregamento a quente” com algo como BrowserSync.
  • Os dados que residem no Sanity podem alimentar vários sites e serviços. Você pode criar um site de currículo que use isso e publique um PDF em vez de uma página da web.
  • Você pode adicionar CSS e fazer isso parecer um site real.