Créer un Playground et un Storybook pour les Composants

- Read in english
Ressources: huchet-vue

Nous avons des composants et des tests, mais jusqu'à présent, nous n'avons pas pu les voir en action. Il est temps de créer un playground pour deux raisons principales :

  1. Tests : Nous devons tester nos composants dans un environnement réel pour nous assurer qu'ils fonctionnent comme prévu. Écrire une page avec tous les composants, leurs props et slots aide à créer la meilleure API et à l'implémenter efficacement. Cette approche minimise les refactorisations fréquentes en fournissant une vue d'ensemble des composants.
  2. Visualisation : La visualisation des composants est essentielle. Bien que Tailwind CSS simplifie le style, il est impossible de bien saisir un composant par le code, en particulier les composants complexes avec de nombreuses variantes ou slots. Un playground nous permet de voir les composants en action et de les tester dans divers scénarios.

Configuration du Playground

Tout d'abord, créez un nouveau dossier nommé playground à la racine de votre projet.

bash
mkdir playground

Ensuite, créez un nouveau projet Vite dans ce dossier, qui dépendra de notre bibliothèque de composants. Être dans un monorepo simplifie ce processus.

bash
cd playground && pnpm create vite --template vue-ts

Nommez ce projet vue.

Avant d’installer les dépendances, mettez à jour le pnpm-workspace.yaml pour inclure le package playground/vue. Cela permet au playground d'accéder à la bibliothèque de composants.

yaml
packages:
  - 'packages/*'
  - 'playground/*'

Installez les dépendances du playground :

bash
pnpm install

Dans ce playground Vue.js, supprimez les fichiers, dossiers et contenus inutiles :

bash
rm -rf .vscode .public src/{assets,components}
echo "<template></template>" > src/App.vue
echo "" > src/style.css

Supprimez le dossier .vscode, le dossier public, les dossiers assets et components dans src, ainsi que le contenu de App.vue et style.css.

Maintenant, installez la bibliothèque de composants dans le playground :

bash
pnpm add ../../packages/huchet-vue

Cette commande installe la bibliothèque de composants en créant un lien symbolique vers celle-ci dans node_modules. Ainsi, toute importation effectuée dans le playground résout la bibliothèque de composants dans le monorepo, permettant des modifications en temps réel pendant le développement.

Démarrez le script de surveillance dans le dossier du package huchet-vue et le script de développement dans le dossier playground/vue. Tout changement dans la bibliothèque de composants se reflétera dans le playground.

Utilisation du Playground

Avec la bibliothèque de composants installée dans le playground, vous pouvez commencer à l'utiliser.

Dans le fichier src/App.vue, importez le composant Button et utilisez-le :

vue
<script lang="ts" setup>
import { Button } from '@barbapapazes/huchet-vue'
</script>

<template>
  <div class="flex gap-6 p-6">
    <Button label="Hello World" />
    <Button label="Hello World" variant="outline" />
  </div>
</template>

Pour voir le résultat, démarrez Vite dans le playground :

bash
pnpm dev

Ensuite, démarrez Vite dans la bibliothèque de composants :

bash
pnpm watch

Important

Plus votre bibliothèque contient de composants, plus il faudra de temps pour refléter les changements dans le playground. Si cela commence à ralentir, envisagez d'importer directement le composant depuis la bibliothèque avec un chemin relatif ou d'utiliser un storybook comme Histoire, que nous allons aborder ensuite.

Dans votre navigateur, vous devriez voir deux boutons, non stylisés.

Deux boutons, non stylisés.
Deux boutons, non stylisés.

Styliser le Playground

Nos composants sont non stylisés. Pour réduire la taille du bundle et permettre la génération côté utilisateur, nous ne fournissons pas de CSS avec la bibliothèque de composants.

Note

Nous pourrions expédier une configuration Tailwind CSS avec la bibliothèque de composants pour garantir que les composants sont correctement stylés dans le playground.

Nous allons utiliser Tailwind CSS 4, même s'il n'est pas encore sorti, car il est accompagné d'un plugin Vite qui simplifie son utilisation et aucun autre changement cassant n'est attendue.

bash
pnpm i -D tailwindcss@next @tailwindcss/vite@next

