Skip to content

FSHSP-109 feat(schematics): starter to copy ui-kit components into the consumer project - #37

Merged
LBU4SH merged 6 commits into
mainfrom
feat/fshsp-109-schematics-starter
Aug 14, 2026
Merged

FSHSP-109 feat(schematics): starter to copy ui-kit components into the consumer project#37
LBU4SH merged 6 commits into
mainfrom
feat/fshsp-109-schematics-starter

Conversation

@LBU4SH

@LBU4SH LBU4SH commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Implémente FSHSP-109 : permettre à un projet Angular de copier les composants du kit dans son code source et de les posséder, à la manière de shadcn/ui ou spartan-ng, plutôt que de consommer @4sh/ui-kit en dépendance figée.

Ce que ça donne côté consommateur

ng add @4sh/ui-kit                    # fondation : styles, tokens, angular.json
ng generate @4sh/ui-kit:add           # sélection interactive (a = tout)
ng generate @4sh/ui-kit:add --all     # sans prompt
ng generate @4sh/ui-kit:update        # diff par composant : appliquer / ignorer

Un seul nom à retenir. add résout les dépendances entre composants (ui-select entraîne ui-icon, ui-field, ui-spinner, ui-label, ui-helper + les bases partagées) par analyse des imports, sans liste à maintenir. Chaque fichier copié porte son origine en en-tête, et ui-kit.json recense l'installé.

ng add embarque aussi la chaîne de génération des tokens (JSON + tokens.config.json + tokens.build.mjs + style-dictionary) : un projet peut rebrander sans attendre une release du kit.

Rien ne change pour un consommateur classique de @4sh/ui-kit : les sources brutes restent hors du package compilé.

Le prérequis technique, vérifié en premier

ng-packagr inline template et SCSS dans le .mjs publié — les sources que le starter doit copier n'existent pas dans le tarball du kit. D'où un package compagnon @4sh/ui-kit-schematics, alimenté depuis projects/ui-kit/ au build (aucune duplication à maintenir), et une façade de ~40 lignes dans le kit qui ne contient aucune logique et délègue.

ng-add ne peut pas appeler le compagnon directement (pas encore installé) : il inscrit la devDependency, programme l'installation, puis enchaîne via RunSchematicTask — le pattern d'@angular/material. add/update délèguent en direct par externalSchematic, ce qui garde le prompt interactif au premier plan (vérifié).

Vérifications

Le parcours a été exécuté, pas relu :

  • 63/63 SCSS de composants copiés compilent contre l'arborescence consommateur
  • pipeline de tokens réellement régénéré vers src/styles/ui-kit/generated/
  • prompt interactif piloté sous un vrai PTY : a (53 composants → 58 unités), sélection partielle, sélection vide
  • ng-add idempotent sur un workspace ng new : pas de doublon dans styles/includePaths, scaffolds édités préservés
  • façade testée contre les packages construits, compagnon présent et absent

Ces exécutions ont débusqué quatre bugs qu'une relecture n'aurait pas montrés :

Bug Conséquence évitée
barrel styles/utils.scss non copiée (fichier racine, pas dans utils/) aucun composant copié n'aurait compilé
tokens.config.json pointant projects/ui-kit/styles/generated tokens régénérés au mauvais endroit
message d'erreur de la façade en code mort (externalSchematic résout à l'exécution) Collection "..." cannot be resolved. sans quoi faire
version du compagnon désalignée (0.1.0 vs ^0.1.2) ng add en échec à l'installation

Publication

