Construire le SSG que j'ai toujours voulu : un sandwich 11ty, Vite et JAM

Publié: 2022-03-10
Résumé rapide ↬ En janvier 2020, Ben Holmes a entrepris de faire ce que presque tous les développeurs Web font chaque année : reconstruire son site personnel. Dans cet article, il partage son histoire sur la façon dont il a entrepris de construire son propre pipeline de construction à partir de zéro absolu et a créé Slinkity.

Je ne sais pas pour vous, mais j'ai été submergé par tous les outils de développement Web que nous avons de nos jours. Que vous aimiez les modèles Markdown, HTML brut, React, Vue, Svelte, Pug, Handlebars, Vibranium, vous pouvez probablement le mélanger avec des données CMS et obtenir un joli cocktail de site statique.

Je ne vais pas vous dire quels outils de développement d'interface utilisateur utiliser, car ils sont tous excellents, en fonction des besoins de votre projet. Cet article vise à trouver le générateur de site statique parfait pour toute occasion ; quelque chose qui nous permet d'utiliser des modèles sans JS comme le démarquage pour commencer, et d'apporter des "îlots" d'interactivité pilotée par les composants selon les besoins.

Je distille la valeur d'une année d'apprentissages en un seul article ici. Non seulement allons-nous parler de code (aka duct-taping 11ty et Vite ensemble), mais nous allons également explorer pourquoi cette approche est si universelle aux problèmes jamstackiens. Nous aborderons :

  • Deux approches de la génération de sites statiques et pourquoi nous devrions combler l'écart ;
  • Où les langages de modèles comme Pug et Nunjucks s'avèrent toujours utiles ;
  • Quand des frameworks de composants comme React ou Svelte devraient entrer en jeu ;
  • Comment le nouveau monde de rechargement à chaud de Vite nous aide à apporter l'interactivité JS à notre HTML avec presque aucune configuration ;
  • Comment cela complète la cascade de données de 11ty, apportant des données CMS à n'importe quel framework de composants ou modèle HTML que vous pourriez souhaiter.

Alors sans plus tarder, voici mon histoire de scripts de construction terribles, de percées de bundler et de spaghetti-code-duct-tape qui (finalement) m'ont donné le SSG que j'ai toujours voulu : un sandwich 11ty, Vite et Jam appelé Slinkity !

Une grande fracture dans la génération de sites statiques

Avant de plonger, je veux discuter de ce que j'appellerai deux « camps » dans la génération de sites statiques.

Dans le premier camp, nous avons le "simple" générateur de site statique. Ces outils n'apportent pas d'ensembles JavaScript, d'applications d'une seule page et d'autres mots à la mode auxquels nous nous attendons. Ils ne font que clouer les principes fondamentaux de Jamstack : extrayez les données de n'importe quel blob JSON de CMS que vous préférez, et faites glisser ces données dans des modèles HTML simples + CSS. Des outils comme Jekyll, Hugo et 11ty dominent ce camp, vous permettant de transformer un répertoire de fichiers démarqués et liquides en un site Web entièrement fonctionnel. Avantages clés:

  • Courbe d'apprentissage peu profonde
    Si vous connaissez le HTML, vous êtes prêt à partir !
  • Temps de construction rapides
    Nous ne traitons rien de complexe, donc chaque route se construit en un clin d'œil.
  • Temps instantané d'interactivité
    Il n'y a pas (ou très peu) de JavaScript à analyser sur le client.

Maintenant dans le deuxième camp, nous avons le générateur de site statique "dynamique". Ceux-ci introduisent des frameworks de composants tels que React, Vue et Svelte pour apporter de l'interactivité à votre Jamstack. Celles-ci remplissent la même promesse fondamentale de combiner les données CMS avec les itinéraires de votre site au moment de la construction. Avantages clés:

  • Construit pour l'interactivité
    Besoin d'un carrousel d'images animées ? Formulaire en plusieurs étapes ? Ajoutez simplement une pépite de composants HTML, CSS et JS.
  • Gestion de l'état
    Quelque chose comme React Context des magasins Svelte permet un partage de données transparent entre les itinéraires. Par exemple, le panier de votre site e-commerce.