Ensuite, enregistrez le plugin Tailwind CSS dans le fichier vite.config.ts :

ts
import Tailwindcss from '@tailwindcss/vite'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    Vue(),
    Tailwindcss(), 
  ],
})

Dans le src/style.css, importez les styles Tailwind CSS :

css
@import "tailwindcss";

Automatiquement, les boutons sont stylés comme prévu.

Deux boutons, stylisés.
Deux boutons, stylisés.

Le Storybook Histoire

Parfois, un playground ne suffit pas. Vous avez besoin de documenter vos composants, de les visualiser dans divers scénarios et de les isoler pour vous assurer que les problèmes proviennent du composant et non de l'intégration. C'est ici qu'un storybook entre en jeu.

Nous allons utiliser Histoire, un outil similaire à Storybook qui est léger, basé sur Vite et optimisé pour Vue.js.

Configuration de Histoire

La configuration de Histoire est simple, surtout avec Tailwind CSS 4.

Tout d'abord, créez un nouveau dossier depuis la racine du projet :

bash
mkdir .histoire && cd .histoire && echo '{\n"name": "huchet-vue-histoire",\n"private": true\n}' > package.json

Note

J'ai placé le dossier Histoire à la racine du projet au lieu du dossier packages car c'est un outil de développement, et non un package npm publiable.

Ajoutez le dossier au workspace :

bash
echo "  - .histoire" >> ../pnpm-workspace.yaml

Installez Histoire et Tailwind CSS :

bash
pnpm i -D histoire @histoire/plugin-vue @vitejs/plugin-vue vue tailwindcss@next @tailwindcss/vite@next

Note

Nous installons maintenant Tailwind CSS car nous en aurons besoin, comme nous l'avons vu dans le playground.

Histoire utilise un fichier de configuration nommé histoire.config.ts, que nous allons créer dans le dossier .histoire :

bash
touch histoire.config.ts

La configuration comprend plusieurs clés :

  • plugins : Plugins pour Histoire, comme le plugin Vue Histoire.
  • storyMatch : Fichiers à correspondre pour créer des histoires, comme les fichiers *.story.vue.
  • setupFile : Fichier de configuration à utiliser avec Histoire, où nous allons créer un setup.ts.
  • theme : Options de personnalisation comme le titre, le logo, le favicon pour l'interface Histoire.
  • vite : Configuration Vite utilisant les plugins Vue et Tailwind CSS.
ts
import { resolve } from 'node:path'
import { HstVue } from '@histoire/plugin-vue'
import Tailwind from '@tailwindcss/vite'
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'histoire'

export default defineConfig({
  plugins: [HstVue()],

  storyMatch: [
    resolve(__dirname, '../packages/huchet-vue/src/**/*.story.vue'),
  ],

  setupFile: resolve(__dirname, 'setup.ts'),

  theme: {
    title: 'Huchet Vue',
  },

  vite: {
    plugins: [
      Vue(),
      Tailwind(),
    ],
    server: {
      fs: {
        allow: ['..'],
      },
    },
  },
})

Puisque les histoires se trouvent dans la bibliothèque de composants, nous devons explicitement indiquer à Histoire de les chercher dans le dossier packages/huchet-vue/src à l'aide de la clé storyMatch. Pendant ce temps, nous permettons au serveur Histoire d'accéder au dossier parent via la clé server.fs.allow, empêchant ainsi les problèmes d'accessibilité aux fichiers.

Pour implémenter Tailwind CSS dans Histoire, importez le CSS dans le fichier setup.ts, de la même manière que dans le playground :

bash
touch setup.ts style.css
echo "import './style.css';" > setup.ts
echo "@import 'tailwindcss';" > style.css

Note

Le fichier setup.ts est exécuté au démarrage de Histoire et est un endroit idéal pour la personnalisation ou les styles globaux.

Pour commencer avec Histoire, ajoutez trois scripts au package.json :

json
{
  "scripts": {
    "dev": "histoire dev",
    "build": "histoire build",
    "serve": "histoire serve"
  }
}

Maintenant, nous pouvons démarrer Histoire :

bash
pnpm dev
Histoire en cours d'exécution.
Histoire en cours d'exécution.

Création d'une Histoire

