Construindo o SSG que eu sempre quis: um sanduíche 11ty, Vite e JAM

Publicados: 2022-03-10
Resumo rápido ↬ Em janeiro de 2020, Ben Holmes decidiu fazer o que quase todo desenvolvedor web faz todos os anos: reconstruir seu site pessoal. Neste artigo, ele compartilha sua história de como começou a construir seu próprio pipeline de construção a partir do zero absoluto e criou o Slinkity.

Não sei quanto a você, mas tenho ficado impressionado com todas as ferramentas de desenvolvimento web que temos hoje em dia. Se você gosta de Markdown, HTML simples, React, Vue, Svelte, Pug templates, Handlebars, Vibranium - você provavelmente pode misturar com alguns dados de CMS e obter um bom coquetel de site estático.

Não vou dizer quais ferramentas de desenvolvimento de interface do usuário você deve usar porque todas são ótimas — dependendo das necessidades do seu projeto. Este post é sobre encontrar o gerador de site estático perfeito para qualquer ocasião; algo que nos permite usar templates sem JS como markdown para começar e trazer “ilhas” de interatividade orientada a componentes conforme necessário.

Estou destilando o valor de um ano de aprendizado em um único post aqui. Não apenas falaremos sobre código (também conhecido como fita adesiva 11ty e Vite juntos), mas também exploraremos por que essa abordagem é tão universal para problemas Jamstackianos. Abordaremos:

  • Duas abordagens para a geração de sites estáticos e por que devemos preencher a lacuna;
  • Onde linguagens de templates como Pug e Nunjucks ainda são úteis;
  • Quando estruturas de componentes como React ou Svelte devem entrar em ação;
  • Como o novo mundo de recarga a quente do Vite nos ajuda a trazer interatividade JS para nosso HTML com quase zero de configurações;
  • Como isso complementa a cascata de dados do 11ty, trazendo dados CMS para qualquer estrutura de componente ou modelo HTML que você desejar.

Então, sem mais delongas, aqui está minha história de scripts de compilação terríveis, avanços de bundler e fita adesiva de código espaguete que (eventualmente) me deram o SSG que eu sempre quis: um sanduíche de 11ty, Vite e Jam chamado Slinkity!

Uma grande divisão na geração de sites estáticos

Antes de mergulhar, quero discutir o que chamarei de dois “campos” na geração de sites estáticos.

No primeiro acampamento, temos o gerador de site estático “simples”. Essas ferramentas não trazem pacotes JavaScript, aplicativos de página única e quaisquer outras palavras-chave que esperamos. Eles apenas pregam os fundamentos do Jamstack: extraia dados de qualquer blob JSON de CMS que você preferir e deslize esses dados em modelos HTML simples + CSS. Ferramentas como Jekyll, Hugo e 11ty dominam este campo, permitindo que você transforme um diretório de markdown e arquivos líquidos em um site totalmente funcional. Principais benefícios:

  • Curva de aprendizado rasa
    Se você sabe HTML, você está pronto para ir!
  • Tempos de construção rápidos
    Não estamos processando nada complexo, então cada rota é construída em um piscar de olhos.
  • Tempo instantâneo para interativo
    Não há (ou muito pouco) JavaScript para analisar no cliente.

Agora, no segundo campo, temos o gerador de site estático “dinâmico”. Eles introduzem estruturas de componentes como React, Vue e Svelte para trazer interatividade ao seu Jamstack. Eles cumprem a mesma promessa principal de combinar dados do CMS com as rotas do seu site no momento da construção. Principais benefícios:

  • Construído para interatividade
    Precisa de um carrossel de imagens animadas? Formulário de várias etapas? Basta adicionar uma pepita de HTML, CSS e JS.
  • Gerenciamento de estado
    Algo como as lojas React Context of Svelte permitem o compartilhamento contínuo de dados entre rotas. Por exemplo, o carrinho em seu site de comércio eletrônico.