Les deux packages partent ensemble, sous le même numéro (estampillé depuis le kit à l'assemblage) : la façade réclame le compagnon en ^<version du kit>.

Le compagnon est publié avant le kit, délibérément : npm n'a pas de transaction, et un compagnon orphelin est inerte là où un kit sans compagnon serait cassé pour tous, irrattrapable passé 72 h. Le raisonnement est en commentaire dans le workflow.

⚠️ Une action manuelle avant la première release

@4sh/ui-kit-schematics n'existe pas encore sur npm, et Trusted Publishing ne se déclare que sur un package déjà présent sur le registre. Sa première publication doit passer par un token — comme la 0.1.0 du kit — puis déclarer le Trusted Publisher et révoquer le token. Procédure dans docs/PUBLISHING.md.

Lancer le workflow avant d'avoir fait ça est sans danger : l'ordre retenu fait échouer le compagnon avant que le kit ne parte.

Hors périmètre

Versionnage par composant : non prévu, les deux packages sont en lockstep sur la version du kit. Le manifeste garde une entrée par composant, ce qui suffit à rendre update sélectif.

LBU4SH added 6 commits August 14, 2026 16:42
… package

- schematics-assets.build.mjs: copies raw component/style/token-pipeline
  sources from projects/ui-kit/ into assets/, ahead of ng-packagr's AOT
  build (which inlines templates/styles and strips the sources needed
  by ng-add/add/update).
- projects/ui-kit-schematics/: ng-add, add, update schematics.
  Dependency resolution between components is derived by static parsing
  of existing @4sh/ui-kit/* imports, not hand-maintained.
- schematics-package.build.mjs assembles the publishable dist/ output.
- npm scripts: schematics:assets, schematics:build, schematics:pack.

add and update verified end-to-end via SchematicTestRunner.
… the consumer layout

ng-add end-to-end test surfaced that the embarked tokens.config.json still
pointed outputs at projects/ui-kit/styles/generated (the monorepo path).
schematics-assets.build.mjs now rewrites outputs[].destination to
src/styles/ui-kit/generated at copy time. Verified by actually running the
copied scripts/tokens.build.mjs against a scratch consumer directory.
…e angular.json

ng-add now completes the consumer's style setup:
- main.scss / variables.scss scaffolds, created once then left editable
  (main.scss takes over the role of the kit's index.scss).
- angular.json: appends the global sheet, FontAwesome and the CDK overlay
  css to styles, and the includePaths the components' bare @use specifiers
  need. Goes through updateWorkspace so comments and layout survive.
- adds @fortawesome/fontawesome-free (referenced by the styles entry, but
  not a kit peerDependency since ui-icon only emits CSS classes) and
  style-dictionary, the engine behind the copied tokens.build.mjs.

Also fixes the assets build missing styles/utils.scss: it sits at the root
of styles/, not inside utils/, so the directory-only copy skipped it — and
it is the barrel all 57 component stylesheets resolve '@use utils' against.

Verified by compiling the scaffolded main.scss and all 63 copied component
stylesheets against the consumer layout (63 OK, 0 failures), plus a re-run
of ng-add over a ng new workspace: no duplicate styles/includePaths
entries, edited scaffolds preserved.
…from the manifest

Per-component versions are not planned: the kit carries a single version
(docs/VERSIONING.md), so stamping the kit version on each entry is the
intended behaviour, not a shortfall. The per-component entry still earns
its place — it is what makes update selective and records what was copied.
…a a ui-kit facade

Consumers now only ever type @4sh/ui-kit:

  ng add @4sh/ui-kit
  ng generate @4sh/ui-kit:add
  ng generate @4sh/ui-kit:update

The kit ships a collection.json plus a ~40-line CommonJS facade that holds
no logic and delegates to @4sh/ui-kit-schematics, so the raw component
sources stay out of the runtime package.

- ng-add cannot call the companion directly (not installed yet), so it
  writes the devDependency, schedules the install, and queues the
  companion's ng-add as a task depending on it — the @angular/material
  pattern. add/update delegate synchronously via externalSchematic, which
  keeps the interactive prompt in the foreground.
- .cjs and explicit extensions in collection.json are required: ng-packagr
  stamps "type": "module" on the published package, and CommonJS
  extensionless resolution never tries .cjs.
- "ng-add": { "save": "devDependencies" } keeps the kit out of the
  consumer's runtime dependencies, as the ticket requires.
- the companion's published version is stamped from the kit's at assembly
  time: the facade requests ^<kit version>, so a version of its own could
  fall outside that range and break ng add.
- facade schemas are copied from the companion rather than rewritten, so an
  option added on one side cannot be silently dropped by the other.

Verified against the built packages: ng-add queues node-package then
run-schematic with the right collection, add/update delegate and copy, and
a missing companion now reports how to fix it (the first attempt caught
nothing — externalSchematic resolves when the rule runs, not when it is
built).
The starter needs both packages at the same version: the kit's ng-add
facade requests the companion as ^<kit version>, so shipping one without
the other breaks ng add. The workflow now builds both, fails the dry run
on a version mismatch, and publishes them from the same approved job.

The companion is published FIRST, deliberately. npm has no transaction, so
the order decides what a half-published release leaves behind: an orphan
companion is inert, while a kit published without its companion is broken
for every consumer and unfixable after npm's 72h unpublish window.

Docs updated for the second package: Trusted Publisher must be declared on
each package page, and since @4sh/ui-kit-schematics is not on the registry
yet, its first publish cannot use OIDC — it needs a one-off token, exactly
as the kit's 0.1.0 did. Also documents the ng-packagr constraints behind
the .cjs facade and the fact that the companion's own version field is
overwritten at assembly.

CHANGELOG entry written from the consumer's side: what they type, what
they get, and that nothing changes for plain @4sh/ui-kit users.
@LBU4SH
LBU4SH merged commit 2f25acb into main Aug 14, 2026
2 of 3 checks passed
@LBU4SH
LBU4SH deleted the feat/fshsp-109-schematics-starter branch August 14, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant