Hammerill Light Logo

Comment j'ai créé ce site

Comment j'ai créé ce site

Bonjour ! Je m'appelle Kirill.

Vous me connaissez peut-être sous mon surnom - Hammerill. Ou sous mon nom officiel, Kyrylo.

Quoi qu'il en soit, vous êtes intéressé par la façon dont ce site a été créé. Permettez-moi de commencer.

Alors, qu'est-ce qu'Hammerill ? Eh bien, disons simplement que c'est un lien direct avec moi.

Imaginez-moi avoir 11 ans dans un cours d'anglais :

"H-A-M-M-E-R" - "Hammer". Ça veut dire marteau, les enfants.

...

Kirill ! Que veut dire "hammer" ?

Et c'est à ce moment-là que j'ai pensé à fusionner les deux mots : "hammer" et mon propre nom "Kirill" en un seul : Hammerill. Je ne me souciais pas vraiment du sens ou quoi que ce soit, ça me paraissait juste cool. Depuis, je le mets partout comme mon surnom.

Et j'ai imaginé un logo, littéralement un marteau avec des coins en diamant :

Vieux logo d'Hammerill

L'ancien logo d'Hammerill réalisé par mes soins dans Paint en 2016.

Fait intéressant, seuls ces coins en diamant sont encore là. Vous pouvez les voir sous la forme de deux carrés bleus en mode clair ou de deux carrés blancs en mode sombre comme le logo de ce site.

Je parlerai de l'histoire de ce surnom sur la page principale lorsque j'aurai terminé l'effet parallaxe.

Si vous savez pas ce qu'est la parallaxe, jetez un oeil rapide à cet exemple :

Pour l'instant, continuons.

Après une longue période d'inactivité en ligne après la guerre, j'ai décidé de redonner vie à mon ancien surnom. Une seule petite chose m'est venue à l'esprit : créer un site Web personnel.

J'ai enregistré le nom de domaine hammerill.com et pris un VPS. Je ne parlerai pas trop des services que j'ai utilisés, disons que le nom de domaine m'a coûté ~10€/an et le VPS ~100€/an.

Maintenant, étant étudiant en informatique, je dois le configurer.

Parlons maintenant de la partie technique.

La seule chose que je connaissais en tant que serveur Web était Apache. J'ai essayé de l'installer directement sur le VPS et de le laisser servir du HTML brut. J'ai également appris des choses telles que HTTPS, les certificats SSL et comment les obtenir, Let's Encrypt, afin de se débarrasser de cette erreur de sécurité ennuyeuse.

Mais Apache installé directement sur le VPS n'était pas la solution la plus confortable avec laquelle travailler. Je ne pouvais pas vraiment le configurer pour mes sous-domaines (comme sand-box2d.hammerill.com), c'est peut-être juste mon problème, peut-être que c'est Apache qui est difficile à configurer, je sais pas.

Où est-ce que je suis censé sauvegarder ma configuration ? Dois-je la copier manuellement à chaque fois ? C'était le moment de tout réviser et d'automatiser. J'ai pensé à mon serveur Git personnel.

Comme je l'ai vu lors de mon stage, n'importe qui peut en fait avoir son propre serveur Git, GitLab par exemple. J'ai donc essayé de l'installer sur mon VPS. C'était... pas facile. Cela m'a obligé à apprendre des choses telles que Docker, son Compose et le serveur Web Nginx. Et enfin, je l'ai fait fonctionner.

Mais GitLab me semblait trop lourd. Heureusement, je viens de commencer à travailler sur un projet dans mon lycée où les profs utilisaient l'ultra petit Gitea à la place, j'ai donc changé. Cela m'a également obligé à utiliser davantage de Docker.

Après avoir été obligé d'apprendre Docker, j'ai commencé à le voir comme une chose intéressante. Si je peux stocker mes configurations sur le serveur Git, lancer le conteneur Docker est bien plus simple que forcer l'installation manuelle des dépendances. Désormais, chaque service peut être placé dans l'espace portable sans toucher à la configuration du serveur lui-même.

La première chose que je voulais mettre dans le Docker était le serveur Web. Et ce n'était pas Apache. C'était Nginx. Et ça a très bien fonctionné ! Il dessert désormais tous mes sous-domaines, facilement configurables à tout moment.