Existem prós distintos para qualquer abordagem. Mas e se você escolher um SSG do primeiro campo como Jekyll, apenas para perceber seis meses em seu projeto que você precisa de alguma interatividade de componentes? Ou você escolhe algo como NextJS para esses componentes poderosos, apenas para lutar com a curva de aprendizado do React, ou KB desnecessários de JavaScript em um post estático no blog?

Poucos projetos se encaixam perfeitamente em um campo ou outro, na minha opinião. Eles existem em um espectro, favorecendo constantemente novos conjuntos de recursos à medida que as necessidades de um projeto evoluem. Então, como encontramos uma solução que nos permite começar com as ferramentas simples do primeiro campo e adicionar gradualmente recursos do segundo quando precisamos deles?

Bem, vamos caminhar um pouco pela minha jornada de aprendizado.

Nota: Se você já está vendendo modelos estáticos com 11ty para construir seus sites estáticos, sinta-se à vontade para pular para o passo a passo do código suculento.

Mais depois do salto! Continue lendo abaixo ↓

Indo de componentes para modelos e APIs da Web

Em janeiro de 2020, decidi fazer o que quase todo desenvolvedor da Web faz todos os anos: reconstruir meu site pessoal. Mas desta vez ia ser diferente. Eu me desafiei a construir um site com as mãos amarradas nas costas, sem frameworks ou pipelines de construção permitidos!

Esta não foi uma tarefa simples como um devoto do React. Mas com a cabeça erguida, comecei a construir meu próprio pipeline de construção a partir do zero absoluto. Há muito código mal escrito que eu poderia compartilhar da v1 do meu site pessoal… mas vou deixar você clicar neste README se for corajoso. Em vez disso, quero me concentrar nas lições de nível superior que aprendi me privando de meus prazeres culpados de JS.

Os modelos vão muito além do que você imagina

Eu vim para este projeto um viciado em JavaScript em recuperação. Existem algumas necessidades relacionadas a sites estáticos que eu adorava usar estruturas baseadas em componentes para preencher:

  1. Queremos dividir meu site em componentes de interface do usuário reutilizáveis ​​que podem aceitar objetos JS como parâmetros (também conhecidos como “props”).
  2. Precisamos buscar algumas informações em tempo de construção para colocar em um site de produção.
  3. Precisamos gerar várias rotas de URL a partir de um diretório de arquivos ou de um objeto JSON gordo de conteúdo.

Lista retirada deste post no meu blog pessoal.

Mas você deve ter notado… nenhum deles realmente precisa de JavaScript do lado do cliente. Estruturas de componentes como o React são criadas principalmente para lidar com questões de gerenciamento de estado, como o aplicativo da web do Facebook que inspirou o React em primeiro lugar. Se você está apenas dividindo seu site em componentes pequenos ou elementos do sistema de design, modelos como o Pug também funcionam muito bem!

Veja esta barra de navegação, por exemplo. No Pug, podemos definir um “mixin” que recebe dados como props:

 // nav-mixins.pug mixin NavBar(links) // pug's version of a for loop each link in links a(href=link.href) link.text

Então, podemos aplicar esse mixin em qualquer lugar do nosso site.

 // index.pug // kinda like an ESM "import" include nav-mixins.pug html body +NavBar(navLinksPassedByJS) main h1 Welcome to my pug playground

Se “renderizarmos” este arquivo com alguns dados, obteremos um belo index.html para servir aos nossos usuários.

 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] }) // use the NodeJS filesystem helpers to write a file to our build await writeFile('build/index.html', html)

Claro, isso não oferece detalhes como CSS com escopo para seus mixins ou JavaScript com estado onde você quiser. Mas tem alguns benefícios muito poderosos sobre algo como React:

  1. Não precisamos de empacotadores sofisticados que não entendemos.
    Acabamos de escrever essa chamada pug.render manualmente e já temos a primeira rota de um site pronta para implantação.
  2. Não enviamos nenhum JavaScript para o usuário final.
    Usar o React geralmente significa enviar um tempo de execução grande e velho para os navegadores das pessoas serem executados. Ao chamar uma função como pug.render em tempo de compilação, mantemos todo o JS do nosso lado enquanto enviamos um arquivo .html limpo no final.