Il y a des avantages distincts à l'une ou l'autre approche. Mais que se passe-t-il si vous choisissez un SSG du premier camp comme Jekyll, pour réaliser seulement six mois après le début de votre projet que vous avez besoin d'une certaine interactivité avec les composants ? Ou vous choisissez quelque chose comme NextJS pour ces composants puissants, seulement pour lutter avec la courbe d'apprentissage de React, ou des Ko inutiles de JavaScript sur un article de blog statique ?

Peu de projets s'intègrent parfaitement dans un camp ou dans l'autre à mon avis. Ils existent sur un spectre, favorisant constamment de nouveaux ensembles de fonctionnalités à mesure que les besoins d'un projet évoluent. Alors comment trouver une solution qui nous permette de commencer avec les outils simples du premier camp, et d'ajouter progressivement les fonctionnalités du second quand on en a besoin ?

Eh bien, parcourons un peu mon parcours d'apprentissage.

Remarque : Si vous êtes déjà convaincu par les modèles statiques avec 11ty pour créer vos sites statiques, n'hésitez pas à passer à la procédure pas à pas du code juteux.

Plus après saut! Continuez à lire ci-dessous ↓

Passer des composants aux modèles et aux API Web

En janvier 2020, j'ai entrepris de faire ce que presque tous les développeurs Web font chaque année : reconstruire mon site personnel. Mais cette fois, ça allait être différent. Je me suis lancé le défi de créer un site les mains liées derrière le dos, sans framework ni build pipelines autorisés !

Ce n'était pas une tâche simple en tant que passionné de React. Mais la tête haute, j'ai entrepris de construire mon propre pipeline de construction à partir de zéro absolu. Il y a beaucoup de code mal écrit que je pourrais partager à partir de la v1 de mon site personnel… mais je vous laisserai cliquer sur ce README si vous êtes si courageux. Au lieu de cela, je veux me concentrer sur les plats à emporter de niveau supérieur que j'ai appris en me privant de mes plaisirs coupables JS.

Les modèles vont beaucoup plus loin que vous ne le pensez

Je suis venu à ce projet un junky de récupération de JavaScript. Il y a quelques besoins liés au site statique que j'aimais utiliser pour répondre à des frameworks basés sur des composants :

  1. Nous voulons décomposer mon site en composants d'interface utilisateur réutilisables pouvant accepter des objets JS en tant que paramètres (alias "accessoires").
  2. Nous devons récupérer des informations au moment de la construction pour accéder à un site de production.
  3. Nous devons générer un ensemble de routes d'URL à partir d'un répertoire de fichiers ou d'un gros objet JSON de contenu.

Liste tirée de cet article sur mon blog personnel.

Mais vous avez peut-être remarqué… aucun d'entre eux n'a vraiment besoin de JavaScript côté client. Les frameworks de composants comme React sont principalement conçus pour gérer les problèmes de gestion d'état, comme l'application Web Facebook inspirant React en premier lieu. Si vous décomposez simplement votre site en composants de petite taille ou en éléments de système de conception, des modèles comme Pug fonctionnent également très bien !

Prenez cette barre de navigation par exemple. Dans Pug, nous pouvons définir un "mixin" qui reçoit des données sous forme d'accessoires :

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

Ensuite, nous pouvons appliquer ce mixin n'importe où sur notre site.

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

Si nous "rendons" ce fichier avec quelques données, nous obtiendrons un beau index.html à servir à nos utilisateurs.

 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)

Bien sûr, cela ne donne pas de subtilités comme le CSS étendu pour vos mixins, ou le JavaScript avec état là où vous le souhaitez. Mais il a des avantages très puissants par rapport à quelque chose comme React :

  1. Nous n'avons pas besoin de groupeurs fantaisistes que nous ne comprenons pas.
    Nous venons d'écrire cet appel pug.render à la main, et nous avons déjà le premier itinéraire d'un site prêt à être déployé.
  2. Nous n'envoyons aucun code JavaScript à l'utilisateur final.
    Utiliser React signifie souvent envoyer un gros moteur d'exécution pour que les navigateurs des utilisateurs s'exécutent. En appelant une fonction comme pug.render au moment de la construction, nous gardons tout le JS de notre côté tout en envoyant un fichier .html propre à la fin.

