docs(modules): add client manifest generation and update discovery docs

- introduce `OUTPUT_CLIENT` constant and `renderClientManifest` for `'use client'` bundle
- rename `renderManifest` to `renderServerManifest` for clarity
- update `sync` command to write both server and client manifests
- update `findInstalledModuleNames` to support custom package path resolution
- rewrite MODULES.md to explain dual-manifest architecture and client hydration rationale
This commit is contained in:
2026-04-25 14:34:43 -04:00
parent c793bc418c
commit 1b85d6fac7
3 changed files with 76 additions and 20 deletions
+15 -8
View File
@@ -15,24 +15,31 @@ Aucun fichier de configuration manuelle. La plateforme découvre les modules par
## Découverte
Les modules sont activés via un **manifeste statique** généré par la CLI `zen-modules sync` dans le projet consommateur, à `app/.zen/modules.generated.js`. Ce fichier contient des `import * as ...` pour chaque package détecté et appelle `register()` au top level :
Les modules sont activés via deux **manifestes statiques** générés par la CLI `zen-modules sync` dans le projet consommateur :
- `app/.zen/modules.generated.js` — manifeste serveur (importé par `instrumentation.js`).
- `app/.zen/modules.client.js` — manifeste client (`'use client'`, importé par `app/layout.js`).
Les deux fichiers contiennent les mêmes `import * as ... from '@zen/module-X'` mais déclenchent `register()` dans leur bundle respectif. La séparation est nécessaire parce que `app/layout.js` est un Server Component : son graphe d'imports tourne dans le bundle serveur. Pour que les `registerPage()` / `registerWidget()` peuplent aussi le registre côté browser au moment de l'hydratation, il faut un fichier `'use client'` dédié.
```js
// app/.zen/modules.generated.js — AUTO-GÉNÉRÉ
// app/.zen/modules.generated.js — AUTO-GÉNÉRÉ (serveur)
import * as m0_zen_module_posts from '@zen/module-posts';
export const modules = [
{ name: '@zen/module-posts', exports: m0_zen_module_posts },
];
await Promise.all(modules.map(m => m.exports.register?.()));
```
Le manifeste est importé deux fois :
- **Côté serveur** par `instrumentation.js` qui le passe à `initializeZen({ modules })`.
- **Côté client** par `app/layout.js` (side-effect import).
```js
// app/.zen/modules.client.js — AUTO-GÉNÉRÉ (client)
'use client';
import * as m0_zen_module_posts from '@zen/module-posts';
m0_zen_module_posts.register?.();
export {};
```
Cette importation statique permet à Turbopack/Webpack d'analyser le graphe complet des modules — JSX, `next/headers`, `next/navigation`, frontières `'use client'` — exactement comme pour le code de l'application elle-même.
L'importation statique (le `import * as ...`) permet à Turbopack/Webpack d'analyser le graphe complet du module — JSX, `next/headers`, `next/navigation`, frontières `'use client'` — exactement comme pour le code de l'application elle-même.
### Critères de détection