É por isso que acho que os templates são uma ótima “base” para sites estáticos. Ainda assim, ser capaz de alcançar frameworks de componentes onde realmente nos beneficiamos deles seria bom. Mais sobre isso mais tarde.

Leitura recomendada : Como criar modelos angulares melhores com o Pug por Zara Cooper

Você não precisa de uma estrutura para criar aplicativos de página única

Enquanto eu estava nisso, eu também queria algumas transições de página sexy no meu site. Mas como podemos fazer algo assim sem uma estrutura?

Crossfade com transição de limpeza vertical
Crossfade com transição de limpeza vertical. (Visualização grande)

Bem, não podemos fazer isso se cada página for seu próprio arquivo .html . Todo o navegador é atualizado quando pulamos de um arquivo HTML para outro, então não podemos ter aquele bom efeito de cross-fade (já que mostraríamos brevemente as duas páginas uma sobre a outra).

Precisamos de uma maneira de “buscar” o HTML e o CSS para onde quer que estejamos navegando e animá-lo usando JavaScript. Isso soa como um trabalho para aplicativos de página única! Eu usei um medley de API de navegador simples para isso:

  1. Intercepte todos os seus cliques no link usando um ouvinte de eventos.
  2. fetch API : Busque todos os recursos para qualquer página que você queira visitar, e pegue o bit que eu quero animar em exibição: o conteúdo fora da barra de navegação (que eu quero que permaneça estacionário durante a animação).
  3. API de animações da web : Animar o novo conteúdo para exibição como um quadro-chave.
  4. API history : altere a rota exibida na barra de URL do navegador usando window.history.pushState({}, 'new-route') . Caso contrário, parece que você nunca saiu da página anterior!

Para maior clareza, aqui está uma ilustração visual desse conceito de aplicativo de página única usando um simples localizar e substituir ( artigo de origem ):

Processo de roteamento passo a passo do lado do cliente: 1. Hambúrguer mal passado é retornado, 2. Solicitamos um hambúrguer bem feito usando a API de busca, 3. Massageamos a resposta, 4. Retiramos o elemento 'patty' e o aplicamos para nossa página atual.
Processo de roteamento passo a passo do lado do cliente: 1. Hambúrguer mal passado é retornado, 2. Solicitamos um hambúrguer bem feito usando a API de busca, 3. Massageamos a resposta, 4. Retiramos o elemento 'patty' e o aplicamos para nossa página atual. (Visualização grande)

Nota : Você também pode visitar o código fonte do meu site pessoal.

Claro, alguns pares de React et al e sua biblioteca de animação de escolha podem fazer isso. Mas para um caso de uso tão simples quanto uma transição de fade… as APIs da web são muito poderosas por conta própria. E se você quiser transições de página mais robustas em modelos estáticos como Pug ou HTML simples, bibliotecas como Swup irão atendê-lo bem.

O que 11 anos trouxe para a mesa

Eu estava me sentindo muito bem com meu pequeno SSG neste momento. Claro que não poderia buscar nenhum dado do CMS em tempo de compilação, e não suportava layouts diferentes por página ou por diretório, e não otimizava minhas imagens e não tinha compilações incrementais.

Ok, talvez eu precise de ajuda.

Dado todos os meus aprendizados da v1, pensei que ganhei meu direito de abandonar a regra “sem pipelines de construção de terceiros” e alcançar as ferramentas existentes. Acontece que o 11ty tem um tesouro de recursos que eu preciso!

  • Busca de dados em tempo de construção usando arquivos .11ydata.js ;
  • Dados globais disponíveis para todos os meus templates de uma pasta _data ;
  • Hot recarregamento durante o desenvolvimento usando browsersync;
  • Suporte para transformações HTML sofisticadas;
  • … e inúmeras outras guloseimas.