Maintenant, le plus important. Mon site lui-même.

Il s'agit d'une application Next.js exécutée sur le port 3000 dans un Docker. Un autre Docker (Nginx) effectue le proxy sur le port 443 tout en fournissant les certificats SSL. J'expliquerai plus tard comment je l'ai codé.

Ce VPS est un endroit idéal pour héberger le reste. Par exemple :

  • Serveur de messagerie. VPS exécute un autre Docker qui me permet de configurer mon propre serveur de messagerie.
  • Ackee. Ackee est une alternative open source à Google Analytics ou similaire.
  • code-server. Une solution sympa pour avoir votre propre VSCode en ligne accessible depuis chaque ordinateur pouvant se connecter à Internet. Il suffit de bien le sécuriser. Par exemple, ce texte que vous lisez est écrit sur 4 PC différents (mon ordinateur portable puissant à la maison, mon ordinateur portable lent, un PC au lycée et un PC en stage). L'état du texte et du terminal est parfaitement synchronisé avec toutes les machines connectées au code-server.
  • Et bien plus encore, comme les rapports SMS...

Et enfin, l'aspect programmation du site que vous visitez.

  • Tout d'abord, ce site est basé sur Next.js.
  • Next.js est un framework basé sur la bibliothèque React.
  • React permet de créer des composants réutilisables (genre de modèles d'éléments HTML) et de les utiliser dans votre code JavaScript (en fait TSX).

L'intérêt de Next.js est qu'il exécute votre code JavaScript sur le serveur et envoie le HTML prêt au client. En général, du code React simple sans aucun framework est exécuté sur le client, ce qui peut être difficile pour les appareils bas de gamme. Et plus encore, vous pouvez demander à Next.js d'exécuter votre code une seule fois au moment du build et de générer les ressources HTML/CSS/JS statiques. C'est ainsi que le static.hammerill.com/fr (vous pouvez même y accéder en mode HTTP plein depuis une TRÈS vieille machine) et hammerill.github.io fonctionnent.

J'ai choisi Next.js alors que je pensais : "Eh bien. Je dois créer mon site. Je n'ai pas pratiqué le développement web pendant un moment. Quelle est la dernière pile technologique que je peux apprendre maintenant et utiliser pour créer mon site Web ?".

Et c'est comme ça que j'ai choisi Next.js, TailwindCSS et shadcn/ui.

Tailwind vous offre une autre façon de styliser les éléments. L'idée est que vous appliquiez le nom de la classe comme flex flex-wrap au lieu de créer une classe en CSS comme celle-ci :

.wrapper {
  display: flex;
  flex-wrap: wrap;
}

Cela simplifie vraiment tout ! Allez-y et essayez-le.

shadcn/ui vous fournit les composants prêts dans un look moderne pour certaines choses les plus utilisées comme le menu déroulant. De cette façon, je n'ai pas à perdre de temps à coder des choses telles que "programmer l'état fermé/ouvert du menu", et à la place, je remplis simplement mon site avec le contenu que je souhaite voir.

Regardez ces boutons qu'il propose (je vous rappelle que la seule chose que j'ai stylisée est leur positionnement) :

NE PAS. CLIQUER. SUR. MOI.

Bien sûr, il fournit beaucoup plus de choses, comme le bouton du menu déroulant dans le coin supérieur gauche.

Le composant <VisibleWrapper> est la particularité de mon site. Peut-être la plus problématique.

Il agit comme un <div> mais chaque fois que l'élément n'est pas à l'écran, il devient transparent. Lorsqu'il apparaît à l'écran, il redevient visible. Et nous pouvons voir cet effet s'estomper légèrement à mesure que l'effet CSS de transition a été appliqué.

