Structure du projet
Ce que génère @lrvo/start, à quoi sert chaque fichier, et où écrire son propre code.
Cette page décrit l'arborescence générée par npx @lrvo/start, puis celle de @lrvo/core lui-même.
Le projet généré
mon-projet/
├── app/
│ ├── layout.js layout racine : providers, thème, manifestes
│ ├── icon.svg
│ ├── .lrvo/ AUTO-GÉNÉRÉ, gitignoré
│ │ ├── modules.generated.js
│ │ ├── modules.client.js
│ │ ├── public-pages.server.js
│ │ ├── blocks.server.js
│ │ ├── blocks.client.js
│ │ └── templates.server.js
│ ├── (public)/
│ │ ├── layout.js
│ │ ├── page.js page d'accueil
│ │ ├── not-found.js
│ │ └── [...slug]/page.js catch-all du contenu public
│ ├── (auth)/auth/
│ │ ├── page.js redirige vers /auth/login
│ │ └── [...auth]/page.js pages d'authentification
│ ├── (admin)/admin/
│ │ ├── layout.js
│ │ ├── page.js
│ │ └── [...admin]/page.js pages d'admin enregistrées
│ └── lrvo/
│ ├── api/[...path]/route.js routeur API
│ ├── [...path]/page.js pages publiques de module, + leur manifeste
│ └── media/[filename]/route.js route fichier des médias
├── components/
│ ├── Icons.js
│ └── lrvo/
│ ├── blocks/<id>/ blocs personnalisés
│ └── templates/ templates de rendu public
├── styles/globals.css
├── dev/icons/ script make-favicon
├── instrumentation.js boot serveur
├── theme.js apparence du projet
├── next.config.mjs
├── jsconfig.json alias @styles, @components
├── .npmrc token du registre privé, suivi par git
└── .env variables d'environnement, suivi par gitLes fichiers qui comptent
instrumentation.js
Point d'entrée du boot serveur. Il charge les manifestes puis initialise la plateforme.
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { initializeLrvo } = await import('@lrvo/core');
const { modules } = await import('./app/.lrvo/modules.generated.js');
await import('./app/.lrvo/blocks.server.js');
await import('./app/.lrvo/templates.server.js');
const { default: theme } = await import('./theme.js');
await initializeLrvo({ modules, theme });
}
}Le garde sur NEXT_RUNTIME évite d'exécuter ce code sur le runtime Edge, qui n'a ni pg ni système de fichiers.
Les templates sont chargés avant initializeLrvo pour être disponibles si un module les utilise pendant son boot.
theme.js
L'apparence de tout le projet : couleur de marque, teinte des gris, arrondis, coquille de l'admin, modes offerts. L'admin, les pages publiques, les modules, les courriels et les PDF la lisent. Le fichier généré porte les valeurs par défaut, commentées. Voir Personnaliser l'apparence.
app/layout.js
Le layout racine monte quatre choses, en plus de la feuille de style globale.
import '@styles/globals.css';
import LrvoModulesClient from './.lrvo/modules.client.js';
import LrvoBlocksClient from './.lrvo/blocks.client.js';
import './.lrvo/blocks.server.js';
import './.lrvo/templates.server.js';
import { LrvoProvider } from '@lrvo/core/features/provider';
import { ThemeStyle } from '@lrvo/core/themes/server';
export default function RootLayout({ children }) {
return (
<html lang="fr" suppressHydrationWarning>
<head>
<ThemeStyle />
</head>
<body className="antialiased">
<LrvoModulesClient />
<LrvoBlocksClient />
<LrvoProvider>{children}</LrvoProvider>
</body>
</html>
);
}L'alias @styles vient du jsconfig.json généré, qui déclare aussi @components. styles/globals.css importe Tailwind puis @lrvo/core/styles/core.css. Voir Styles.
Deux détails ne sont pas évidents.
Les composants de manifeste sont rendus, pas seulement importés. Sous Turbopack, un import purement side-effect d'un fichier 'use client' orphelin inclut le fichier dans le bundle mais n'exécute pas son code top-level. Les enregistrements ne tourneraient jamais.
Les manifestes serveur sont importés ici en plus d'instrumentation.js. C'est nécessaire pour que les render.js marqués 'use client' et les templates traversent le compilateur RSC et soient référencés dans le manifeste client de React. Sans cet import, un bloc au rendu client échoue avec « Could not find the module in the React Client Manifest ».
Le manifeste des pages publiques
Le troisième cas de la même règle, mais son remède vit dans la route et non dans le layout :
// app/lrvo/[...path]/page.js
import '../../.lrvo/public-pages.server.js';
export { default, generateMetadata } from '@lrvo/core/public-pages/server';Une page publique de module est retrouvée au rendu par une lecture de registre, pas par un import. Le compilateur RSC de la route ne peut donc pas deviner qu'elle existe, et les composants 'use client' qu'elle rend restent hors du React Client Manifest. L'import du manifeste crée l'arête statique qui manque.
Il est accroché à la route plutôt qu'au layout pour que les pages publiques des modules n'entrent pas dans le graphe de toutes les autres routes du site.
La règle générale, valable pour les trois cas : tout registre dont les entrées sont des composants doit être alimenté depuis le graphe RSC de la route qui les rend, jamais depuis instrumentation.js seul.
Les groupes de routes
| Groupe | Rôle |
|---|---|
(public) | Site public. Le [...slug] délègue au registre de contenu public. |
(auth) | Pages d'authentification, servies par une seule route catch-all. |
(admin) | Administration. Le layout et les pages sont ré-exportés du core. |
Chaque route du core tient en une ligne :
// app/(admin)/admin/layout.js
export { default } from '@lrvo/core/features/admin/layout';C'est ce qui permet à une mise à jour du package de faire évoluer l'admin sans toucher au projet.
app/.lrvo/
Généré par npx lrvo-modules sync, gitignoré, jamais committé. Régénéré par les scripts postinstall, dev et build.
Ne jamais éditer ces fichiers : la prochaine synchronisation écrase les modifications. Voir Cycle de vie d'un module.
components/lrvo/
C'est ici que le projet ajoute ses extensions de contenu.
| Dossier | Contenu |
|---|---|
blocks/<id>/ | Un bloc personnalisé, avec fields.js, template.js, render.js. |
templates/ | Templates de rendu public, plus le content.js partagé. |
Les deux sont détectés par lrvo-modules sync. Voir Blocs personnalisés et Contenu public et templates.
Où écrire son code
| Besoin | Emplacement |
|---|---|
| Page publique fixe | app/(public)/… |
| Extension d'admin propre au projet | app/lrvo.extensions.js, importé par app/layout.js |
| Bloc personnalisé | components/lrvo/blocks/<id>/ |
| Template de rendu | components/lrvo/templates/<id>.js |
| Fonctionnalité réutilisable entre projets | un package @lrvo/module-* |
Si une fonctionnalité peut vivre en module, elle vit en module. Voir Créer un module.
L'arborescence de @lrvo/core
Utile pour lire la référence, pas pour développer.
src/
├── core/ infrastructure : api, database, users, email, storage,
│ payments, pdf, cron, crypto, toast, themes, registres
├── features/ auth, admin, provider
├── shared/ components, icons, hooks, lib, styles, utils
├── blocks-registry/ blocs personnalisés et rendu serveur
└── media-registry/ façade vers @lrvo/module-mediasUne feature suit la règle plat plus un barrel : un index.js qui ré-exporte, des fichiers plats à côté. Les sous-dossiers ne sont autorisés que pour plusieurs fichiers du même rôle : components/, pages/, templates/, widgets/.
Suffixes de runtime
Le nom des fichiers porte l'information de frontière, et le build s'en sert comme source de vérité.
| Suffixe | Signification |
|---|---|
.server.js | Code serveur strict. Peut importer pg, fs, node:*. |
.client.js | Débute par 'use client'. |
actions.js | Débute par 'use server'. |
| Aucun | Module neutre. |
Voir Frontières serveur/client.
Étape suivante
Administration ajoute une section complète à l'admin.