Se você já experimentou SSGs básicos como Jekyll ou Hugo, você deve ter uma boa ideia de como o 11ty funciona. Única diferença? 11ty usa JavaScript completamente.

O 11ty suporta basicamente todas as bibliotecas de templates existentes, então ficou feliz em renderizar todas as minhas páginas Pug para rotas .html . Sua opção de encadeamento de layout também ajudou na configuração do meu aplicativo de página única falsa. Eu só precisava de um único script para todas as minhas rotas e um layout “global” para importar esse script:

 // _includes/base-layout.html <html> <body> <!--load every page's content between some body tags--> {{ content }} <!--and apply the script tag just below this--> <script src="main.js"></script> </body> </html> // random-blog-post.pug --- layout: base-layout --- article h2 Welcome to my blog p Have you heard the story of Darth Plagueis the Wise?

Contanto que o main.js faça toda a interceptação de links que exploramos, temos transições de página!

Ah, e a cascata de dados

Então, o 11ty ajudou a limpar todo o meu código de espaguete da v1. Mas trouxe outra peça importante: uma API limpa para carregar dados em meus layouts. Este é o pão com manteiga da abordagem Jamstack. Em vez de buscar dados no navegador com manipulação JavaScript + DOM, você pode:

  1. Busque dados em tempo de compilação usando Node.
    Isso pode ser uma chamada para alguma API externa, uma importação local de JSON ou YAML ou até mesmo o conteúdo de outras rotas em seu site (imagine atualizar um índice sempre que novas rotas forem adicionadas ).
  2. Encaixe esses dados em suas rotas. Lembre-se da função .render que escrevemos anteriormente:
 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] })

…mas em vez de chamar pug.render com nossos dados todas as vezes, deixamos o 11ty fazer isso nos bastidores.

Claro, eu não tinha muitos dados para o meu site pessoal. Mas foi ótimo criar um arquivo .yaml para todos os meus projetos pessoais:

 # _data/works.yaml - title: Bits of Good Homepage hash: bog-homepage links: - href: https://bitsofgood.org text: Explore the live site - href: https://github.com/GTBitsOfGood/bog-web text: Scour the Svelt-ified codebase timeframe: May 2019 - present tags: - JAMstack - SvelteJS - title: Dolphin Audio Visualizer ...

E acesse esses dados em qualquer modelo:

 // home.pug .project-carousel each work in works h3 #{title} p #{timeframe} each tag in tags ...

Vindo do mundo da “renderização do lado do cliente” com create-react-app, essa foi uma grande revelação. Chega de enviar chaves de API ou grandes blobs JSON para o navegador.

Também adicionei algumas novidades para busca de JavaScript e melhorias de animação em relação à versão 1 do meu site. Se você está curioso, aqui é onde meu README estava neste momento.

Eu estava feliz neste momento, mas algo estava faltando

Fui surpreendentemente longe abandonando componentes baseados em JS e adotando modelos (com transições de página animadas para inicializar). Mas eu sei que isso não vai satisfazer minhas necessidades para sempre. Lembra daquela grande divisão com a qual nos dei o pontapé inicial? Bem, claramente ainda há aquela ravina entre minha configuração de construção (firmemente no acampamento nº 1) e o refúgio da interatividade JS (o Next, SvelteKit e mais do acampamento nº 2). Digamos que eu queira adicionar:

  • um modal pop-up com alternância de abrir/fechar,
  • um sistema de design baseado em componentes como Material UI, completo com estilo com escopo,
  • uma forma complexa de várias etapas, talvez acionada por uma máquina de estado.