C'est pourquoi je pense que les modèles sont une excellente "base" pour les sites statiques. Pourtant, être en mesure d'atteindre des frameworks de composants où nous en bénéficions vraiment serait bien. Plus sur cela plus tard.

Lecture recommandée : Comment créer de meilleurs modèles angulaires avec Pug par Zara Cooper

Vous n'avez pas besoin d'un cadre pour créer des applications à page unique

Pendant que j'y étais, je voulais aussi des transitions de page sexy sur mon site. Mais comment réussir quelque chose comme ça sans cadre ?

Fondu enchaîné avec transition de volet vertical
Fondu enchaîné avec transition de volet vertical. ( Grand aperçu )

Eh bien, nous ne pouvons pas faire cela si chaque page est son propre fichier .html . L'ensemble du navigateur se rafraîchit lorsque nous passons d'un fichier HTML à l'autre, nous ne pouvons donc pas avoir ce bel effet de fondu enchaîné (puisque nous afficherions brièvement les deux pages l'une au-dessus de l'autre).

Nous avons besoin d'un moyen de «récupérer» le HTML et le CSS pour l'endroit où nous naviguons et de l'animer en utilisant JavaScript. Cela ressemble à un travail pour les applications d'une seule page ! J'ai utilisé un simple mélange d'API de navigateur pour cela :

  1. Interceptez tous vos clics sur les liens à l'aide d'un écouteur d'événements.
  2. fetch API : Récupérez toutes les ressources de la page que vous souhaitez visiter et saisissez le bit que je veux animer : le contenu en dehors de la barre de navigation (que je veux rester immobile pendant l'animation).
  3. API d'animations Web : animez le nouveau contenu sous forme d'image clé.
  4. API history : modifiez la route affichée dans la barre d'URL de votre navigateur à l'aide window.history.pushState({}, 'new-route') . Sinon, on dirait que vous n'avez jamais quitté la page précédente !

Pour plus de clarté, voici une illustration visuelle de ce concept d'application à page unique utilisant une simple recherche et remplacement ( article source ):

Processus de routage étape par étape côté client : 1. Un hamburger moyennement rare est renvoyé, 2. Nous demandons un hamburger bien fait à l'aide de l'API de récupération, 3. Nous massons la réponse, 4. Nous retirons l'élément "patty" et l'appliquons à notre page actuelle.
Processus de routage étape par étape côté client : 1. Un hamburger moyennement rare est renvoyé, 2. Nous demandons un hamburger bien fait à l'aide de l'API de récupération, 3. Nous massons la réponse, 4. Nous retirons l'élément "patty" et l'appliquons à notre page actuelle. ( Grand aperçu )

Note : Vous pouvez également visiter le code source depuis mon site personnel.

Bien sûr, une association de React et al et de votre bibliothèque d'animation de choix peut le faire. Mais pour un cas d'utilisation aussi simple qu'une transition en fondu… les API Web sont assez puissantes en elles-mêmes. Et si vous voulez des transitions de page plus robustes sur des modèles statiques comme Pug ou du HTML brut, des bibliothèques comme Swup vous serviront bien.

Ce que 11ty a apporté à la table

Je me sentais plutôt bien avec mon petit SSG à ce stade. Bien sûr, il ne pouvait pas récupérer de données CMS au moment de la construction, et ne prenait pas en charge différentes mises en page par page ou par répertoire, et n'optimisait pas mes images, et n'avait pas de builds incrémentiels.

D'accord, j'aurais peut-être besoin d'aide.

Compte tenu de tous mes apprentissages de la v1, je pensais avoir gagné mon droit d'abandonner la règle "pas de pipelines de construction tiers" et d'utiliser les outils existants. Il s'avère que 11ty a un trésor de fonctionnalités dont j'ai besoin !

  • Récupération de données au moment de la construction à l'aide de fichiers .11ydata.js ;
  • Données globales disponibles pour tous mes modèles à partir d'un dossier _data ;
  • Rechargement à chaud pendant le développement à l'aide de browsersync ;
  • Prise en charge des transformations HTML sophistiquées ;
  • … et d'innombrables autres goodies.

Si vous avez essayé des SSG rudimentaires comme Jekyll ou Hugo, vous devriez avoir une assez bonne idée du fonctionnement de 11ty. Seule différence ? 11ty utilise JavaScript de bout en bout.

11ty prend en charge pratiquement toutes les bibliothèques de modèles, il était donc heureux de rendre toutes mes pages Pug en routes .html . Son option de chaînage de mise en page m'a également aidé avec la configuration de ma fausse application à page unique. J'avais juste besoin d'un seul script pour toutes mes routes et d'une mise en page "globale" pour importer ce 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?

Tant que ce main.js fait tout ce lien d'interception que nous avons exploré, nous avons des transitions de page !

Oh, et la cascade de données

Donc, 11ty m'a aidé à nettoyer tout mon code spaghetti de la v1. Mais cela a apporté un autre élément important : une API propre pour charger des données dans mes mises en page. C'est le pain et le beurre de l'approche Jamstack. Au lieu de récupérer les données dans le navigateur avec la manipulation JavaScript + DOM, vous pouvez :

  1. Récupérez les données au moment de la construction à l'aide de Node.
    Il peut s'agir d'un appel à une API externe, d'une importation JSON ou YAML locale, ou même du contenu d' autres itinéraires sur votre site (imaginez la mise à jour d'une table des matières chaque fois que de nouveaux itinéraires sont ajoutés).
  2. Insérez ces données dans vos itinéraires. Rappelez-vous cette fonction .render que nous avons écrite précédemment :
 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] })

