docs(modules): update module structure to reflect tsup build workflow
- fix entry point path from `index.js` to `src/index.js` compiled to `dist/index.js` - update file tree to show `src/` as source root and `dist/` as published output - update `package.json` example with correct `main`, `exports`, `files`, and build scripts - add explanation of mandatory pre-build step before publish - document why JSX must be compiled (turbopackIgnore + Node native resolution) - add minimal `tsup.config.js` example with `bundle: false` and JSX loader - add verification step to check compiled output before publishing
This commit is contained in:
+56
-24
@@ -30,7 +30,7 @@ Pour chaque module trouvé, le core vérifie qu'il exporte les bons symboles, pu
|
|||||||
Le point d'entrée du package (`main` ou `exports["."]`) doit exporter :
|
Le point d'entrée du package (`main` ou `exports["."]`) doit exporter :
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// @zen/module-blog/index.js
|
// @zen/module-blog/src/index.js (compilé vers dist/index.js par tsup)
|
||||||
|
|
||||||
export const manifest = {
|
export const manifest = {
|
||||||
name: '@zen/module-blog',
|
name: '@zen/module-blog',
|
||||||
@@ -221,38 +221,70 @@ Toute variable requise par le module doit être déclarée dans `manifest.envVar
|
|||||||
|
|
||||||
```
|
```
|
||||||
@zen/module-blog/
|
@zen/module-blog/
|
||||||
├── package.json # name: "@zen/module-blog", main: "./index.js"
|
├── package.json # name: "@zen/module-blog", main: "./dist/index.js"
|
||||||
|
├── tsup.config.js # build avec bundle: false, loader JSX, outbase: 'src'
|
||||||
├── README.md # documente les env vars et la configuration
|
├── README.md # documente les env vars et la configuration
|
||||||
├── index.js # exporte manifest, register, createTables, dropTables
|
├── src/
|
||||||
└── src/
|
│ ├── index.js # exporte manifest, register, createTables, dropTables
|
||||||
├── db.server.js # createTables/dropTables
|
│ ├── db.server.js # createTables/dropTables
|
||||||
├── register-server.js # imports déclencheurs (chargé par register())
|
│ ├── register-server.js # imports déclencheurs (chargé par register())
|
||||||
├── api.server.js # routes API (registerApiRoutes)
|
│ ├── api.server.js # routes API (registerApiRoutes)
|
||||||
├── admin/
|
│ ├── admin/
|
||||||
│ ├── BlogAdminPage.client.js # registerPage + composant
|
│ │ ├── BlogAdminPage.client.js # registerPage + composant
|
||||||
│ └── widgets/... # registerWidgetFetcher + registerWidget
|
│ │ └── widgets/... # registerWidgetFetcher + registerWidget
|
||||||
└── public/
|
│ └── public/
|
||||||
└── BlogPublicPage.js # registerPublicModulePage
|
│ └── BlogPublicPage.js # registerPublicModulePage
|
||||||
|
└── dist/ # généré par `npm run build` — c'est ce qui est publié
|
||||||
```
|
```
|
||||||
|
|
||||||
Tout le code du module vit dans `src/`. Seul `index.js` reste à la racine — c'est le point d'entrée public lu par le core via `main: "./index.js"`. Il importe depuis `./src/` :
|
Le champ `files` dans `package.json` publie **uniquement** `dist/`, `README.md` et `LICENSE` :
|
||||||
|
|
||||||
```js
|
|
||||||
// index.js
|
|
||||||
export async function register() {
|
|
||||||
await import('./src/register-server.js');
|
|
||||||
}
|
|
||||||
export { createTables, dropTables } from './src/db.server.js';
|
|
||||||
```
|
|
||||||
|
|
||||||
Le champ `files` dans `package.json` publie uniquement `index.js`, `src/`, `README.md` et `LICENSE` :
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"files": ["index.js", "src", "README.md", "LICENSE"]
|
{
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"exports": { ".": { "import": "./dist/index.js" } },
|
||||||
|
"files": ["dist", "README.md", "LICENSE"],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsup",
|
||||||
|
"prepublishOnly": "npm run build"
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Build obligatoire avant publish
|
||||||
|
|
||||||
|
**Tout module `@zen/module-*` doit être pré-compilé avant publication.** Les fichiers du module ne doivent jamais contenir de JSX brut au runtime — le JSX doit être transformé en `React.createElement` (ou équivalent) par le build du module lui-même.
|
||||||
|
|
||||||
|
**Pourquoi.** Le core découvre les modules via `import(/* turbopackIgnore */ name)` dans [`discover.server.js`](../src/core/modules/discover.server.js) ; le commentaire `turbopackIgnore` est nécessaire pour empêcher Turbopack/Webpack de tenter de bundler un nom de package dynamique. Conséquence : tout l'arbre d'imports transitifs du module est résolu et exécuté par Node natif, **sans** transformation JSX. Un fichier `.client.js` qui contient `<MyComponent />` au runtime fait planter `register()` avec `Unexpected token '<'`.
|
||||||
|
|
||||||
|
Le module doit donc utiliser le même setup que `@zen/core` : un build `tsup` avec `bundle: false`, qui transforme JSX → JS standard tout en préservant la structure de fichiers (un fichier d'entrée → un fichier de sortie). Le `'use client'` est conservé en haut des fichiers `.client.js` compilés, ce qui permet à Next.js de respecter les frontières RSC quand le projet consommateur bundle le module.
|
||||||
|
|
||||||
|
### Exemple de `tsup.config.js` minimal
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { defineConfig } from 'tsup';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/**/*.js', 'src/**/*.jsx'],
|
||||||
|
format: ['esm'],
|
||||||
|
outDir: 'dist',
|
||||||
|
outbase: 'src',
|
||||||
|
bundle: false,
|
||||||
|
splitting: false,
|
||||||
|
clean: true,
|
||||||
|
loader: { '.js': 'jsx' },
|
||||||
|
jsx: 'automatic',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vérifier qu'un module est correctement compilé
|
||||||
|
|
||||||
|
Avant `npm publish`, ouvrir `dist/` et confirmer qu'aucun fichier ne contient de syntaxe JSX brute (chercher `<` suivi d'une majuscule). Tous les composants doivent apparaître sous forme d'appels `jsx(...)` ou `React.createElement(...)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Cycle de vie complet
|
## Cycle de vie complet
|
||||||
|
|
||||||
| Étape | Côté core | Côté module |
|
| Étape | Côté core | Côté module |
|
||||||
|
|||||||
Reference in New Issue
Block a user