Se você é um purista de JS simples, provavelmente tem respostas sem framework para todos esses casos de uso. Mas há uma razão para JQuery não ser mais a norma! Há algo atraente na criação de componentes discretos e fáceis de ler de HTML, estilos com escopo e partes de variáveis ​​de “estado” JavaScript. React, Vue, Svelte, etc. oferecem tantas sutilezas para depuração e teste que a manipulação direta do DOM não consegue igualar.

Então aqui está minha pergunta de um milhão de dólares:

Podemos usar templates HTML diretos para começar e gradualmente adicionar componentes React/Vue/Svelte onde queremos?

A resposta é sim . Vamos tentar.

11ty + Vite: uma combinação feita no céu ️

Aqui está o sonho que estou imaginando aqui. Onde quer que eu queira inserir algo interativo, quero deixar um pequeno sinalizador no meu modelo para “colocar o componente X React aqui”. Esta pode ser a sintaxe do shortcode que o 11ty suporta:

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react './components/FancyLiveDemo.jsx' %}

Mas lembre-se, o 11ty de uma peça (propositalmente) evita: uma maneira de agrupar todo o seu JavaScript. Vindo da guilda OG de agregação, seu cérebro provavelmente salta para a construção de processos Webpack, Rollup ou Babel aqui. Construa um arquivo grande de ponto de entrada e produza um belo código otimizado, certo?

Bem, sim, mas isso pode envolver bastante. Se estivermos usando componentes React, por exemplo, provavelmente precisaremos de alguns carregadores para JSX, um processo Babel sofisticado para transformar tudo, um interpretador para importação de módulos SASS e CSS, algo para ajudar no recarregamento ao vivo e assim por diante.

Se ao menos houvesse uma ferramenta que pudesse ver nossos arquivos .jsx e saber exatamente o que fazer com eles.

Digite: Vite

Vite tem sido o assunto da cidade ultimamente. Ele deve ser a ferramenta tudo-em-um para construir praticamente qualquer coisa em JavaScript. Aqui está um exemplo para você tentar em casa. Vamos criar um diretório vazio em algum lugar da nossa máquina e instalar algumas dependências:

 npm init -y # Make a new package.json with defaults set npm i vite react react-dom # Grab Vite + some dependencies to use React

Agora, podemos criar um arquivo index.html para servir como “ponto de entrada” do nosso aplicativo. Vamos mantê-lo bem simples:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> </body> </html>

A única parte interessante é que div id="root" no meio. Esta será a raiz do nosso componente React em um momento!

Se desejar, você pode iniciar o servidor Vite para ver nosso arquivo HTML simples em seu navegador. Basta executar vite (ou npx vite se o comando não tiver sido configurado em seu terminal) e você verá esta saída útil:

 vite vX.XX dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in Xms.

Assim como o Browsersync ou outros servidores dev populares, o nome de cada arquivo .html corresponde a uma rota em nosso servidor. Portanto, se renomeássemos index.html para about.html , visitaríamos http://localhost:3000/about/ (sim, você precisará de uma barra final!)

Agora vamos fazer algo interessante. Juntamente com esse arquivo index.html , adicione um componente React básico de algum tipo. Usaremos o useState do React aqui para demonstrar a interatividade:

 // TimesWeMispronouncedVite.jsx import React from 'react' export default function TimesWeMispronouncedVite() { const [count, setCount] = React.useState(0) return ( <div> <p>I've said Vite wrong {count} times today</p> <button onClick={() => setCount(count + 1)}>Add one</button> </div> ) }

Agora, vamos carregar esse componente em nossa página. Isso é tudo o que temos para adicionar ao nosso index.html :

 <!DOCTYPE html> ... <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> <!--Don't forget type="module"! This lets us use ES import syntax in the browser--> <script type="module"> // path to our component. Note we still use .jsx here! import Component from './TimesWeMispronouncedVite.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('root'); ReactDOM.render(React.createElement(Component), componentRoot); </script> </body> </html>