En revenant à packages/huchet-vue, nous pouvons créer notre premier fichier d'histoire, Button/Button.story.vue :

bash
touch src/Button/Button.story.vue

Histoire propose des composants prédéfinis pour créer une histoire avec des variantes.

  1. Story : Le composant principal pour créer une histoire.
  2. Variant : Un composant pour créer une variante d'un composant au sein de l'histoire.

Dans notre scénario, nous créons une histoire dans Button.story.vue avec deux variantes : solid et outline.

vue
<script lang="ts" setup>
import { logEvent } from 'histoire/client'
import Button from './Button.vue'
</script>

<template>
  <Story>
    <Variant title="Solid">
      <Button variant="solid" label="Hello World" @click="logEvent('Click', $event)" />
    </Variant>
    <Variant title="Outline">
      <Button variant="outline" label="Hello World" @click="logEvent('Click', $event)" />
    </Variant>
  </Story>
</template>

Note

La fonction logEvent enregistre les événements dans l'interface, aidant les développeurs à comprendre la sortie du composant.

Et cela fonctionne !

Histoire avec le composant Button.
Histoire avec le composant Button.

Cependant, un problème majeur persiste : les composants Story et Variant ne sont pas reconnus par notre éditeur.

Ajout des Types Histoire

Heureusement, nous pouvons résoudre ce problème facilement car Histoire fournit les outils nécessaires.

Histoire introduit un nouveau contexte TypeScript dans notre projet, nous devons donc créer un nouveau fichier TSConfig dans le dossier packages/huchet-vue :

bash
touch tsconfig.story.json

Ce fichier étend tsconfig.app.json mais capture uniquement les fichiers story.vue et un nouveau fichier histoire.d.ts :

json
{
  "extends": "./tsconfig.app.json",
  "compilerOptions": {
    "moduleResolution": "node"
  },
  "include": [
    "histoire.d.ts",
    "src/**/*.story.vue"
  ],
  "exclude": []
}

Note

L'option moduleResolution est essentielle pour une résolution correcte des modules. Le package @vue/tsconfig utilise Bundler, mais nous avons besoin de Node pour notre cas d'utilisation. Assurez-vous que "exclude": [] écrase l'option exclude dans tsconfig.app.json.

Créez le fichier histoire.d.ts :

bash
touch histoire.d.ts

Référencez les types d'Histoire dans ce fichier :

ts
/// <reference types="@histoire/plugin-vue/components" />

Enregistrez le nouveau TSConfig dans le tsconfig.json :

json
{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.node.json"
    },
    {
      "path": "./tsconfig.story.json"
    }
  ]
}

Mettez à jour tsconfig.app.json avec une option exclude pour éviter la capture de TSConfig qui se chevauche :

json
{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": [
    "src/**/*.ts",
    "src/**/*.vue"
  ],
  "exclude": [
    "src/**/*.story.vue"
  ]
}

Note

Les captures TSConfig qui se chevauchent peuvent entraîner des comportements inattendus et de nombreux problèmes. Assurez-vous de définir des limites claires entre les TSConfigs pour éviter des conflits.

Dans le prochain article, nous améliorerons l'intégration avec l'écosystème Vue.js en créant un résolveur pour Unplugin Vue Component et un module Nuxt.

Photo de profil d'Estéban

Merci de me lire ! Je m'appelle Estéban, et j'adore écrire sur le développement web.

Je code depuis plusieurs années maintenant, et j'apprends encore de nouvelles choses chaque jour. J'aime partager mes connaissances avec les autres, car j'aurais aimé avoir accès à des ressources aussi claires et complètes lorsque j'ai commencé à apprendre la programmation.

Si vous avez des questions ou souhaitez discuter, n'hésitez pas à commenter ci-dessous ou à me contacter sur Bluesky, X, et LinkedIn.

J'espère que vous avez apprécié cet article et appris quelque chose de nouveau. N'hésitez pas à le partager avec vos amis ou sur les réseaux sociaux, et laissez un commentaire ou une réaction ci-dessous—cela me ferait très plaisir ! Si vous souhaitez soutenir mon travail, vous pouvez me sponsoriser sur GitHub !

Continue readingAméliorer l'intégration avec Unplugin et Nuxt Module