… mais au lieu d'appeler pug.render avec nos données à chaque fois, nous laissons 11ty le faire en coulisses.

Bien sûr, je n'avais pas beaucoup de données pour mon site personnel. Mais c'était génial de créer un fichier .yaml pour tous mes projets personnels :

 # _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 ...

Et accédez à ces données dans n'importe quel modèle :

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

Venant du monde du "rendu côté client" avec create-react-app, ce fut une assez grosse révélation. Plus besoin d'envoyer de clés API ou de gros blobs JSON au navigateur.

J'ai également ajouté quelques goodies pour la récupération de JavaScript et des améliorations d'animation par rapport à la version 1 de mon site. Si vous êtes curieux, voici où en était mon README à ce stade.

J'étais heureux à ce stade mais il manquait quelque chose

Je suis allé étonnamment loin en abandonnant les composants basés sur JS et en adoptant des modèles (avec des transitions de page animées pour démarrer). Mais je sais que cela ne satisfera pas mes besoins éternellement. Vous vous souvenez de ce grand fossé avec lequel je nous ai lancé ? Eh bien, il y a clairement encore ce ravin entre ma configuration de construction (fermement dans le camp n ° 1) et le paradis de l'interactivité JS-ifiée (le Next, SvelteKit et plus du camp n ° 2). Dire que je veux ajouter:

  • un pop-up modal avec une bascule d'ouverture/fermeture,
  • un système de conception basé sur des composants comme Material UI, avec un style étendu,
  • un formulaire complexe en plusieurs étapes, peut-être piloté par une machine à états.

Si vous êtes un puriste JS, vous avez probablement des réponses sans framework à tous ces cas d'utilisation. Mais il y a une raison pour laquelle JQuery n'est plus la norme ! Il y a quelque chose d'intéressant à créer des composants HTML discrets et faciles à lire, des styles de portée et des éléments de variables "d'état" JavaScript. React, Vue, Svelte, etc. offrent tellement de subtilités pour le débogage et les tests que la manipulation directe du DOM ne peut pas tout à fait correspondre.

Voici donc ma question à un million de dollars :

Pouvons-nous utiliser des modèles HTML simples pour commencer et ajouter progressivement des composants React/Vue/Svelte là où nous le voulons ?

La réponse est oui . Essayons.

11ty + Vite : un match paradisiaque ️

Voici le rêve que j'imagine ici. Partout où je veux insérer quelque chose d'interactif, je veux laisser un petit drapeau dans mon modèle pour "mettre le composant X React ici". Cela pourrait être la syntaxe de shortcode prise en charge par 11ty :

 # 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' %}

Mais rappelez-vous, le 11ty monobloc évite (à dessein) : un moyen de regrouper tout votre JavaScript. Venant de la guilde OG du regroupement, votre cerveau passe probablement à la création de processus Webpack, Rollup ou Babel ici. Construisez un gros fichier de point d'entrée ole et produisez un beau code optimisé, n'est-ce pas ?

