Simplifiez votre pile avec un générateur de site statique sur mesure
Publié: 2022-03-10Avec l'avènement du mouvement Jamstack, les sites à service statique sont redevenus à la mode. La plupart des développeurs qui proposent du HTML statique ne créent pas de HTML natif. Pour avoir une solide expérience de développeur, nous nous tournons souvent vers des outils appelés Static Site Generators (SSG).
Ces outils sont dotés de nombreuses fonctionnalités qui rendent agréable la création de sites statiques à grande échelle. Qu'ils fournissent de simples crochets vers des API tierces comme les sources de données de Gatsby ou fournissent une configuration approfondie comme l'énorme collection de moteurs de modèles de 11ty, il y a quelque chose pour tout le monde dans la génération de sites statiques.
Parce que ces outils sont conçus pour divers cas d'utilisation, ils doivent avoir beaucoup de fonctionnalités. Ces fonctionnalités les rendent puissants. Ils les rendent également assez complexes et opaques pour les nouveaux développeurs. Dans cet article, nous réduirons le SSG à ses composants de base et créerons le nôtre.
Qu'est-ce qu'un générateur de site statique ?
À la base, un générateur de site statique est un programme qui effectue une série de transformations sur un groupe de fichiers pour les convertir en actifs statiques, tels que HTML. Le type de fichiers qu'il peut accepter, la façon dont il les transforme et les types de fichiers qui sortent différencient les SSG.
Jekyll, un SSG précoce et toujours populaire, utilise Ruby pour traiter les modèles Liquid et les fichiers de contenu Markdown en HTML.
Gatsby utilise React et JSX pour transformer les composants et le contenu en HTML. Il va ensuite plus loin et crée une application d'une seule page qui peut être servie de manière statique.
11ty rend le HTML à partir de moteurs de modèles tels que Liquid, Handlebars, Nunjucks ou les littéraux de modèle JavaScript.
Chacune de ces plateformes possède des fonctionnalités supplémentaires pour nous faciliter la vie. Ils fournissent des thèmes, créent des pipelines, une architecture de plug-in, etc. Avec chaque fonctionnalité supplémentaire vient plus de complexité, plus de magie et plus de dépendances. Ce sont des fonctionnalités importantes, bien sûr, mais tous les projets n'en ont pas besoin.
Entre ces trois SSG différents, nous pouvons voir un autre thème commun : données + modèles = site final. Cela semble être la fonctionnalité de base des sites statiques générateurs. C'est sur cette fonctionnalité que nous baserons notre SSG.
À la base, un générateur de site statique est un programme qui effectue une série de transformations sur un groupe de fichiers pour les convertir en actifs statiques, tels que HTML.
"
La pile technologique de notre nouveau générateur de site statique : Handlebars, Sanity.io et Netlify
Pour créer notre SSG, nous aurons besoin d'un moteur de modèle, d'une source de données et d'un hôte capable d'exécuter notre SSG et de créer notre site. De nombreux générateurs utilisent Markdown comme source de données, mais que se passerait-il si nous allions plus loin et connections nativement notre SSG à un CMS ?
- Source des données : Sanity.io
- Récupération de données et création de modèles : nœud et guidon
- Hébergeur et déploiement : Netlify.
Conditions préalables
- NodeJS installé
- Compte Sanity.io
- Connaissance de Git
- Connaissance de base de la ligne de commande
- Connaissance de base du déploiement sur des services tels que Netlify.
Note : Pour suivre, vous pouvez trouver le code dans ce dépôt sur GitHub.
Configuration de notre structure de document en HTML
Pour commencer notre structure de document, nous allons écrire du HTML brut. Inutile de compliquer encore les choses.
Dans notre structure de projet, nous devons créer un emplacement pour nos fichiers sources. Dans ce cas, nous allons créer un répertoire src
et y mettre notre index.html
.
Dans index.html
, nous décrirons le contenu que nous voulons. Ce sera une page à propos relativement simple.
<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>
Gardons cela simple. Nous allons commencer par un h1
pour notre page. Nous suivrons cela avec quelques paragraphes d'informations biographiques, et nous ancrerons la page avec une liste de liens pour en savoir plus.
Convertir notre HTML en un modèle qui accepte les données
Une fois que nous avons notre structure de base, nous devons mettre en place un processus pour combiner cela avec une certaine quantité de données. Pour ce faire, nous allons utiliser le moteur de template Handlebars.
À la base, Handlebars prend une chaîne de type HTML, insère des données via des règles définies dans le document, puis génère une chaîne HTML compilée.
Pour utiliser Handlebars, nous devrons initialiser un package.json et installer le package.
Exécutez npm init -y
pour créer la structure d'un fichier package.json avec un contenu par défaut. Une fois que nous avons cela, nous pouvons installer les guidons.
npm install handlebars
Notre script de construction sera un script Node. C'est le script que nous utiliserons localement pour construire, mais aussi ce que notre fournisseur de déploiement et notre hôte utiliseront pour construire notre code HTML pour le site en ligne.
Pour démarrer notre script, nous allons créer un fichier index.js
et exiger deux packages en haut. Le premier est Handlebars et le second est un module par défaut dans Node pour accéder au système de fichiers actuel.
const fs = require('fs'); const Handlebars = require('handlebars');
Nous utiliserons le module fs
pour accéder à notre fichier source, ainsi que pour écrire dans un fichier de distribution. Pour commencer notre construction, nous allons créer une fonction main
pour que notre fichier s'exécute lorsqu'il est appelé et une fonction buildHTML
pour combiner nos données et notre balisage.
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');
La fonction main()
accepte deux arguments : le chemin vers notre modèle HTML et le chemin que nous voulons que notre fichier construit vive. Dans notre fonction principale, nous buildHTML
sur le chemin source du modèle avec une certaine quantité de données.
La fonction build convertit le document source en une chaîne et transmet cette chaîne à Handlebars. Handlebars compile un modèle à l'aide de cette chaîne. Nous transmettons ensuite nos données dans le modèle compilé et Handlebars affiche une nouvelle chaîne HTML remplaçant toutes les variables ou la logique du modèle par la sortie de données.
Nous renvoyons cette chaîne dans notre fonction main
et utilisons la méthode writeFile
fournie par le module de système de fichiers de Node pour écrire le nouveau fichier à l'emplacement spécifié si le répertoire existe.
Pour éviter une erreur, ajoutez un répertoire dist
dans votre projet avec un fichier .gitkeep
dedans. Nous ne voulons pas valider nos fichiers construits (notre processus de construction le fera), mais nous voudrons nous assurer d'avoir ce répertoire pour notre script.
Avant de créer un CMS pour gérer cette page, confirmons qu'il fonctionne. Pour tester, nous allons modifier notre document HTML pour utiliser les données que nous venons de lui transmettre. Nous utiliserons la syntaxe de la variable Handlebars pour inclure le contenu variableData
.
<h1>{{ variableData }}</h1>
Maintenant que notre code HTML a une variable, nous sommes prêts à exécuter notre script de nœud.
node index.js
Une fois le script terminé, nous devrions avoir un fichier à /dist/index.html
. Si nous lisons ouvrir ceci dans un navigateur, nous verrons notre balisage rendu, mais aussi notre chaîne "Ceci est une donnée variable".
Connexion à un CMS
Nous avons un moyen de rassembler les données avec un modèle, maintenant nous avons besoin d'une source pour nos données. Cette méthode fonctionnera avec n'importe quelle source de données disposant d'une API. Pour cette démo, nous utiliserons Sanity.io.
Sanity est une source de données basée sur l'API qui traite le contenu comme des données structurées. Ils disposent d'un système de gestion de contenu open source pour rendre la gestion et l'ajout de données plus pratiques pour les éditeurs et les développeurs. Le CMS est ce que l'on appelle souvent un CMS « Headless ». Au lieu d'un système de gestion traditionnel où vos données sont étroitement couplées à votre présentation, un CMS sans tête crée une couche de données qui peut être consommée par n'importe quel frontend ou service (et éventuellement plusieurs en même temps).
Sanity est un service payant, mais ils ont un plan "Standard" qui est gratuit et qui possède toutes les fonctionnalités dont nous avons besoin pour un site comme celui-ci.
Mise en place de la santé mentale
Le moyen le plus rapide d'être opérationnel avec un nouveau projet Sanity consiste à utiliser la CLI Sanity. Nous allons commencer par l'installer globalement.
npm install -g @sanity/cli
La CLI nous donne accès à un groupe d'assistants pour la gestion, le déploiement et la création. Pour commencer, nous allons exécuter sanity init
. Cela nous guidera à travers un questionnaire pour aider à démarrer notre Studio (ce que Sanity appelle leur CMS open-source).
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
Cette étape créera un nouveau projet et un ensemble de données dans votre compte Sanity, créera une version locale de Studio et liera les données et le CMS pour vous. Par défaut, le répertoire studio
sera créé à la racine de notre projet. Dans les projets à plus grande échelle, vous souhaiterez peut-être le configurer en tant que référentiel séparé. Pour ce projet, c'est bien de garder cela lié ensemble.
Pour exécuter notre Studio localement, nous allons changer le répertoire dans le répertoire du studio
et exécuter sanity start
. Cela exécutera Studio sur localhost:3333
. Lorsque vous vous connectez, un écran s'affiche pour vous informer que vous avez un « schéma vide ». Avec cela, il est temps d'ajouter notre schéma, c'est ainsi que nos données seront structurées et éditées.
Création d'un schéma d'intégrité
La façon dont vous créez des documents et des champs dans Sanity Studio consiste à créer des schémas dans le fichier schemas/schema.js
.
Pour notre site, nous allons créer un type de schéma appelé "À propos des détails". Notre schéma découlera de notre HTML. En général, nous pourrions faire de la majeure partie de notre page Web un seul champ de texte enrichi, mais il est recommandé de structurer notre contenu de manière découplée. Cela offre une plus grande flexibilité quant à la manière dont nous pourrions vouloir utiliser ces données à l'avenir.
Pour notre page Web, nous voulons un ensemble de données qui comprend les éléments suivants :
- Titre
- Nom et prénom
- Biographie (avec édition de texte enrichi)
- Une liste de sites Web avec un nom et une URL.
Pour définir cela dans notre schéma, nous créons un objet pour notre document et définissons ses champs. Une liste annotée de notre contenu avec son type
de champ :
- Titre — chaîne
- Nom complet — chaîne
- Biographie - tableau de "blocs"
- Liste de sites Web - tableau d'objets avec des champs de nom et de chaîne d'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' } ] } ] } ] } ])
Ajoutez ceci à vos types de schémas, enregistrez et votre Studio recompilera et vous présentera vos premiers documents. À partir de là, nous ajouterons notre contenu dans le CMS en créant un nouveau document et en remplissant les informations.
Structurer votre contenu de manière réutilisable
À ce stade, vous vous demandez peut-être pourquoi nous avons un "nom complet" et un "titre". C'est parce que nous voulons que notre contenu ait le potentiel d'être polyvalent. En incluant un champ de nom au lieu d'inclure le nom uniquement dans le titre, nous donnons plus d'utilisation à ces données. Nous pouvons ensuite utiliser les informations de ce CMS pour alimenter également une page de CV ou un PDF. Le champ biographie pourrait être utilisé par programmation dans d'autres systèmes ou sites Web. Cela nous permet d'avoir une seule source de vérité pour une grande partie de ce contenu au lieu d'être dicté par le cas d'utilisation directe de ce site particulier.
Tirer nos données dans notre projet
Maintenant que nous avons rendu nos données disponibles via une API, intégrons-les dans notre projet.
Installer et configurer le client JavaScript Sanity
Tout d'abord, nous avons besoin d'accéder aux données dans Node. Nous pouvons utiliser le client JavaScript Sanity pour forger cette connexion.
npm install @sanity/client
Cela va récupérer et installer le SDK JavaScript. À partir de là, nous devons le configurer pour récupérer les données du projet que nous avons configuré précédemment. Pour ce faire, nous allons configurer un script utilitaire dans /utils/SanityClient.js
. Nous fournissons le SDK avec notre ID de projet et le nom de l'ensemble de données, et nous sommes prêts à l'utiliser dans notre script principal.
const sanityClient = require('@sanity/client'); const client = sanityClient({ projectId: '4fs6x5jg', dataset: 'production', useCdn: true }) module.exports = client;
Récupérer nos données avec GROQ
De retour dans notre fichier index.js
, nous allons créer une nouvelle fonction pour récupérer nos données. Pour ce faire, nous utiliserons le langage de requête natif de Sanity, le GROQ open-source.
Nous allons créer la requête dans une variable, puis utiliser le client que nous avons configuré pour récupérer les données en fonction de la requête. Dans ce cas, nous construisons un objet avec une propriété appelée about
. Dans cet objet, nous souhaitons renvoyer les données de notre document spécifique. Pour ce faire, nous interrogeons en fonction du document _id
qui est généré automatiquement lorsque nous créons notre document.
Pour trouver le _id
du document, nous accédons au document dans Studio et le copions à partir de l'URL ou passons en mode "Inspecter" pour afficher toutes les données du document. Pour accéder à Inspect, cliquez sur le menu "kabob" en haut à droite ou utilisez le raccourci Ctrl + Alt + I . Cette vue listera toutes les données de ce document, y compris notre _id
. Sanity renverra un tableau d'objets de document, donc pour des raisons de simplicité, nous renverrons la 0th
entrée.
Nous transmettons ensuite la requête à la méthode fetch
de notre client Sanity et celle-ci renverra un objet JSON de toutes les données de notre document. Dans cette démo, renvoyer toutes les données n'est pas un gros problème. Pour les implémentations plus importantes, GROQ permet une "projection" facultative pour ne renvoyer que les champs explicites que vous souhaitez.
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); }
Conversion du champ de texte enrichi en HTML
Avant de pouvoir renvoyer les données, nous devons effectuer une transformation sur notre champ de texte enrichi. Alors que de nombreux CMS utilisent des éditeurs de texte enrichi qui renvoient directement du HTML, Sanity utilise une spécification open source appelée Portable Text. Portable Text renvoie un tableau d'objets (pensez au texte enrichi comme une liste de paragraphes et d'autres blocs multimédias) avec toutes les données sur le style du texte enrichi et les propriétés telles que les liens, les notes de bas de page et d'autres annotations. Cela permet de déplacer et d'utiliser votre texte dans des systèmes qui ne prennent pas en charge HTML, comme les assistants vocaux et les applications natives.
Pour notre cas d'utilisation, cela signifie que nous devons transformer l'objet en HTML. Il existe des modules NPM qui peuvent être utilisés pour convertir du texte portable en diverses utilisations. Dans notre cas, nous utiliserons un package appelé block-content-to-html.
npm install @sanity/block-content-to-html
Ce package affichera tout le balisage par défaut de l'éditeur de texte enrichi. Chaque type de style peut être remplacé pour se conformer au balisage dont vous avez besoin pour votre cas d'utilisation. Dans ce cas, nous laisserons le paquet faire le travail pour nous.
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 }
Utilisation du contenu de Sanity.io dans les guidons
Maintenant que les données sont dans une forme que nous pouvons utiliser, nous allons les transmettre à notre fonction buildHTML
en tant qu'argument de données.
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'); }); }
Maintenant, nous pouvons changer notre code HTML pour utiliser les nouvelles données. Nous utiliserons plus d'appels de variables dans notre modèle pour extraire la plupart de nos données.
Pour rendre notre variable de content
de texte enrichi, nous devrons ajouter une couche supplémentaire d'accolades à notre variable. Cela indiquera à Handlebars de restituer le HTML au lieu d'afficher le HTML sous forme de chaîne.
Pour notre tableau externalLinks
, nous devrons utiliser la fonctionnalité de bouclage intégrée de Handlebars pour afficher tous les liens que nous avons ajoutés à notre 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>
Configuration du déploiement
Mettons ça en direct. Nous avons besoin de deux composants pour que cela fonctionne. Tout d'abord, nous voulons un hôte statique qui construira nos fichiers pour nous. Ensuite, nous devons déclencher une nouvelle version de notre site lorsque le contenu est modifié dans notre CMS.
Déploiement sur Netlify
Pour l'hébergement, nous utiliserons Netlify. Netlify est un hébergeur de site statique. Il sert des actifs statiques, mais possède des fonctionnalités supplémentaires qui permettront à notre site de fonctionner correctement. Ils ont une infrastructure de déploiement intégrée qui peut exécuter notre script de nœud, des webhooks pour déclencher des builds et un CDN distribué dans le monde entier pour s'assurer que notre page HTML est servie rapidement.
Netlify peut surveiller notre référentiel sur GitHub et créer une version basée sur une commande que nous pouvons ajouter dans leur tableau de bord.
Tout d'abord, nous devrons envoyer ce code à GitHub. Ensuite, dans le tableau de bord de Netlify, nous devons connecter le nouveau référentiel à un nouveau site dans Netlify.
Une fois que c'est connecté, nous devons dire à Netlify comment construire notre projet. Dans le tableau de bord, nous nous dirigerons vers Paramètres> Construire et déployer> Paramètres de construction. Dans ce domaine, nous devons changer notre "commande Build" en "node index.js" et notre "répertoire de publication" en "./dist".
Lorsque Netlify construit notre site, il exécute notre commande, puis vérifie le contenu du dossier que nous listons et publie le contenu à l'intérieur.
Configurer un Webhook
Nous devons également indiquer à Netlify de publier une nouvelle version lorsque quelqu'un met à jour le contenu. Pour ce faire, nous allons configurer un Webhook pour informer Netlify que nous avons besoin de reconstruire le site. Un Webhook est une URL accessible par programme à un service différent (tel que Sanity) pour créer une action dans le service d'origine (dans ce cas Netlify).
Nous pouvons configurer un « Build hook » spécifique dans notre tableau de bord Netlify dans Paramètres > Build & Deploy > Build hooks. Ajoutez un crochet, donnez-lui un nom et enregistrez. Cela fournira une URL qui peut être utilisée pour déclencher à distance une construction dans Netlify.
Ensuite, nous devons indiquer à Sanity de faire une demande à cette URL lorsque vous publiez des modifications.
Nous pouvons utiliser la CLI Sanity pour accomplir cela. Dans notre répertoire /studio
, nous pouvons exécuter sanity hook create
pour nous connecter. La commande demandera un nom, un jeu de données et une URL. Le nom peut être ce que vous voulez, l'ensemble de données doit être la production
de notre produit et l'URL doit être l'URL fournie par Netlify.
Désormais, chaque fois que nous publierons du contenu dans Studio, notre site Web sera automatiquement mis à jour. Aucun cadre nécessaire.
- Le code peut être trouvé dans ce dépôt GitHub →
Prochaines étapes
Ceci est un très petit exemple de ce que vous pouvez faire lorsque vous créez votre propre outillage. Bien que des SSG plus complets puissent être ce dont vous avez besoin pour la plupart des projets, la création de votre propre mini-SSG peut vous aider à mieux comprendre ce qui se passe dans le générateur de votre choix.
- Ce site ne publie qu'une seule page, mais avec un petit extra dans notre script de construction, nous pourrions lui faire publier plus de pages. Il pourrait même publier un article de blog.
- L'"expérience développeur" manque un peu au référentiel. Nous pourrions exécuter notre script Node sur n'importe quelle sauvegarde de fichier en implémentant un package comme Nodemon ou en ajoutant un "rechargement à chaud" avec quelque chose comme BrowserSync.
- Les données qui résident dans Sanity peuvent alimenter plusieurs sites et services. Vous pouvez créer un site de CV qui l'utilise et publie un PDF au lieu d'une page Web.
- Vous pouvez ajouter du CSS et le faire ressembler à un vrai site.