Ce composant crée 4 problèmes :

  1. Lecteurs d'écran
    Certains lecteurs d'écran (comme celui de Chrome sur mobile) peuvent avoir du mal à analyser des éléments encore invisibles. Depuis le 26 mai, je propose la grande solution : VisibleWrapper appliquera opacity-5 au lieu de opacity-0.
  2. JS requis
    Comme tous les éléments sont définis comme non visibles par défaut, un script en JS doit les activer. Cela peut augmenter le temps de chargement. Depuis le 26 mai, la grande solution aide aussi : vous pourrez voir légèrement le contenu.
  3. Création d'une nouvelle mise en page
    Chaque fois que j'ajoute un nouvel élément, je dois m'assurer qu'il se trouve dans un <VisibleWrapper> ou, plus simple, remplacer <div> par <VisibleWrapper> s'il s'agit bien d'un <div> par hasard.
  4. DOM
    Regarder le code HTML produit n'est pas vraiment confortable. Par exemple, tous les paragraphes du blog sont enveloppés dans ces <div>.

Les deux premiers problèmes peuvent être résolus. Et d'ailleurs, j'ai proposé la grande solution depuis le 26 mai. Vous pouvez résoudre le premier problème en réglant les graphiques sur un niveau bas (en disant à JS de rendre tous les éléments visibles) ou résoudre tous les deux de façon permanent en accédant à la version statique du site (en désactivant complètement <VisibleWrapper> et en le transformant en <div> normal). Je vous rappelle que dans le cas de mon site, l'utilisation de la version statique est bien encouragée. Elle reçoit les dernières mises à jour et bénéficie du même support.

Les deux autres sont inévitables. Mais l'utilisateur final s'en fiche. 🤷

De plus, comment ai-je placé tous les paragraphes du blog dans des <div> spéciaux et fait en sorte que cela fonctionne en statique ?

Le texte que vous lisez en ce moment est écrit en MDX, un type de Markdown qui me permet d'insérer du code JSX spécial. Ensuite, il est compilé dans un JSX normal. Après cela, en statique, il est compilé en HTML.

Avez-vous remarqué la possibilité de changer la langue ? Si vous allez cliquer sur Menu déroulant > Langue > English, vous verriez la version anglaise de cet article. Ces deux versions (française et anglaise) sont des fichiers MDX différents situés dans le même dossier d'article.

Alors comment ça marche ? Premièrement, le changement de langue est fourni par la bibliothèque next-intl. Ensuite, comme l'exige le "Next.js App Router", j'importe tous ces fichiers MDX dans le fichier page.tsx situés dans le dossier de l'article particulier (je le copie-colle à chaque fois -_-) et renvoie le fichier MDX correspondant au composant qui l'enveloppe sous forme d'article.

Pour avoir une idée de comment cela fonctionne, jetez un œil à cette capture d'écran :

Structure du blog d'Hammerill

Remarque : ce n'est pas la structure complète. Je la sectorise également et il y a encore plus de fichiers. Je vous donne cet exemple uniquement pour vous faire comprendre le principe.

Examinons-le. De bas en haut (préparez-vous, cela remplira tout votre écran) :

  • layout.tsx et page.tsx dans le dossier blog
    Page principale du blog. Elle vous montre tous les articles.
  • layout.tsx dans le dossier (articles)
    Mise en page partagée de tous les articles. Voir plus ici.
  • article-utils.tsx
    Fichier contenant tous les éléments nécessaires pour mettre en place l'article importé de MDX. Par exemple, placer l'image floue de l'article en arrière-plan et ajouter le bouton "Retour au blog". Ce fichier est séparé de "layout.tsx" car il déclare qu'il exporte les composants utilisés dans les routes d'articles. Le composant principal exporté est "ArticleHolder" prenant quelques métadonnées et MDX importé avec le paramètre régional correspondant comme enfant.
  • Dossiers à l'intérieur du dossier (articles)
    Chaque article particulier. En considérant le Next.js App Router, cela signifie que vous pouvez accéder aux deux articles sur les URL "/blog/example" et "/blog/second-example".
  • img.png
    Une image utilisée dans l'article. Peut-être qu'elle est utilisée comme image d'aperçu de l'article. Peut-être qu'elle est utilisée dans l'article comme figure. Elle pourrait être placée dans le dossier "img".
  • get-article-meta.ts
    Un fichier exportant les métadonnées de l'article. Il importe tous les fichiers MDX locaux, prend leurs exportations (titre et description localisés) et les rassemble tous. Il peut contenir la méta générale ne dépendant pas des paramètres régionaux (comme la date de publication au format ISO, par exemple "2024-05-19").
  • page.tsx
    Fichier gérant l'itinéraire comme requis par le Next.js App Router. Il importe simplement tous les fichiers MDX locaux, regarde le paramètre régional demandé et retourne un "ArticleHolder" en lui transmettant toutes les données nécessaires (métadonnées de "get-article-meta.ts" et MDX avec le paramètre régional actuel).
  • en.mdx et fr.mdx
    Contenu réel de l'article. C'est simplement le Markdown, mais je dois exporter titre et description traduits et je peux importer certains de mes propres composants si nécessaire. Ils pourraient être placés dans le dossier "content".

Waouh ! C'est beaucoup. Et pourtant, j'ai pris mon temps pour composer tout ça et ça marche vraiment.

Mais pourquoi tout compliquer à l'excès ? Et bien, ça rend mon site accessible à tous ceux que je connais car toutes les langues sont bien prises en charge.

Et de plus, il pourrait être exporté statiquement. Cela signifie que chaque modification que j'apporte pourrait créer une nouvelle exportation statique. Cette exportation pourrait fonctionner même si je ne me soucie plus de mon site, car l'hébergement par GitHub est gratuit et permanent (GitHub supprimerait-il mon compte et tout son contenu si je restais hors ligne pendant si longtemps ? 🤔).

Nous n'avons pas encore discuté des aspects intéressants de cette approche : les plugins MDX et les composants personnalisés.

Tout d'abord, j'ai créé le composant typography contenant divers éléments de typographie personnalisés comme recommandé par shadcn. Ensuite, j'enveloppe tous les éléments dans le <VisibleWrapper>.

Par exemple, au lieu du <p> normal, il y a <P> qui ressemble essentiellement à ceci :

<VisibleWrapper className={visibleWrapperClassName}>
  <p {...props} className={cn("mt-6 leading-7 break-words", className)}>
    {children}
  </p>
</VisibleWrapper>

Cela signifie que je dois représenter un paragraphe avec mon composant et qu'appliquer simplement du CSS ne suffit pas.

Heureusement, MDX me permet de le faire. Jetez un œil à mdx-components.tsx :

import { ---, P, --- } from "@/components/typography";

export function useMDXComponents(---): MDXComponents {
---
p: ({children, ...props}: {children?: React.ReactNode}) => (
  <P {...props}>{children}</P>
),
---
}

Maintenant, le module transformant le paragraphe MDX en paragraphe JSX comprend qu'il doit produire mon composant <P>, pas la balise HTML par défaut <p>. C'est très sympa ! J'ai fait ça pour tous les éléments.

Après cela, je peux connecter des plugins Remark et Rehype personnalisés tels que autolink-headings qui ajoute ces boutons à droite des titres lorsque vous les survolez. Ma tâche est de m'assurer qu'il fonctionne et de lui donner du style.

À propos, ces boutons sont ajoutés à gauche par défaut. Je dois le configurer. Regardez next.config.mjs :

export const withMDX = createMDX({
  options: {
    rehypePlugins: [rehypeHighlight, rehypeSlug, [rehypeAutolinkHeading, {behavior: "append"}]],
    remarkPlugins: [remarkGfm, [remarkToc, {heading: tocHeading}]],
  },
  extension: /\.mdx?$/,
});

Vous l'avez vu ? C'est behavior: "append".

Ce que je voulais dire, c'est qu'il y avait TROP de choses comme ça qui m'obligeaient à appliquer une toute petite configuration pour que cela fonctionne. Mais pour trouver cette petite configuration, je dois passer des heures à comprendre qui est responsable du problème et comment y remédier. Après tout, cela fait de moi un développeur expérimenté.

Autre exemple : lors de l'impression d'une page, le texte sera flou sur le papier si on applique le nom de classe Tailwind blur-none quelque part. Pour vraiment supprimer l'effet de flou, il faut plutôt appliquer filter-none. 🫠

En général, créer ce site a été un plaisir, une bonne manière de passer du temps.

Si vous lisez ceci, la moitié du travail est fait. Mais l'effet parallaxe n'est pas encore terminé. Je devrais commencer à travailler !

Si vous souhaitez vous abonner ou dire autre chose, envoyez-moi un e-mail et je verrai plus loin sur la mise en œuvre de cette fonctionnalité.

Merci d'être resté avec moi, à bientôt !