Pour certain·e·s, c'est le désir de partager, pour d'autres, c'est une façon de prendre des notes, mais on a tous·tes, en tant que développeur·se, au moins une bonne raison de créer notre propre dev blog. Sauf que bien des fois, on peut se retrouver découragé·e devant la myriade de technologies à notre disposition pour créer un site web, et la potentielle courbe d'apprentissage de celles-ci.
Et si je te dis que grâce à Nuxt 3 et au module Nuxt/Content, il devient beaucoup plus facile de créer un site dit "content-driven", comme le serait notre dev blog.
Nuxt 3 est le framework "piles incluses" de Vue 3. Il est, à l'heure où j'écris cet article, encore en Release Candidate, mais peu de choses devraient changer d'ici la version finale.
Le but de cet article n'est pas de faire une revue détaillée du fonctionnement de Nuxt puisque nous n'allons écrire que peu de code propre au framework mais je t'invite à jeter un oeil à la documentation pour te permettre d'aller plus loin par la suite.
Nuxt/Content est un module Nuxt qui permet au framework de transformer des simples fichiers markdown en véritables pages pour nous permettre de créer un site en se concentrant sur le contenu. Il y a aussi une documentation pour t'aider à approfondir sur le module.
Création du projet
Dans ton terminal préféré, il te suffit de lancer la commande suivante pour initialiser un projet Nuxt :
npx nuxi init mon-blog
Pour être tranquille pour la suite, nous allons installer ce dont on a besoin :
cd mon-blog
npm install
npm i -D @nuxt/content
Le dev server se lance avec la commande :
npm run dev
En navigant sur http://localhost:3000, tu te retrouves alors sur la page de notre nouveau site, auto-générée par la CLI de Nuxt (nuxi).
Afin de pouvoir utiliser le module content, il faut l'ajouter aux modules dans la config Nuxt nuxt.config.ts
comme ci-dessous :
import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
modules: ['@nuxt/content']
})
Un peu de code
Désolé, il y aura quand même un peu de code... Il faut bien préparer la structure!
Une première page
La première chose à faire est de préparer les pages. Nuxt, par convention, transformera chaque composant Vue déclaré dans le dossier pages
en page, dont le chemin sera le nom donné au fichier. Ainsi pages/index.vue
va créer une route qui correspond à l'index de notre site. Et c'est ce que nous allons faire avec un placeholder:
<!-- pages/index.vue -->
<template>
<div>index page</div>
</template>
Ensuite, il nous faut soit retirer le fichier app.vue
(et laisser Nuxt wrapper les pages lui même) ou l'éditer pour lui indiquer d'utiliser les pages (et layouts).
<!-- app.vue -->
<template>
<div>
<NuxtLayout>
<NuxtPage/>
</NuxtLayout>
</div>
</template>
Si l'on essaie d'accéder à une quelconque adresse autre que l'index, Nuxt nous renverra une erreur 404. Ce qui est normal puisque nous n'avons configuré qu'une unique page.
D'autres pages grâce au catch-all
Pour garder une structure simple dans le cadre de cet article, nous considérerons, que toutes les autres pages sont potentiellement des articles du blog. Pour les exposer, il suffit alors de créer une page dite "catch-all". Sous le dossier pages/
, on appellera ce composant [...slug].vue
, c'est la convention retenue par Nuxt pour "attraper" tout autre chemin qui n'est pas clairement défini comme une page (comme l'est index.vue
).
<!-- pages/[...slug].vue -->
<template>
<main>
<ContentDoc />
</main>
</template>
Et ça suffit pour le moment pour le code. Mais qu'est-ce que ce composant ContentDoc
et d'où sort-il ?
Il s'agit d'un composant auto-importé par Nuxt, exposé par le module Content qui a deux fonctionnalités:
- Récupérer le contenu d'un fichier markdown.
- Faire le rendu de celui-ci.
Où va-t-il récupérer le contenu ? C'est le sujet de la suite !
Ajouter du contenu
Par convention, le module content ira chercher tout fichier markdown, yaml, json et même csv dans un dossier content/
situé à la racine.
C'est donc parti pour écrire notre premier post en créant un fichier Markdown content/mon-premier-post.md
.
# Mon premier post
Ceci est le contenu du premier post de mon blog Nuxt + Content.
Et juste avec ça, nous venons de créer le premier post de notre blog! En navigant vers http://localhost:3000/mon-premier-post, on peut voir le contenu parsé et rendu en HTML équivalent à notre Markdown.
Pour donner un peu plus de contenu, nous allons créer un deuxième post avec content/un-autre-post.md
.
# Un autre post
Et voici un autre post, le premier s'ennuyait.
Et une autre page est ajoutée à notre site : https://localhost:3000/un-autre-post
Ajouter la navigation
Maintenant que nous avons quelque posts, il serait intéressant de pouvoir accéder à ceux-ci depuis notre page d'accueil. Nuxt/Content expose le composant 'ContentNavigation', il s'agit d'un composant dit "renderless": ce composant ne fait aucun rendu mais expose des variables et méthodes à ses composants enfants. Reprenons notre page index.vue
comme ceci:
<template>
<div>
<h1>Mon blog Nuxt 3 + Content 2</h1>
<nav>
<ul>
<ContentNavigation v-slot="{ navigation }">
<li v-for="link of navigation" :key="link._path" >
<NuxtLink :to="link._path">
{{ link.title }}
</NuxtLink>
</li>
</ContentNavigation>
</ul>
</nav>
</div>
</template>
Le composant ContentNavigation
génère une liste de liens vers chacune des pages que nous avons créées et les expose auto-magiquement au travers de navigation
. Si cette mécanique Vue appelée "scoped slots" t'es inconnue, voici la documentation.
Allez plus loin
Maintenant que nous avons une structure, il est temps d'ajouter un peu d'âme et de customisation à notre blog.
Modifier les composants Markdown (Prose)
Il est très facile de surcharger les composants utilisés par Nuxt/Content pour transformer le markdown en HTML. Voici la liste des composants Prose que Nuxt/Content met à notre disposition.
Ainsi, en déclarant un composant ProseH1.vue
dans un dossier components/content/
comme ceci:
<!-- components/content/ProseH1.vue -->
<template>
<h1><slot /></h1>
</template>
<style scoped>
h1 {
color: red;
font-weight: bold;
}
</style>
Tous les h1
générés par les #
markdown sont maintenant rouge et en gras, comme décidé dans notre composant ProseH1
!
La syntaxe MDC
Toujours dans l'optique de centrer la création des sites sur le contenu, le module Nuxt/Content apporte une syntaxe Markdown particulière : les MDC (ou MarkDown Components). Nous allons pouvoir créer des composants Vue et les réutiliser directement depuis nos fichiers de contenu en Markdown. Cette syntaxe va nous permettre d'utiliser les nombreuses API des composants Vue (props, slots...) depuis les fichiers Markdown.
Voici un bouton pour l'exemple, qu'on mettre lui aussi dans components/content
:
<!-- components/content/CustomButton -->
<script setup lang="ts">
defineProps<{ color: string }>()
const sendAlert = () => alert('Hello :)')
</script>
<template>
<button @click="sendAlert" :style="{ color }">
<slot />
</button>
</template>
Allons éditer notre premier post pour y ajouter ce bouton :
# Mon premier post
Ceci est le contenu du premier post de mon blog Nuxt + Content.
::CustomButton{color='red'}
clique sur moi!
::
On peut directement passer des props au composant, comme nous avons passé color
dans cet exemple! Cette syntaxe supporte même les named slots.
Je te laisse approfondir dans la documentation. Tout composant déclaré dans components/content
sera accessible depuis les fichier Markdown de contenu, les possibilités sont presque infinies!
Cette article reste une introduction très basique à Nuxt et au module Content, mais j'espère qu'il te donne une idée du monde de possibilités que ces technologies offrent. A considérer aussi qu'à l'heure ou j'écris cet article, elles sont encore jeunes (nuxt@3.0.0RC-6
et @nuxt/content@v2.0.1
), et seront surement amenées à évoluer.
Tu peux retrouver le code de cet article sur ce repo. Je t'invite aussi à passer sur mon dev blog, réalisé avec Nuxt3 et Nuxt/Content, dont tu peux retrouver le code ici!
Top comments (4)
Superbe !
Cependant, une erreur de frappe dans le premier codeblock.
Non, c'est bien un
npx nuxi
pour exécuter le binary de nuxi qui est le nouveay cli de nuxt3 :)Oh d'accord :o
Je viens de voir la doc, c'est un peu bizarre comme typo, on dirait une faute de frappe 😆
Sympa l'article.
Je cherchais une solution pour mon blog ayant essayé docusaurus et next.js, j'avais une envie de pousser plus sur du vue...
Merci !