Construindo um site estático com componentes usando Nunjucks

Publicados: 2022-03-10
Resumo rápido ↬ Mesmo que você não use nenhum JavaScript do lado do cliente para construir um site, isso não significa que você tenha que desistir da ideia de construir com componentes. Aprenda a construir um site estático com a ajuda de um pré-processador HTML.

É bastante popular hoje em dia, e ouso dizer uma ótima ideia, construir sites com componentes. Em vez de construir páginas inteiras uma a uma, construímos um sistema de componentes (pense: um formulário de pesquisa, um cartão de artigo, um menu, um rodapé) e então juntamos o site com esses componentes.

Estruturas JavaScript como React e Vue enfatizam fortemente essa ideia. Mas mesmo que você não use nenhum JavaScript do lado do cliente para construir um site, isso não significa que você tenha que desistir da ideia de construir com componentes! Usando um pré-processador HTML, podemos construir um site estático e ainda obter todos os benefícios de abstrair nosso site e seu conteúdo em componentes reutilizáveis.

Sites estáticos estão na moda hoje em dia, e com razão, pois são rápidos, seguros e baratos para hospedar. Até a Smashing Magazine é um site estático, acredite ou não!

Vamos dar uma volta por um site que construí recentemente usando essa técnica. Eu usei o CodePen Projects para construí-lo, que oferece o Nunjucks como pré-processador, que foi perfeitamente adequado para o trabalho.

Um site de quatro páginas com cabeçalho, navegação e rodapé consistentes

Este é um microsite. Ele não precisa de um CMS completo para lidar com centenas de páginas. Ele não precisa de JavaScript para lidar com a interatividade. Mas precisa de um punhado de páginas que compartilham o mesmo layout.

Cabeçalho e rodapé consistentes
Cabeçalho e rodapé consistentes em todas as páginas
Mais depois do salto! Continue lendo abaixo ↓

HTML sozinho não tem uma boa solução para isso. O que precisamos são importações . Linguagens como PHP tornam isso simples com coisas como <?php include "header.php"; ?> <?php include "header.php"; ?> , mas hosts de arquivos estáticos não executam PHP (de propósito) e HTML sozinho não ajuda. Felizmente, podemos pré-processar inclusões com Nunjucks.

Importando componentes para páginas
Importar componentes é possível em linguagens como PHP

Faz todo o sentido aqui criar um layout , incluindo pedaços de HTML representando o cabeçalho, a navegação e o rodapé. O modelo Nunjucks tem o conceito de blocos, que nos permite inserir conteúdo nesse local quando usamos o layout.

 <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Power of Serverless</title> <link rel="stylesheet" href="/styles/style.processed.css"> </head> <body> {% include "./template-parts/_header.njk" %} {% include "./template-parts/_nav.njk" %} {% block content %} {% endblock %} {% include "./template-parts/_footer.njk" %} </body>

Observe que os arquivos incluídos são nomeados como _file.njk . Isso não é totalmente necessário. Pode ser header.html ou icons.svg , mas eles são nomeados assim porque 1) arquivos que começam com sublinhados são um pouco de uma maneira padrão de dizer que são parciais. Em Projetos CodePen, isso significa que eles não tentarão ser compilados sozinhos. 2) Ao nomeá-lo .njk , poderíamos usar mais coisas do Nunjucks se quisermos.

Nenhum desses bits tem nada de especial neles. Eles são apenas pequenos pedaços de HTML destinados a serem usados ​​em cada uma de nossas quatro páginas.

 <footer> <p>Just a no-surprises footer, people. Nothing to see here.<p> </footer>

Feito desta forma, podemos fazer uma mudança e ter a mudança refletida em todas as quatro páginas.

Usando o layout para as quatro páginas

Agora cada uma de nossas quatro páginas pode ser um arquivo. Vamos apenas começar com index.njk , que em Projetos CodePen, será processado automaticamente e criará um arquivo index.html toda vez que você salvar.

O arquivo index.njk
Começando com um arquivo index.njk

Aqui está o que poderíamos colocar em index.njk para usar o layout e soltar algum conteúdo nesse bloco:

 {% extends "_layout.njk" %} {% block content %} <h1>Hello, World!</h1> {% endblock %}

Isso nos comprará uma página inicial totalmente funcional! Agradável! Cada uma das quatro páginas pode fazer exatamente a mesma coisa, mas colocando conteúdo diferente no bloco, e temos um pequeno site de quatro páginas que é fácil de gerenciar.

index.html compilado
O arquivo index.njk é compilado em index.html

Para constar, não tenho certeza se chamaria esses pequenos pedaços de componentes de reutilização. Estamos apenas sendo eficientes e dividindo um layout em partes. Eu penso em um componente mais como um pedaço reutilizável que aceita dados e gera uma versão única de si mesmo com esses dados. Chegaremos a isso.

Tornando a navegação ativa

Agora que repetimos um pedaço idêntico de HTML em quatro páginas, é possível aplicar CSS exclusivo a itens de navegação individuais para identificar a página atual? Poderíamos com JavaScript e olhando para window.location e tal, mas podemos fazer isso sem JavaScript. O truque é colocar uma class no <body> exclusiva para cada página e usar isso no CSS.

Em nosso _layout.njk temos como saída do corpo um nome de classe como uma variável:

 <body class="{{ body_class }}">

Então, antes de chamarmos esse layout em uma página individual, definimos essa variável:

 {% set body_class = "home" %} {% extends "_layout.njk" %}

Digamos que nossa navegação foi estruturada como

 <nav class="site-nav"> <ul> <li class="nav-home"> <a href="/"> Home </a> ...