Sim, é isso. Não há necessidade de transformar nosso arquivo .jsx em um arquivo .js pronto para navegador! Onde quer que o Vite veja uma importação .jsx , ele converterá automaticamente esse arquivo para algo que os navegadores possam entender. Não há nem mesmo uma pasta dist ou build ao trabalhar em desenvolvimento; O Vite processa tudo dinamicamente — completo com a recarga do módulo a quente toda vez que salvamos nossas alterações.

Ok, então temos uma ferramenta de construção incrivelmente capaz. Como podemos trazer isso para nossos modelos 11ty?

Executando Vite ao lado de 11ty

Antes de entrarmos nas coisas boas, vamos discutir a execução do 11ty e do Vite lado a lado. Vá em frente e instale o 11ty como uma dependência dev no mesmo diretório do projeto da última seção:

 npm i -D @11ty/eleventy # yes, it really is 11ty twice

Agora vamos fazer uma pequena verificação pré-voo para ver se o 11ty está funcionando. Para evitar qualquer confusão, sugiro que você:

  1. Exclua esse arquivo index.html anterior;
  2. Mova esse TimesWeMispronouncedVite.jsx para dentro de um novo diretório. Digamos, components/ ;
  3. Crie uma pasta src para o nosso site morar;
  4. Adicione um modelo a esse diretório src para o 11ty processar.

Por exemplo, um arquivo blog-post.md com o seguinte conteúdo:

 # Hello world! It's markdown here

A estrutura do seu projeto deve ficar assim:

 src/ blog-post.md components/ TimesWeMispronouncedVite.jsx

Agora, execute 11ty do seu terminal assim:

 npx eleventy --input=src

Se tudo correr bem, você deverá ver uma saída de compilação como esta:

 _site/ blog-post/ index.html

Onde _site é nosso diretório de saída padrão e blog-post/index.html é nosso arquivo markdown lindamente convertido para navegação.

Normalmente, executaríamos npx eleventy --serve para ativar um servidor dev e visitar a página /blog-post . Mas estamos usando o Vite para nosso servidor de desenvolvimento agora! O objetivo aqui é:

  1. Faça com que onze construam nosso markdown, Pug, nunjucks e muito mais no diretório _site .
  2. Aponte o Vite no mesmo diretório _site para que ele possa processar os componentes React, importações de estilo sofisticado e outras coisas que o 11ty não captou.

Portanto, um processo de construção de duas etapas, com 11ty entregando o Vite. Aqui está o comando CLI que você precisará para iniciar o 11ty e o Vite no modo “watch” simultaneamente:

 (npx eleventy --input=src --watch) & npx vite _site

Você também pode executar esses comandos em dois terminais separados para facilitar a depuração.

Com alguma sorte, você poderá visitar http://localhost:3000/blog-post/ (novamente, não se esqueça da barra final!) para ver o arquivo Markdown processado.

Hidratação parcial com códigos de acesso

Vamos fazer um breve resumo sobre códigos de acesso. Hora de revisitar essa sintaxe de antes:

 {% react '/components/TimesWeMispronouncedVite.jsx' %}

Para aqueles que não estão familiarizados com códigos de acesso: eles são quase o mesmo que uma chamada de função, onde a função retorna uma string de HTML para deslizar em sua página. A “anatomia” do nosso shortcode é:

  • {% … %}
    Wrapper que denota o início e o fim do shortcode.
  • react
    O nome da nossa função shortcode vamos configurar em breve.
  • '/components/TimesWeMispronouncedVite.jsx'
    O primeiro (e único) argumento para nossa função shortcode. Você pode ter quantos argumentos quiser.

Vamos conectar nosso primeiro código de acesso! Adicione um arquivo .eleventy.js à base do seu projeto e adicione esta entrada de configuração para nosso shortcode de react :

 // .eleventy.js, at the base of the project module.exports = function(eleventyConfig) { eleventyConfig.addShortcode('react', function(componentPath) { // return any valid HTML to insert return `<div>This is where we'll import ${componentPath}</div>` }) return { dir: { // so we don't have to write `--input=src` in our terminal every time! input: 'src', } } }

