Outillage
Technologies utilisées
| Outil | Rôle dans SIA UI |
|---|---|
| TypeScript | Sécurise les API publiques et les composants installés |
| React | Moteur de rendu ciblé par @sia-ui/react et le registre |
| pnpm workspaces | Lie les packages locaux et partage les dépendances |
| Turborepo | Orchestre build, tests et typecheck entre packages |
| tsup | Produit les bundles ESM, CommonJS et déclarations TypeScript |
| Vitest | Exécute les tests unitaires rapides |
| CSS variables | Transporte les tokens et permet les thèmes dynamiques |
| Mermaid | Documente les flux et dépendances dans les fichiers Markdown |
Pipeline local
Commandes
| Commande | Utilité |
|---|---|
pnpm install | Synchroniser le workspace et le lockfile |
pnpm typecheck | Vérifier tous les contrats TypeScript, templates du registre compris |
pnpm test | Exécuter les tests de chaque package |
pnpm build | Générer les packages distribuables |
pnpm preview | Lancer le catalogue visuel Vite |
pnpm storybook | Lancer Storybook pour les composants isolés |
pnpm clean | Supprimer les artefacts de build |
pnpm check:deps | Vérifier qu'aucun paquet publié n'a de dépendance tierce |
pnpm changeset | Décrire un changement à publier |
pnpm release | Construire et publier sur npm |
pnpm sia -- list | Inspecter le registre local |
Portée du typage
pnpm typecheck couvre les sources des packages et les templates du registre. Les fichiers copiés chez l'utilisateur sont le produit réellement distribué: ils doivent être vérifiés comme le reste.
// packages/registry/tsconfig.json
{
"include": ["src/**/*.ts", "templates/**/*.ts", "templates/**/*.tsx"]
}Une entrée ajoutée au registre sans passer tsc ne doit pas être publiée.
Formats produits
ESM couvre les bundlers modernes, CommonJS conserve une compatibilité Node et les fichiers .d.ts fournissent l'autocomplétion et la validation aux projets.
Un seul jeu d'options de build
tsup.preset.ts, à la racine, porte les options communes aux sept paquets construits par tsup. Chaque tsup.config.ts ne déclare plus que ce qui lui est propre — son entry, ses external :
import { preset } from "../../tsup.preset";
export default preset({ entry: ["src/index.ts"], external: ["react"] });Une décision de build se prend donc une fois. Pas de sourcemaps en est l'exemple : les cartes pesaient environ soixante pour cent de chaque archive npm — @sia-ui/react-web passait de 2,1 Mo à 759 Ko en les retirant — pour du code que personne ne débogue depuis dist. Un projet qui veut remonter à la source lit les .d.ts ou installe le composant par le registre, où il reçoit le fichier TypeScript lui-même.
La licence voyage avec le paquet
npm n'emporte que ce qui vit dans le dossier du paquet : une LICENSE à la racine du dépôt n'arrive jamais dans l'archive. Chaque paquet publié en porte donc une copie, listée dans son champ files — mais aucune n'est écrite à la main. pnpm sync:license les régénère depuis le fichier racine, seule source, et pnpm check:license échoue sur la moindre dérive. La CI le lance juste après le garde-fou des dépendances.
Le journal est visible sur npm
Chaque paquet garde son CHANGELOG.md, généré par Changesets, et le publie dans son archive npm. Le même contenu est aussi recopié dans le README.md du paquet sous Journal des changements, parce que npm affiche d'abord le README. pnpm changeset:version lance pnpm sync:changelogs après avoir généré les versions. pnpm release contrôle ensuite la copie et refuse la publication si un README a dérivé de son changelog.
Tests de montage
@sia-ui/react-web monte chacun de ses composants exportés et vérifie qu'il tient debout. C'est délibérément grossier : rien n'est asserté sur ce qui s'affiche.
pnpm --filter @sia-ui/react-web testCe garde-fou existe parce que typecheck dit qu'un composant compile et Storybook qu'il se bundle — ni l'un ni l'autre ne le rend. Après une migration qui a déplacé 88 fichiers, réécrit leurs imports et découpé leur feuille de style, c'est exactement ce qui manquait.
Deux fichiers portent la mécanique :
src/smoke.test.tsxparcourt les exports du barrel et monte tout ce qui commence par une majuscule;src/smoke-props.tsdéclare les props minimales de ceux qui en exigent. Une entrée ajoutée là est une information : ce composant a une prop obligatoire, et laquelle.
Les sous-composants d'un ensemble composé — Radio, TabsTrigger — lèvent volontairement hors de leur parent. Ils sont listés comme non montables seuls : c'est un bon comportement, pas un défaut.
src/config.test.tsx couvre ensuite ce que la refonte du fournisseur a changé : une valeur par défaut qui traverse l'arbre, une prop explicite qui gagne sur elle, un libellé traduit, le repli sur le français et la composition de deux fournisseurs imbriqués.
Ajouter un composant
Rien à faire : le test le ramasse depuis le barrel. S'il a une prop obligatoire, l'ajouter à MINIMAL_PROPS — le test le dira.
Lint
ESLint couvre tout le workspace depuis une configuration unique, eslint.config.mjs. Les règles qui demandent le type checker en sont volontairement absentes : elles doubleraient le temps d'exécution pour signaler ce que tsc voit déjà, et typecheck tourne de toute façon.
Deux assouplissements assumés :
no-consoleest levé pour l'outillage et la CLI — écrire sur la sortie standard est leur rôle, pas une trace de débogage oubliée;react-hooks/rules-of-hooksest levé dans les stories : la fonctionrenderd'une story est un composant, mais la règle ne juge que le nom.
react-hooks/exhaustive-deps ne produit plus aucun avertissement dans react, react-web et headless, et doit le rester : les composants sont copiés dans des projets qui lancent leur propre lint, et chaque avertissement devient le leur. Une valeur lue par un écouteur ou un intervalle sans devoir le relancer passe par une ref mise à jour au rendu (latest.current = …), l'idiome de useLocalForm et SearchInput — useEffectEvent demanderait React 19.2, les paquets acceptent 18.2.
Les règles du React Compiler (react-hooks/refs, purity, set-state-in-effect) ne sont pas activées ici ; elles le sont chez qui utilise la configuration recommended du plugin en version 7 — voir Ce que le projet hôte doit fournir.
Publication
Les huit paquets publiés portent toujours le même numéro : ils sont déclarés fixed dans .changeset/config.json. Un changeset sur un seul d'entre eux fait sortir les huit, à la même version. Un utilisateur installe @sia-ui/react-web et @sia-ui/headless côte à côte, et deux numéros différents ne lui apprendraient rien.
Le mode linked, utilisé jusqu'à la 0.7.1, alignait seulement les paquets modifiés : un paquet inchangé restait en arrière, et un changement sur un paquet en retard le faisait sauter au-delà des autres. fixed supprime les deux cas.
pnpm changeset # décrire le changement
pnpm changeset:version # versions + CHANGELOG
pnpm release # build puis publishTout est en 0.x tant que les arbitrages restants ne sont pas rendus. Voir Source unique des composants.
Garde-fou des dépendances
pnpm check:deps échoue si un paquet publié déclare une dépendance de production autre que @sia-ui/*. C'est la règle du §04 rendue mécanique : SIA UI se branche sur les librairies d'une application, il n'en embarque aucune.
La CI l'exécute avant le lint : c'est la vérification la plus rapide et la plus structurante.