pages Next.js directement en markdown
Avec Next.js, chaque page du site est représentée par un fichier javascript qui lui sert de point d'entrée. Ces pages sont ensuite pré-rendues à la compilation, ou côté serveur si elles sont dynamiques, ce qui a l'avantage d'être plus facilement indexé par les moteurs de recherche et d'être plus rapide à afficher par le client puisque l'affichage se fait avant qu'aucun code n'ai besoin d'être exécuté.
Tout cela est formidable, mais je ne veux évidemment pas avoir à écrire mes articles en javascript ! J'écris mes articles en Markdown car c'est un excellent compromis entre lisibilité et richesse de formatage.
Ce que j'ai fini par faire est d'écrire un plugin webpack
qui me permet d'utiliser des fichiers markdown à la place des fichiers javascript.
Le plugin prend le contenu d'un fichier .md
en entrée et génère du javascript
que next.js convertie ensuite comme d'habitude. Techniquement, il m'a suffit de
modifier next.config.js
pour effectuer cette conversion:
config.module.rules.push({ test: /\.md$/, include: pagesFolder, use: [ ...loaders, { loader:path.resolve('lib/post-loader.js'), options:{} } ] })
pagesFolder
est le chemin vers le dossier/pages
que next.js utilise pour former la structure ; les fichiers markdown présent ailleurs ne doivent pas passer par ce pluginloaders
est la liste de plugins déjà enregistrés pour traiter les fichiers javascript, il doit y avoir moyen de rendre cela implicite mais je n'ai pas encore trouvé comment faire (les conseils sont bienvenus)
Au moment de la compilation, le code dans lib/post-loader.js
prend le contenu
markdown et l'insère dans le code suivant :
import PostPage from '~/components/post' import {getPostThread} from '~/lib/compile-posts' <<<importSupportScript(md)>>> const Page = (props)=> ( <PostPage slug={<<<slug>>>} content={props.content} script={MDScript} threadPosts={props.threadPosts} ${coverSize(md)} /> ) export async function getStaticProps(context) { return { props: { content: <<<escapedSource>>>, threadPosts: getPostThread('posts',<<<thread>>>,['slug', 'title', 'date']) }, } } export default Page
escapedSource
est le contenu markdown sous forme d'une chaîne de caractère constante javascript.slug
est le nom du fichier markdownthread
est le nom de la série de post, si précisé dans le front matter de l'articlecoverSize(md)
récupère les dimensions de l'image de couverture s'il y en a une dans le front matterimportSupportScript(md)
me permet d'importer du code (en tant queMDScript
) dans le cas des pages qui comportent des fonctionnalités particulière, mais j'y reviendrais dans un prochain article.
Dans une précédente version de cet article, je disais qu'écrire ces articles
fonctionne efficacement comme une revue de code... et je ne croyais pas si bien
dire. J'avais une vision faussée de getStaticProps
, je cherchais à l'éviter
et générer l'ensemble des données directement depuis mon plugin en espérant
simplifier le code généré, ce qui fonctionne, mais ça n'est pas la meilleure
stratégie comme j'ai fini par me rendre compte en travaillant sur la
traduction...
Pour voir tout cela en contexte, rendez vous sur gitHub !
Dans de prochains articles, je parlerais de mon implémentation de i18n (internationalisation) qui est presque terminée et, comme je le disais plus haut, je parlerais aussi de comment mes articles comportant des fonctionnalités particulières sont constitués.
Behind the scenes
- open-sourcing myself
- using Markdown as Next.js pages
- Posting both in French and English