Agora, vamos incrementar nosso blog-post.md com nosso novo shortcode. Cole este conteúdo em nosso arquivo markdown:

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react '/components/TimesWeMispronouncedVite.jsx' %}

E se você executar um rápido npx eleventy , deverá ver esta saída em seu diretório _site em /blog-post/index.html :

 <h1>Super interesting programming tutorial</h1> <p>Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example!</p> <div>This is where we'll import /components/TimesWeMispronouncedVite.jsx</div>

Escrevendo nosso código de acesso de componente

Agora vamos fazer algo útil com esse shortcode. Lembra daquela tag de script que escrevemos enquanto testávamos o Vite? Bem, podemos fazer a mesma coisa em nosso shortcode! Desta vez, usaremos o argumento componentPath para gerar a importação, mas manteremos o resto praticamente o mesmo:

 // .eleventy.js module.exports = function(eleventyConfig) { let idCounter = 0; // copy all our /components to the output directory // so Vite can find them. Very important step! eleventyConfig.addPassthroughCopy('components') eleventyConfig.addShortcode('react', function (componentPath) { // we'll use idCounter to generate unique IDs for each "root" div // this lets us use multiple components / shortcodes on the same page idCounter += 1; const componentRootId = `component-root-${idCounter}` return ` <div></div> <script type="module"> // use JSON.stringify to // 1) wrap our componentPath in quotes // 2) strip any invalid characters. Probably a non-issue, but good to be cautious! import Component from ${JSON.stringify(componentPath)}; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('${componentRootId}'); ReactDOM.render(React.createElement(Component), componentRoot); </script> ` }) eleventyConfig.on('beforeBuild', function () { // reset the counter for each new build // otherwise, it'll count up higher and higher on every live reload idCounter = 0; }) return { dir: { input: 'src', } } }

Agora, uma chamada para nosso código de acesso (ex. {% react '/components/TimesWeMispronouncedVite.jsx' %} ) deve gerar algo assim:

 <div></div> <script type="module"> import Component from './components/FancyLiveDemo.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('component-root-1'); ReactDOM.render(React.createElement(Component), componentRoot); </script>

Visitando nosso servidor de desenvolvimento usando (npx eleventy --watch) & vite _site , devemos encontrar um elemento contador lindamente clicável.

Alerta de Buzzword - Hidratação Parcial e Arquitetura de Ilhas

Acabamos de demonstrar a “arquitetura das ilhas” em sua forma mais simples. Essa é a ideia de que nossas árvores de componentes interativos não precisam consumir todo o site. Em vez disso, podemos criar mini-árvores, ou “ilhas”, em todo o nosso aplicativo, dependendo de onde realmente precisamos dessa interatividade. Tem uma landing page básica de links sem nenhum estado para gerenciar? Excelente! Não há necessidade de componentes interativos. Mas você tem um formulário de várias etapas que poderia se beneficiar da biblioteca X React? Sem problemas. Use técnicas como essa de shortcode de react para criar uma ilha Form.jsx .

Isso anda de mãos dadas com a ideia de “hidratação parcial”. Você provavelmente já ouviu o termo “hidratação” se trabalha com SSGs de componentes como NextJS ou Gatsby. Resumindo, é uma forma de:

  1. Renderize seus componentes para HTML estático primeiro.
    Isso dá ao usuário algo para ver quando visita seu site pela primeira vez.
  2. “Hidrate” este HTML com interatividade.
    É aqui que conectamos nossos ganchos e renderizadores de estado para, bem, fazer com que cliques de botão realmente acionem algo.

Esse soco 1-2 torna os frameworks orientados por JS viáveis ​​para sites estáticos. Contanto que o usuário tenha algo para visualizar antes que seu JavaScript termine de analisar, você obterá uma pontuação decente nessas métricas de farol.

