docs(tsup): update build config comments and fix jsx import extensions
This commit is contained in:
+4
-7
@@ -60,14 +60,11 @@ Ces suffixes ne sont pas cosmétiques : **le build les utilise comme source de v
|
||||
|
||||
### Source de vérité
|
||||
|
||||
`tsup.config.js` dérive ses entrées de deux sources :
|
||||
`tsup.config.js` compile **tous les fichiers `.js` et `.jsx` de `src/`** avec `bundle: false`. Chaque fichier devient un module standalone dans `dist/` ; les imports relatifs sont préservés tels quels.
|
||||
|
||||
1. `package.json#exports` — pour tous les points d'entrée publics.
|
||||
2. Un glob récursif `src/**/*.{server,client}.js` — pour le wiring interne (pages, widgets) qui doit rester en module séparé sans être public.
|
||||
|
||||
**Ajouter un module public = éditer seulement `package.json#exports`.** La liste `external` et la liste `entry` sont régénérées au prochain build. Il n'y a plus trois listes à synchroniser.
|
||||
|
||||
Les self-imports `@zen/core/*` sont générés automatiquement à partir des clés de `exports`.
|
||||
- **Ajouter un module public = éditer seulement `package.json#exports`.** L'entry list se régénère au prochain build via un walk de `src/`.
|
||||
- **Pas de bundling des fichiers internes** : les modules de registre (`registry.js`, etc.) sont des singletons — les bundler avec `bundle: true` dans un barrel créerait une copie inline distincte et casserait le partage d'état entre les pages et les widgets.
|
||||
- Les self-imports `@zen/core/*` sont générés automatiquement à partir des clés de `exports` et restent toujours dans la liste `external`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { BaseLayout } from './BaseLayout.jsx';
|
||||
export { BaseLayout } from './BaseLayout.js';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { render } from '@react-email/components';
|
||||
import { fail, info } from '@zen/core/shared/logger';
|
||||
import { sendEmail } from '@zen/core/email';
|
||||
import { VerificationEmail } from './templates/VerificationEmail.jsx';
|
||||
import { PasswordResetEmail } from './templates/PasswordResetEmail.jsx';
|
||||
import { PasswordChangedEmail } from './templates/PasswordChangedEmail.jsx';
|
||||
import { VerificationEmail } from './templates/VerificationEmail.js';
|
||||
import { PasswordResetEmail } from './templates/PasswordResetEmail.js';
|
||||
import { PasswordChangedEmail } from './templates/PasswordChangedEmail.js';
|
||||
|
||||
export { createEmailVerification, verifyEmailToken, createPasswordReset, verifyResetToken, deleteResetToken }
|
||||
from '../../core/users/verifications.js';
|
||||
|
||||
+25
-46
@@ -4,34 +4,37 @@ import { join } from 'node:path';
|
||||
|
||||
const pkg = JSON.parse(readFileSync('./package.json', 'utf8'));
|
||||
|
||||
// Source de vérité #1 : package.json#exports. Donne la liste des points
|
||||
// d'entrée publics et la liste des self-imports à marquer external.
|
||||
const exportEntries = Object.values(pkg.exports)
|
||||
.map(e => e.import).filter(Boolean)
|
||||
.map(p => p.replace('./dist/', 'src/'));
|
||||
|
||||
// Les self-imports @zen/core/* restent toujours externes — ils pointent vers
|
||||
// d'autres points d'entrée du même package, jamais vers des fichiers internes.
|
||||
const selfImports = Object.keys(pkg.exports)
|
||||
.filter(k => k !== '.' && !k.endsWith('.css'))
|
||||
.map(k => '@zen/core' + k.slice(1));
|
||||
|
||||
// Source de vérité #2 : les fichiers *.server.js et *.client.js sous src/.
|
||||
// Convention : un tel fichier est *toujours* un point d'entrée non-bundlé —
|
||||
// soit il fait partie de l'API publique (listé dans exports), soit c'est un
|
||||
// wiring interne (pages, widgets) qui doit rester un module séparé pour
|
||||
// préserver les frontières RSC / 'use client'.
|
||||
// Tous les fichiers source .js et .jsx sont compilés en module standalone
|
||||
// (bundle: false). Chaque fichier est transpilé individuellement ; les imports
|
||||
// relatifs sont préservés tels quels dans le dist.
|
||||
//
|
||||
// Pourquoi bundle: false pour tout ?
|
||||
// - Les fichiers *.server.js et *.client.js doivent rester des modules séparés
|
||||
// pour que Next.js respecte les frontières RSC / 'use client'.
|
||||
// - Les modules de registre (registry.js, etc.) sont des singletons : si un
|
||||
// barrel comme index.js bundlait registry.js avec bundle: true, il en ferait
|
||||
// une copie inline distincte de la version importée en relatif par les pages
|
||||
// et widgets — deux instances, zéro partage d'état.
|
||||
// - Tous les fichiers doivent exister dans dist pour que les imports relatifs
|
||||
// des fichiers *.server.js/*.client.js (compilés sans bundling) puissent être
|
||||
// résolus à l'exécution.
|
||||
//
|
||||
// La liste des points d'entrée publics reste définie dans package.json#exports.
|
||||
// Modifier un export public = éditer seulement package.json#exports.
|
||||
function walk(dir, out = []) {
|
||||
for (const name of readdirSync(dir)) {
|
||||
const full = join(dir, name);
|
||||
if (statSync(full).isDirectory()) walk(full, out);
|
||||
else if (/\.(server|client)\.js$/.test(name)) out.push(full);
|
||||
else if (/\.(js|jsx)$/.test(name)) out.push(full);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
const boundaryFiles = walk('src');
|
||||
|
||||
// Dédup : un chemin déclaré dans exports ET détecté par la glob ne devient
|
||||
// pas deux entrées.
|
||||
const allEntries = [...new Set([...exportEntries, ...boundaryFiles])];
|
||||
|
||||
const SHARED_EXTERNALS = [
|
||||
'react', 'react-dom', 'next',
|
||||
@@ -41,42 +44,18 @@ const SHARED_EXTERNALS = [
|
||||
...selfImports,
|
||||
];
|
||||
|
||||
const unbundled = allEntries.filter(e => /\.(server|client)\.js$/.test(e));
|
||||
const bundled = allEntries.filter(e => !/\.(server|client)\.js$/.test(e));
|
||||
|
||||
const esbuildBase = (o) => {
|
||||
o.loader = { '.js': 'jsx', '.jsx': 'jsx' };
|
||||
o.jsx = 'automatic';
|
||||
};
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry: bundled,
|
||||
export default defineConfig({
|
||||
entry: walk('src'),
|
||||
format: ['esm'],
|
||||
dts: false,
|
||||
splitting: false,
|
||||
sourcemap: false,
|
||||
clean: true,
|
||||
bundle: true,
|
||||
external: SHARED_EXTERNALS,
|
||||
esbuildOptions(o) {
|
||||
esbuildBase(o);
|
||||
o.platform = 'neutral';
|
||||
o.legalComments = 'inline';
|
||||
},
|
||||
},
|
||||
{
|
||||
entry: unbundled,
|
||||
format: ['esm'],
|
||||
dts: false,
|
||||
splitting: false,
|
||||
sourcemap: false,
|
||||
clean: false,
|
||||
bundle: false,
|
||||
external: SHARED_EXTERNALS,
|
||||
esbuildOptions(o) {
|
||||
esbuildBase(o);
|
||||
o.loader = { '.js': 'jsx', '.jsx': 'jsx' };
|
||||
o.jsx = 'automatic';
|
||||
o.outbase = 'src';
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user