Eh bien oui, mais cela peut être assez compliqué. Si nous utilisons des composants React, par exemple, nous aurons probablement besoin de chargeurs pour JSX, d'un processus Babel sophistiqué pour tout transformer, d'un interpréteur pour les importations de modules SASS et CSS, de quelque chose pour aider au rechargement en direct, etc.

Si seulement il y avait un outil qui pouvait simplement voir nos fichiers .jsx et savoir exactement quoi en faire.

Entrez : Vite

Vite a été le sujet de conversation de la ville ces derniers temps. Il est censé être l'outil tout-en-un pour créer à peu près n'importe quoi en JavaScript. Voici un exemple à essayer chez vous. Créons un répertoire vide quelque part sur notre machine et installons quelques dépendances :

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

Maintenant, nous pouvons créer un fichier index.html pour servir de "point d'entrée" à notre application. Nous allons rester assez simple :

 <!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>

Le seul élément intéressant est que div id="root" au milieu. Ce sera la racine de notre composant React dans un instant !

Si vous le souhaitez, vous pouvez lancer le serveur Vite pour voir notre fichier HTML brut dans votre navigateur. Exécutez simplement vite (ou npx vite si la commande n'a pas été configurée dans votre terminal), et vous verrez cette sortie utile :

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

Tout comme Browsersync ou d'autres serveurs de développement populaires, le nom de chaque fichier .html correspond à une route sur notre serveur. Donc, si nous index.html en about.html , nous visiterions http://localhost:3000/about/ (oui, vous aurez besoin d'une barre oblique finale !)

Faisons maintenant quelque chose d'intéressant. Parallèlement à ce fichier index.html , ajoutez un composant React de base quelconque. Nous utiliserons ici useState de React pour démontrer l'interactivité :

 // 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> ) }

Maintenant, chargeons ce composant sur notre page. C'est tout ce que nous avons à ajouter à notre 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>

Ouais, c'est ça. Pas besoin de transformer nous-mêmes notre fichier .jsx en un fichier .js prêt pour le navigateur ! Partout où Vite voit une importation .jsx , il convertit automatiquement ce fichier en quelque chose que les navigateurs peuvent comprendre. Il n'y a même pas de dossier dist ou build lorsque vous travaillez dans le développement; Vite traite tout à la volée, avec un rechargement à chaud du module chaque fois que nous enregistrons nos modifications.

D'accord, nous avons donc un outil de construction incroyablement performant. Comment pouvons-nous apporter cela à nos modèles 11ty ?

Courir Vite aux côtés de 11ty

Avant de nous lancer dans les bonnes choses, discutons de l'exécution côte à côte de 11ty et de Vite. Allez-y et installez 11ty en tant que dépendance dev dans le même répertoire de projet de la dernière section :

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

Faisons maintenant une petite vérification avant le vol pour voir si le 11ty fonctionne. Pour éviter toute confusion, je vous propose :

  1. Supprimez ce fichier index.html de plus tôt;
  2. Déplacez ce TimesWeMispronouncedVite.jsx dans un nouveau répertoire. Dites, components/ ;
  3. Créez un dossier src pour notre site Web ;
  4. Ajoutez un modèle à ce répertoire src pour que 11ty le traite.

Par exemple, un fichier blog-post.md avec le contenu suivant :

 # Hello world! It's markdown here

La structure de votre projet devrait ressembler à ceci :

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

Maintenant, lancez 11ty depuis votre terminal comme ceci :

 npx eleventy --input=src

Si tout se passe bien, vous devriez voir une sortie de build comme celle-ci :

 _site/ blog-post/ index.html

_site est notre répertoire de sortie par défaut, et blog-post/index.html est notre fichier Markdown magnifiquement converti pour la navigation.

Normalement, nous exécuterions npx eleventy --serve pour lancer un serveur de développement et visiter cette page /blog-post . Mais nous utilisons Vite pour notre serveur de développement maintenant ! Le but ici est de :

  1. Demandez à onze de créer notre démarque, Pug, nunjucks, et plus encore dans le répertoire _site .
  2. Pointez Vite sur ce même répertoire _site afin qu'il puisse traiter les composants React, les importations de style sophistiqué et d'autres éléments que 11ty n'a pas détectés.