Bem, até que você não o faça. Pode ser caro “hidratar” um site inteiro, pois você precisará de um pacote JavaScript pronto para processar cada elemento DOM . Mas nossa técnica de shortcode desconexo não cobre a página inteira! Em vez disso, hidratamos “parcialmente” o conteúdo que está lá, inserindo componentes apenas quando necessário.

Não se preocupe, existe um plugin para tudo isso: Slinkity

Vamos recapitular o que descobrimos aqui:

  1. Vite é um empacotador incrivelmente capaz que pode processar a maioria dos tipos de arquivo ( jsx , vue e svelte para citar alguns) sem configuração extra.
  2. Os códigos de acesso são uma maneira fácil de inserir pedaços de HTML em nossos modelos, estilo componente.
  3. Podemos usar códigos de acesso para renderizar pacotes JS dinâmicos e interativos onde quisermos usando hidratação parcial.

Então, e as compilações de produção otimizadas? Carregar estilos com escopo corretamente? Heck, usando .jsx para criar páginas inteiras? Bem, eu juntei tudo isso (e muito mais!) em um projeto chamado Slinkity. Estou animado para ver a recepção calorosa da comunidade ao projeto, e eu adoraria que você, caro leitor, desse uma chance!

Experimente o guia de início rápido

Astro é muito bom também

Leitores com os olhos em tecnologia de ponta provavelmente já pensaram em Astro pelo menos uma vez até agora. E eu não posso te culpar! Ele foi criado com um objetivo bastante semelhante em mente: comece com HTML simples e insira componentes com estado sempre que precisar deles. Caramba, eles até permitem que você comece a escrever componentes React dentro de componentes Vue ou Svelte dentro de arquivos de modelo HTML! É como a edição MDX Xtreme.

No entanto, há um custo bastante importante para a abordagem deles: você precisa reescrever seu aplicativo do zero. Isso significa um novo formato de modelo baseado em JSX (com o qual você pode não se sentir confortável), um pipeline de dados totalmente novo que está faltando algumas sutilezas no momento e bugs gerais à medida que eles resolvem os problemas.

Mas criar um coquetel 11ty + Vite com uma ferramenta como o Slinkity? Bem, se você já tem um site 11ty, o Vite deve se encaixar sem nenhuma reescrita, e os shortcodes devem cobrir muitos dos mesmos casos de uso que os arquivos .astro . Admito que está longe de ser perfeito agora. Mas ei, tem sido útil até agora, e acho que é uma alternativa bastante forte se você quiser evitar reescritas em todo o site!

Empacotando

Este experimento do Slinkity atendeu muito bem às minhas necessidades até agora (e alguns de vocês também!). Sinta-se à vontade para usar qualquer pilha que funcione para o seu JAM. Estou animado para compartilhar os resultados do meu ano de devassidão de ferramentas de construção e estou muito animado para ver como podemos superar a grande divisão do Jamstack.

Leitura adicional

Quer mergulhar mais fundo na hidratação parcial, ou ESM, ou SSGs em geral? Confira estes:

  • Arquitetura das Ilhas
    Esta postagem no blog do Jason Format realmente deu início a uma discussão sobre “ilhas” e “hidratação parcial” no desenvolvimento web. Está repleto de diagramas úteis e da filosofia por trás da ideia.
  • Simplifique sua estática com um gerador de site estático personalizado
    Outro artigo do SmashingMag que o orienta na criação de construtores de sites baseados em Node a partir do zero. Foi uma grande inspiração para mim!
  • Como os Módulos ES redefiniram o desenvolvimento web
    Um post pessoal sobre como os Módulos ES mudaram o jogo de desenvolvimento web. Isso mergulha um pouco mais no “então e agora” da sintaxe de importação na web.
  • Uma introdução aos componentes da web
    Um excelente passo a passo sobre o que são componentes da Web, como o shadow DOM funciona e onde os componentes da Web são úteis. Usei este guia para aplicar componentes personalizados ao meu próprio framework!