Optimisez l'architecture de votre blog VitePress avec Vite
Dans l'article précédent, nous avons initié notre projet VitePress et examiné sa structure. Nous avons également commencé à intégrer notre thème personnalisé. Aujourd'hui, nous allons progresser davantage en définissant l'architecture du blog et son design afin de garantir qu'il reste gérable et évolutif au fil du temps.
Le Répertoire src
Pour commencer, nous allons déplacer les fichiers source de notre projet dans un répertoire src
désigné. Cette approche évite de surcharger le répertoire racine avec des fichiers source et empêche l'inclusion de fichiers indésirables comme README.md
dans les pages de notre projet.
Que constituent nos fichiers source ? Plus précisément, le thème est-il un fichier source ? La réponse est non. Comme nous développons un site centré sur le contenu, seuls les fichiers markdown et publics sont considérés comme des fichiers source. Tout ce qui concerne le thème fait partie de la configuration de VitePress et résidera dans le répertoire .vitepress
.
Pour modifier le répertoire source, nous devons mettre à jour l'option srcDir
dans le fichier config.mts
situé dans le répertoire .vitepress
. Voici le contenu révisé du fichier config.mts
:
import { defineConfig } from 'vitepress'
export default defineConfig({
srcDir: 'src',
// ...
})
Cette option informe VitePress où sont stockées nos pages markdown par rapport à la racine du projet. Dans notre cas, la racine du projet est la racine du dépôt.
Le répertoire src
comprendra également un répertoire public
, où seront stockés des actifs statiques comme des images, des polices et d'autres fichiers non modifiés.
Note
Le répertoire public
est associé à la racine du site et n'est pas traité par VitePress. Par conséquent, les fichiers dans le répertoire public
seront copiés à la racine du site généré sans aucune transformation.
.
├── .vitepress
│ └── config.mts
├── src
│ ├── public
│ └── index.md
└── package.json
Cette structure est significativement plus propre et mieux organisée. Si nous souhaitons rédiger un article de blog, nous ouvrons simplement le répertoire src
, et si nous souhaitons mettre à jour notre thème, nous accédons au répertoire .vitepress
.
Le Répertoire .vitepress
Concernant le répertoire .vitepress
, nous pouvons créer des sous-répertoires pour aider à structurer notre thème, en maintenant la simplicité d'un projet standard Vite + Vue.
Sous .vitepress/theme
, nous établirons les répertoires suivants :
components
: Contient tous les composants Vue utilisés dans le thème.composables
: Contient toutes les fonctions composables Vue utilisées dans le thème.pages
: Contient tous les composants Vue employés comme pages dans le composantLayout.vue
.styles
: Contient tous les fichiers CSS appliqués dans le thème.types
: Contient tous les types TypeScript utilisés dans le thème.utils
: Contient toutes les fonctions utilitaires utilisées dans le thème.
.
├── .vitepress
│ ├── theme
│ │ ├── components
│ │ ├── composables
│ │ ├── pages
│ │ ├── styles
│ │ ├── types
│ │ ├── utils
│ │ ├── index.ts
│ │ └── Layout.vue
│ └── config.mts
├── src
│ ├── public
│ └── index.md
└── package.json
Cette structure ressemble de près à ce à quoi de nombreux développeurs Vue sont habitués, ce qui est avantageux ! Cela supprime la nécessité d'apprendre une nouvelle structure de projet tout en utilisant VitePress. Si vous êtes familiers avec la structuration d'un projet Vue, vous savez déjà comment structurer un projet VitePress. 👌
Le Répertoire pages
Je reconnais que cela peut sembler déroutant. J'ai mentionné plus tôt que VitePress dispose d'un routeur minimal, et que les routes sont générées à partir de la structure du répertoire src
. Alors, que signifient ces pages
?
VitePress suit la convention d'utiliser Layout.vue
comme point d'entrée de l'application Vue. Dans ce scénario, avoir un répertoire layouts
impliquerait qu'un layout utilise un layout, ce qui me semble étrange.
Renommer Layout.vue
en App.vue
pourrait être une option, mais je la trouve moins séduisante. Je préfère conserver le nom Layout.vue
car c'est une convention de VitePress. De plus, comme VitePress n'a pas de routeur, nous ne pouvons pas utiliser un composant RouterView
pour rendre le layout et la page. Cela implique que Layout.vue
et App.vue
remplissent des fonctions différentes.
En fin de compte, établir un répertoire pages
semblait la décision la plus logique. Dans ce répertoire, nous incluons des composants Vue tels que NotFound.vue
, Blog/BlogIndex.vue
, Blog/BlogPost.vue
, etc., formant un système de routage basé sur les fichiers.
Note
Le répertoire pages
est mon approche pour organiser le projet. Ce n'est pas imposé par VitePress. Tous les fichiers .vue
pourraient résider dans le répertoire components
ou layouts
. N'hésitez pas à personnaliser la structure selon vos préférences.
En conclusion, nous utiliserons Layout.vue
pour router nos fichiers Markdown vers le composant de page approprié. Pour ce faire, nous utiliserons la clé layout
dans le frontmatter de nos fichiers Markdown. Cette clé facilite l'importation du composant de page correct dans le fichier Layout.vue
.
Considérez le fichier Markdown suivant :
---
layout: blog-post
---
# Bonjour, le Monde !
Dans le fichier Layout.vue
, nous pouvons rendre le composant Blog/BlogPost.vue
comme suit :
<script lang="ts" setup>
import { useData } from 'vitepress'
const { frontmatter } = useData() // C'est le frontmatter du fichier Markdown actuel
</script>
<template>
<BlogPost v-if="frontmatter.layout === 'blog-post'" />
<Content v-else /> // Rendre simplement le contenu du fichier Markdown
</template>
Cette approche permet un système de routage dynamique sans routeur réel. Dans le même temps, Layout.vue
reste le point d'entrée de l'application Vue.
Note
Si quelque chose n'est pas clair, ne vous inquiétez pas. Nous appliquerons cela dans les prochains articles lors de l'introduction des articles de blog et de la liste de blog.
Configuration de Unplugin Vue Components
Dans le précédent extrait de code, nous avons utilisé le composant BlogPost
sans l'importer. Cette magie devient possible grâce à Unplugin Vue Components.
Note
Cette étape est entièrement optionnelle, et vous pouvez l'omettre si vous le souhaitez. Pour moi, c'est un excellent moyen de maintenir un code propre, et en tant qu'utilisateur de Nuxt, j'ai une légère préférence pour cette méthode. 😅
En coulisses, ce plugin pour Vite scanne nos fichiers à la recherche de composants Vue lorsqu'ils passent par le pipeline de Vite. Lorsqu'il détecte un composant, il ajoute la déclaration d'importation pertinente en haut du fichier. Cela s'aligne sur la philosophie à la demande de Vite, garantissant de petites tailles de bundle et permettant le découpage de composants là où ils sont utilisés.
Ce plugin s'intègre parfaitement à TypeScript, veillant à ce que nous ne compromettons ni le contrôle de type ni l'auto-complétion dans notre IDE.
Installation des Dépendances Nécessaires
Tout d'abord, nous devons installer TypeScript et les types Node. Cela est essentiel car le plugin génère un fichier de déclaration contenant les types de nos composants.
pnpm add -D typescript @types/node vue
Note
L'installation de vue
est requise lors de l'utilisation de pnpm en raison de son mécanisme de levée. Consultez l'option shamefully-hoist
pour plus d'explications.
Ensuite, un fichier tsconfig.json
doit être créé à la racine du projet pour orienter le comportement de TypeScript.
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true
},
"include": ["./.vitepress/**/*"]
}
Les @types/node
sont automatiquement intégrés par TypeScript. Nous incluons tous les fichiers dans le répertoire .vitepress
où se trouvent nos composants TypeScript et Vue. Ce modèle importe également les fichiers .d.ts
, ce qui est crucial pour le plugin.
Nous devons également ajouter "type": "module"
dans le fichier package.json
et modifier les extensions de postcss.config.js
et tailwind.config.js
en .cjs
.
Configuration
Finaliser la configuration du plugin est simple :
- Indiquons au plugin le répertoire où se trouvent nos composants Vue.
- Définissons au plugin les conventions de nommage pour nos composants Vue.
- Spécifions au plugin l'emplacement pour créer le fichier de déclaration.
Étant donné que le fichier config.mts
réside dans le répertoire .vitepress
, il y a plus de configuration que dans un projet Vite standard où la configuration vite.config.ts
est située à la racine du projet.
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import Components from 'unplugin-vue-components/vite'
import { defineConfig } from 'vitepress'
const currentDir = dirname(fileURLToPath(import.meta.url))
const componentsDir = resolve(currentDir, 'theme', 'components')
const pagesDir = resolve(currentDir, 'theme', 'pages')
export default defineConfig({
// ...
vite: {
plugins: [
Components({
dirs: [
componentsDir,
pagesDir,
],
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
dts: resolve(
currentDir,
'components.d.ts'
),
}),
],
},
})
L'option dirs
dirige le plugin vers l'emplacement de nos composants. Dans notre contexte, nous avons deux répertoires : theme/pages
et theme/components
, relatifs au fichier config.mts
. Cette distinction est importante car le processus commence à la racine du projet, mais la configuration se trouve dans le répertoire .vitepress
. Cela évite l'utilisation de ../../
dans les chemins.
L'option include
spécifie les extensions de fichier qui doivent être scannées pour ajouter des déclarations d'importation. Nous incluons les fichiers .vue
et .md
car nous pourrions avoir des composants Vue dans des fichiers Markdown sans avoir besoin d'importations explicites, ce qui est une fonction fantastique.
L'option dts
guide le plugin sur l'endroit où créer le fichier de déclaration. Nous souhaitons créer le fichier components.d.ts
à la racine du répertoire .vitepress
. Ce fichier de déclaration aide notre IDE et TypeScript à fournir une auto-complétion et un contrôle de type, même lorsque les composants ne sont pas explicitement importés.
Lorsque nous lançons notre serveur de développement, nous devrions vérifier le bon fonctionnement du plugin en examinant le fichier components.d.ts
. Au départ, ce fichier peut ne pas comporter de composants car nous n'en avons pas encore. Créer un composant temporaire permettra d'observer les changements et nécessitera un redémarrage du serveur de développement. Utilisons r pour redémarrer le serveur.
Note
La configuration actuelle ne fonctionnera pas comme décrit, et c'est normal. Continuez à lire pour comprendre pourquoi et voir la configuration finale.
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
}
}
Ce fichier est généré par le plugin, ne doit pas être modifié manuellement et doit être ajouté au fichier .gitignore
.
node_modules
cache
components.d.ts
Cependant, la configuration actuelle ne fonctionne pas en raison de limitations provenant de Vite. En arrière-plan, le plugin est connecté au système de surveillance des fichiers de Vite, ce qui signifie qu'il ne répond qu'aux fichiers et répertoires surveillés par Vite. Par défaut, Vite ne surveille que le répertoire root
spécifié par le srcDir
du fichier config.mts
. Par conséquent, les fichiers et répertoires dans le répertoire .vitepress
ne sont pas détectés par Vite et le plugin.
Pour résoudre ce problème, nous devons indiquer à Vite de surveiller le répertoire où se trouvent nos composants et pages Vue. Cela se fait en concevant un plugin compact pour mettre à jour la configuration de surveillance de Vite :
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vitepress'
const currentDir = dirname(fileURLToPath(import.meta.url))
const componentsDir = resolve(currentDir, 'theme', 'components')
const pagesDir = resolve(currentDir, 'theme', 'pages')
export default defineConfig({
srcDir: 'src',
vite: {
plugins: [
{
name: 'watcher',
configureServer(server) {
server.watcher.add([componentsDir, pagesDir])
},
},
// ...
],
},
})
Avec cet ajustement, tout devrait fonctionner comme prévu. Le plugin génère le fichier de déclaration, fournissant l'auto-complétion et le contrôle de type dans notre IDE lorsqu'un composant est créé sans avoir besoin de redémarrer le serveur de développement.
Tout à la Demande
Cette philosophie à la demande peut-elle s'étendre encore plus à tout ?
Absolument, et nous allons y parvenir en utilisant le plugin unplugin-auto-import
. Ce plugin fonctionne de manière similaire au plugin unplugin-vue-components
mais pour les fichiers JavaScript et TypeScript.
Tout d'abord, nous devons installer le plugin :
pnpm add -D unplugin-auto-import
Ensuite, configurons le plugin dans le fichier config.mts
:
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import AutoImport from 'unplugin-auto-import/vite'
import { defineConfig } from 'vitepress'
const currentDir = dirname(fileURLToPath(import.meta.url))
// ...
const composablesDir = resolve(currentDir, 'theme', 'composables')
const utilsDir = resolve(currentDir, 'theme', 'utils')
export default defineConfig({
srcDir: 'src',
vite: {
plugins: [
{
name: 'watcher',
configureServer(server) {
// ...
server.watcher.add([composablesDir, utilsDir])
},
},
AutoImport({
imports: ['vue', 'vitepress'],
dirs: [composablesDir, utilsDir],
dts: resolve(currentDir, 'auto-imports.d.ts'),
}),
// ...
],
},
})
Avec cette configuration, nous atteignons trois objectifs :
- Importer automatiquement toutes les fonctions composables et utilitaires depuis
vue
etvitepress
, permettant l'utilisation deref
,computed
,useData
, etc., sans importations explicites. - Scanner et enregistrer toutes les fonctions composables et utilitaires dans les répertoires
theme/composables
ettheme/utils
. - Permettre au système de surveillance de surveiller les répertoires
theme/composables
ettheme/utils
, de la même manière que le pluginunplugin-vue-components
.
Ce plugin génère un fichier auto-imports.d.ts
pour les mêmes raisons que le fichier components.d.ts
. Il doit également être ajouté au fichier .gitignore
.
node_modules
cache
components.d.ts
auto-imports.d.ts
Scripts
Pour conclure cet article, supprimons le préfixe docs:
de nos scripts dans le fichier package.json
. Comme nous ne créons pas de documentation, et que VitePress est le seul projet dans le dépôt, nous pouvons éliminer en toute sécurité ce préfixe.
{
"scripts": {
"dev": "vitepress dev",
"build": "vitepress build",
"preview": "vitepress preview"
}
}
Excellent ! Nous avons maintenant une structure de projet propre et organisée, prête à commencer notre entreprise de blogging. Dans l'article suivant, nous développerons la liste de blog et tirerons parti d'une des fonctionnalités clés de VitePress : le chargeur de données.