Donc, un processus de construction en deux étapes, avec 11ty remettant le Vite. Voici la commande CLI dont vous aurez besoin pour démarrer simultanément 11ty et Vite en mode « veille » :

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

Vous pouvez également exécuter ces commandes dans deux terminaux distincts pour faciliter le débogage.

Avec un peu de chance, vous devriez pouvoir visiter http://localhost:3000/blog-post/ (encore une fois, n'oubliez pas la barre oblique finale !) pour voir ce fichier Markdown traité.

Hydratation partielle avec des codes courts

Faisons un bref aperçu des shortcodes. Il est temps de revoir cette syntaxe de plus tôt :

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

Pour ceux qui ne connaissent pas les shortcodes : ils sont à peu près identiques à un appel de fonction, où la fonction renvoie une chaîne de code HTML à glisser dans votre page. L'"anatomie" de notre shortcode est :

  • {% … %}
    Wrapper indiquant le début et la fin du shortcode.
  • react
    Le nom de notre fonction shortcode que nous allons configurer dans un instant.
  • '/components/TimesWeMispronouncedVite.jsx'
    Le premier (et unique) argument de notre fonction shortcode. Vous pouvez avoir autant d'arguments que vous le souhaitez.

Câblons notre premier shortcode ! Ajoutez un fichier .eleventy.js à la base de votre projet et ajoutez cette entrée de configuration pour notre 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', } } }

Maintenant, pimentons notre blog-post.md avec notre nouveau shortcode. Collez ce contenu dans notre fichier 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' %}

Et si vous exécutez un rapide npx eleventy , vous devriez voir cette sortie dans votre répertoire _site sous /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>

Écrire notre shortcode de composant

Faisons maintenant quelque chose d'utile avec ce shortcode. Vous souvenez-vous de cette balise de script que nous avons écrite lors de l'essai de Vite ? Eh bien, nous pouvons faire la même chose dans notre shortcode ! Cette fois, nous allons utiliser l'argument componentPath pour générer l'importation, mais garder le reste à peu près le même :

 // .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', } } }

Maintenant, un appel à notre shortcode (ex. {% react '/components/TimesWeMispronouncedVite.jsx' %} ) devrait produire quelque chose comme ceci :

 <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>

En visitant notre serveur de développement en utilisant (npx eleventy --watch) & vite _site , nous devrions trouver un élément de compteur magnifiquement cliquable.

Alerte mot à la mode — hydratation partielle et architecture des îles

Nous venons de démontrer "l'architecture des îles" dans sa forme la plus simple. C'est l'idée que nos arborescences de composants interactifs n'ont pas à consommer l'intégralité du site Web. Au lieu de cela, nous pouvons créer des mini-arbres, ou des "îles", dans notre application en fonction de l'endroit où nous avons réellement besoin de cette interactivité. Vous avez une page de destination basique de liens sans aucun état à gérer ? Génial! Pas besoin de composants interactifs. Mais avez-vous un formulaire en plusieurs étapes qui pourrait bénéficier de la bibliothèque X React ? Aucun problème. Utilisez des techniques comme celle qui react au shortcode pour faire tourner une île Form.jsx .

Cela va de pair avec l'idée d'« hydratation partielle ». Vous avez probablement entendu le terme « hydratation » si vous travaillez avec des SSG à composants tels que NextJS ou Gatsby. Bref, c'est un moyen de :

  1. Rendez d'abord vos composants en HTML statique.
    Cela donne à l'utilisateur quelque chose à voir lorsqu'il visite votre site Web pour la première fois.
  2. « Hydratez » ce HTML avec de l'interactivité.
    C'est là que nous connectons nos crochets d'état et nos rendus pour, eh bien, faire en sorte que les clics sur les boutons déclenchent réellement quelque chose.

Ce coup de poing 1-2 rend les frameworks pilotés par JS viables pour les sites statiques. Tant que l'utilisateur a quelque chose à voir avant que votre JavaScript ne soit terminé, vous obtiendrez un score décent sur ces métriques phares.