Agora podemos direcionar esse link e aplicar um estilo especial conforme necessário fazendo:

 body.home .nav-home a, body.services .nav-services a { /* continue matching classes for all pages... */ /* unique active state styling */ } 
Estilo de estado ativo na navegação
Estilizando links de navegação com uma classe ativa.

Ah e esses ícones? Esses são apenas arquivos .svg individuais que coloquei em uma pasta e incluí como

 {% include "../icons/cloud.svg" %}

E isso me permite estilizá-los como:

 svg { fill: white; }

Supondo que os elementos SVG dentro não tenham atributos de fill já neles.

Criação de conteúdo no Markdown

A página inicial do meu microsite tem uma grande quantidade de conteúdo. Eu certamente poderia escrever e manter isso no próprio HTML, mas às vezes é bom deixar esse tipo de coisa para o Markdown. O Markdown parece mais limpo de escrever e talvez um pouco mais fácil de ver quando há muitas cópias.

Isso é muito fácil em Projetos CodePen. Eu fiz um arquivo que termina em .md , que será automaticamente processado em HTML, então incluí-o no arquivo index.njk .

Markdown compilado em HTML em projetos CodePen
Arquivos em markdown são compilados em HTML em projetos CodePen.
 {% block content %} <main class="centered-text-column"> {% include "content/about.html" %} </main> {% endblock %}

Construindo componentes reais

Vamos considerar os componentes como módulos repetíveis que são passados ​​em dados para se criarem. Em frameworks como o Vue, você trabalharia com componentes de arquivo único que são pedaços isolados de HTML modelado, CSS com escopo e JavaScript específico do componente. Isso é super legal, mas nosso microsite não precisa de nada tão sofisticado.

Precisamos criar alguns “cards” baseados em um template simples, para que possamos construir coisas assim:

Componentes de estilo de cartão
Criando componentes repetíveis com modelos

Construir um componente repetível como o do Nunjucks envolve usar o que eles chamam de Macros. Macros são deliciosamente simples. Eles são como se o HTML tivesse funções !

 {% macro card(title, content) %} <div class="card"> <h2>{{ title }}</h2> <p>{{ content }}</p> </div> {% endmacro %}

Então você chama conforme necessário:

 {{ card('My Module', 'Lorem ipsum whatever.') }}

A ideia aqui é separar dados e marcação . Isso nos dá alguns benefícios bastante claros e tangíveis:

  1. Se precisarmos fazer uma alteração no HTML, podemos alterá-la na macro e ela será alterada em todos os lugares que usarem essa macro.
  2. Os dados não estão emaranhados na marcação
  3. Os dados podem vir de qualquer lugar! Codificamos os dados diretamente nas chamadas para as macros, como fizemos acima. Ou podemos referenciar alguns dados JSON e fazer um loop sobre eles. Tenho certeza de que você pode até imaginar uma configuração na qual esses dados JSON venham de uma espécie de CMS headless, processo de compilação, função serverless, cron job ou qualquer outra coisa.

Agora temos esses cartões repetíveis que combinam dados e marcação, exatamente o que precisamos:

Dados e marcação para o componente são mantidos separados
O HTML é controlado na macro, enquanto os dados podem vir de qualquer lugar

Faça quantos componentes quiser

Você pode pegar essa ideia e correr com ela. Por exemplo, imagine como o Bootstrap é essencialmente um monte de CSS que você segue padrões HTML para usar. Você pode transformar cada um desses padrões em uma macro e chamá-los conforme necessário, essencialmente componentizando a estrutura.

Você pode aninhar componentes se quiser, adotando uma espécie de filosofia de design atômico. O Nunjucks também oferece lógica, o que significa que você pode criar componentes condicionais e variações apenas passando dados diferentes.

No site simples que fiz, fiz uma macro diferente para a seção de ideias do site porque envolvia dados um pouco diferentes e um design de cartão um pouco diferente.

Componentes do cartão na seção Ideias
É possível criar quantos componentes você quiser

Um caso rápido contra sites estáticos

Eu poderia argumentar que a maioria dos sites se beneficia de uma arquitetura baseada em componentes, mas apenas alguns sites são apropriados por serem estáticos. Eu trabalho em muitos sites nos quais ter linguagens de back-end é apropriado e útil.

Um dos meus sites, CSS-Tricks, tem coisas como login de usuário com um sistema de permissões um tanto complexo: fóruns, comentários, eCommerce. Embora nenhuma dessas coisas interrompa totalmente a ideia de trabalhar estaticamente, muitas vezes fico feliz por ter um banco de dados e linguagens de back-end para trabalhar. Isso me ajuda a construir o que preciso e mantém as coisas sob o mesmo teto.

Vá em frente e abrace a vida estática!

Lembre-se de que um dos benefícios de construir da maneira que fizemos neste artigo é que o resultado final é apenas um monte de arquivos estáticos. Fácil de hospedar, rápido e seguro. No entanto, não tivemos que desistir de trabalhar de maneira amigável ao desenvolvedor. Este site será fácil de atualizar e adicionar no futuro.

  • O projeto final é um microsite chamado The Power of Serverless for Front-End Developers (https://thepowerofserverless.info/).
  • Hospedagem de arquivos estáticos, se você me perguntar, faz parte do movimento serverless.
  • Você pode ver todo o código (e até mesmo fazer uma cópia para você mesmo) diretamente no CodePen. Ele é construído, mantido e hospedado inteiramente no CodePen usando o CodePen Projects.
  • O CodePen Projects lida com todas as coisas do Nunjucks sobre as quais falamos aqui, e também coisas como processamento Sass e hospedagem de imagens, das quais aproveitei para o site. Você pode replicar o mesmo com, digamos, um processo de compilação baseado em Gulp ou Grunt localmente. Aqui está um projeto clichê como esse que você pode criar.