Eh bien, jusqu'à ce que vous ne le fassiez pas. Il peut être coûteux d'« hydrater » un site Web entier, car vous aurez besoin d'un ensemble JavaScript prêt à traiter chaque élément DOM jusqu'au dernier . Mais notre technique de shortcode scrappy ne couvre pas toute la page ! Au lieu de cela, nous hydratons "partiellement" le contenu qui s'y trouve, en insérant des composants uniquement là où c'est nécessaire.

Ne vous inquiétez pas, il y a un plugin pour tout ça : Slinkity

Récapitulons ici ce que nous avons découvert :

  1. Vite est un bundler incroyablement performant qui peut traiter la plupart des types de fichiers ( jsx , vue et svelte pour n'en nommer que quelques-uns) sans configuration supplémentaire.
  2. Les shortcodes sont un moyen facile d'insérer des morceaux de HTML dans nos modèles, à la manière d'un composant.
  3. Nous pouvons utiliser des shortcodes pour rendre des bundles JS dynamiques et interactifs où nous voulons en utilisant une hydratation partielle.

Qu'en est-il des versions de production optimisées ? Chargement correct des styles de portée ? Heck, utiliser .jsx pour créer des pages entières ? Eh bien, j'ai regroupé tout cela (et bien plus encore !) dans un projet appelé Slinkity. Je suis ravi de voir l'accueil chaleureux de la communauté au projet, et j'aimerais que vous, cher lecteur, lui donniez un tour vous-même !

Essayez le guide de démarrage rapide

Astro est assez génial aussi

Les lecteurs qui ont les yeux rivés sur la technologie de pointe ont probablement déjà pensé à Astro au moins une fois. Et je ne peux pas vous en vouloir ! Il est construit avec un objectif assez similaire à l'esprit : commencez avec du HTML simple et insérez des composants avec état là où vous en avez besoin. Heck, ils vous permettront même de commencer à écrire des composants React dans des composants Vue ou Svelte dans des fichiers de modèle HTML ! C'est comme l'édition MDX Xtreme.

Il y a cependant un coût assez important à leur approche : vous devez réécrire votre application à partir de zéro. Cela signifie un nouveau format de modèle basé sur JSX (avec lequel vous n'êtes peut-être pas à l'aise), un tout nouveau pipeline de données auquel il manque quelques subtilités pour le moment et un bogue général lorsqu'ils résolvent les problèmes.

Mais faire tourner un cocktail 11ty + Vite avec un outil comme Slinkity ? Eh bien, si vous avez déjà un site 11ty, Vite devrait se mettre en place sans aucune réécriture, et les codes abrégés devraient couvrir bon nombre des mêmes cas d'utilisation que les fichiers .astro . J'avoue que c'est loin d'être parfait en ce moment. Mais bon, cela a été utile jusqu'à présent, et je pense que c'est une alternative assez solide si vous voulez éviter les réécritures à l'échelle du site !

Emballer

Cette expérience Slinkity a assez bien répondu à mes besoins jusqu'à présent (et à quelques-uns d'entre vous aussi !). N'hésitez pas à utiliser n'importe quelle pile qui fonctionne pour votre JAM. Je suis juste ravi de partager les résultats de mon année de débauche d'outils de construction, et je suis tellement excité de voir comment nous pouvons combler le grand fossé Jamstack.

Lectures complémentaires

Vous voulez plonger plus profondément dans l'hydratation partielle, ou l'ESM, ou les SSG en général ? Vérifiez ceux-ci :

  • Architecture des îles
    Ce billet de blog de Jason Format a vraiment lancé une discussion sur les «îlots» et «l'hydratation partielle» dans le développement Web. Il regorge de diagrammes utiles et de la philosophie derrière l'idée.
  • Simplifiez votre statique avec un générateur de site statique sur mesure
    Un autre article de SmashingMag qui vous guide à travers la création de créateurs de sites Web basés sur Node à partir de zéro. Cela a été une énorme inspiration pour moi !
  • Comment les modules ES ont redéfini le développement Web
    Un article personnel sur la façon dont les modules ES ont changé le jeu du développement Web. Cela plonge un peu plus dans le "hier et maintenant" de la syntaxe d'importation sur le Web.
  • Présentation des composants Web
    Une excellente présentation de ce que sont les composants Web, du fonctionnement du DOM fantôme et des endroits où les composants Web s'avèrent utiles. J'ai utilisé ce guide pour appliquer des composants personnalisés à mon propre framework !