@madojs/mado 0.11.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/AGENTS.md +116 -32
  2. package/CHANGELOG.md +216 -1
  3. package/README.md +158 -173
  4. package/dist/src/component.d.ts +6 -3
  5. package/dist/src/component.d.ts.map +1 -0
  6. package/dist/src/component.js +163 -36
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/context.d.ts +13 -32
  9. package/dist/src/context.d.ts.map +1 -0
  10. package/dist/src/context.js +73 -48
  11. package/dist/src/context.js.map +1 -1
  12. package/dist/src/css.d.ts +1 -0
  13. package/dist/src/css.d.ts.map +1 -0
  14. package/dist/src/css.js +34 -5
  15. package/dist/src/css.js.map +1 -1
  16. package/dist/src/devtools-hook.d.ts +14 -0
  17. package/dist/src/devtools-hook.d.ts.map +1 -0
  18. package/dist/src/devtools-hook.js +27 -0
  19. package/dist/src/devtools-hook.js.map +1 -0
  20. package/dist/src/devtools.d.ts +24 -22
  21. package/dist/src/devtools.d.ts.map +1 -0
  22. package/dist/src/devtools.js +230 -58
  23. package/dist/src/devtools.js.map +1 -1
  24. package/dist/src/diagnostics.d.ts +12 -0
  25. package/dist/src/diagnostics.d.ts.map +1 -0
  26. package/dist/src/diagnostics.js +68 -8
  27. package/dist/src/diagnostics.js.map +1 -1
  28. package/dist/src/each.d.ts +1 -5
  29. package/dist/src/each.d.ts.map +1 -0
  30. package/dist/src/each.js +0 -8
  31. package/dist/src/each.js.map +1 -1
  32. package/dist/src/forms.d.ts +27 -96
  33. package/dist/src/forms.d.ts.map +1 -0
  34. package/dist/src/forms.js +184 -394
  35. package/dist/src/forms.js.map +1 -1
  36. package/dist/src/head.d.ts +7 -6
  37. package/dist/src/head.d.ts.map +1 -0
  38. package/dist/src/head.js +8 -7
  39. package/dist/src/head.js.map +1 -1
  40. package/dist/src/html/bindings.d.ts +1 -0
  41. package/dist/src/html/bindings.d.ts.map +1 -0
  42. package/dist/src/html/bindings.js.map +1 -1
  43. package/dist/src/html/parser.d.ts +4 -5
  44. package/dist/src/html/parser.d.ts.map +1 -0
  45. package/dist/src/html/parser.js +64 -15
  46. package/dist/src/html/parser.js.map +1 -1
  47. package/dist/src/html/template-types.d.ts +1 -0
  48. package/dist/src/html/template-types.d.ts.map +1 -0
  49. package/dist/src/html/template-types.js.map +1 -1
  50. package/dist/src/html/template.d.ts +5 -1
  51. package/dist/src/html/template.d.ts.map +1 -0
  52. package/dist/src/html/template.js +102 -13
  53. package/dist/src/html/template.js.map +1 -1
  54. package/dist/src/index.d.ts +15 -12
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +18 -10
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/json.d.ts +3 -0
  59. package/dist/src/json.d.ts.map +1 -0
  60. package/dist/src/json.js +14 -0
  61. package/dist/src/json.js.map +1 -0
  62. package/dist/src/lifecycle.d.ts +1 -0
  63. package/dist/src/lifecycle.d.ts.map +1 -0
  64. package/dist/src/lifecycle.js +3 -2
  65. package/dist/src/lifecycle.js.map +1 -1
  66. package/dist/src/page.d.ts +63 -28
  67. package/dist/src/page.d.ts.map +1 -0
  68. package/dist/src/page.js +5 -0
  69. package/dist/src/page.js.map +1 -1
  70. package/dist/src/persisted.d.ts +6 -1
  71. package/dist/src/persisted.d.ts.map +1 -0
  72. package/dist/src/persisted.js +17 -11
  73. package/dist/src/persisted.js.map +1 -1
  74. package/dist/src/resource.d.ts +2 -1
  75. package/dist/src/resource.d.ts.map +1 -0
  76. package/dist/src/resource.js +128 -50
  77. package/dist/src/resource.js.map +1 -1
  78. package/dist/src/router/base.d.ts +66 -0
  79. package/dist/src/router/base.d.ts.map +1 -0
  80. package/dist/src/router/base.js +168 -0
  81. package/dist/src/router/base.js.map +1 -0
  82. package/dist/src/router/manifest.d.ts +1 -0
  83. package/dist/src/router/manifest.d.ts.map +1 -0
  84. package/dist/src/router/manifest.js +156 -171
  85. package/dist/src/router/manifest.js.map +1 -1
  86. package/dist/src/router/match.d.ts +17 -2
  87. package/dist/src/router/match.d.ts.map +1 -0
  88. package/dist/src/router/match.js +60 -6
  89. package/dist/src/router/match.js.map +1 -1
  90. package/dist/src/router/navigation.d.ts +1 -0
  91. package/dist/src/router/navigation.d.ts.map +1 -0
  92. package/dist/src/router/navigation.js +58 -9
  93. package/dist/src/router/navigation.js.map +1 -1
  94. package/dist/src/signal.d.ts +1 -0
  95. package/dist/src/signal.d.ts.map +1 -0
  96. package/dist/src/signal.js +46 -17
  97. package/dist/src/signal.js.map +1 -1
  98. package/dist/src/static-runtime.d.ts +82 -0
  99. package/dist/src/static-runtime.d.ts.map +1 -0
  100. package/dist/src/static-runtime.js +209 -0
  101. package/dist/src/static-runtime.js.map +1 -0
  102. package/dist/src/vite/index.d.ts +32 -3
  103. package/dist/src/vite/index.d.ts.map +1 -0
  104. package/dist/src/vite/index.js +49 -17
  105. package/dist/src/vite/index.js.map +1 -1
  106. package/docs/README.md +5 -8
  107. package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
  108. package/docs/architecture/v1-roadmap.md +19 -0
  109. package/docs/en/00-the-mado-way.md +1 -1
  110. package/docs/en/01-quickstart.md +183 -0
  111. package/docs/en/10-pages-and-components.md +279 -0
  112. package/docs/en/11-templates-and-signals.md +211 -0
  113. package/docs/en/12-routing.md +229 -0
  114. package/docs/en/13-data.md +227 -0
  115. package/docs/en/14-forms.md +91 -0
  116. package/docs/en/15-static-snapshots.md +181 -0
  117. package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +56 -4
  118. package/docs/en/{13-deployment.md → 20-deployment.md} +79 -17
  119. package/docs/en/{15-error-handling.md → 21-error-handling.md} +9 -6
  120. package/docs/en/{14-testing.md → 22-testing.md} +6 -5
  121. package/docs/en/23-cookbook.md +292 -0
  122. package/docs/en/24-devtools-and-diagnostics.md +45 -0
  123. package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +17 -9
  124. package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +5 -5
  125. package/docs/en/33-migration-0.12-0.13.md +56 -0
  126. package/docs/en/40-llm-guide.md +774 -0
  127. package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +28 -25
  128. package/docs/en/{05-why-mado.md → 42-why-mado.md} +3 -3
  129. package/docs/en/README.md +99 -27
  130. package/docs/recipes/nginx/Containerfile +26 -0
  131. package/docs/recipes/nginx/nginx.conf +42 -0
  132. package/llms.txt +263 -210
  133. package/package.json +51 -23
  134. package/scripts/clean.mjs +8 -0
  135. package/scripts/cli/generate.mjs +57 -10
  136. package/scripts/cli/help.mjs +13 -5
  137. package/scripts/cli/index.mjs +31 -7
  138. package/scripts/cli/init.mjs +19 -19
  139. package/scripts/cli/release.mjs +38 -83
  140. package/scripts/cli/run.mjs +5 -3
  141. package/scripts/logger.mjs +117 -0
  142. package/scripts/output-guard.mjs +128 -0
  143. package/scripts/preview.mjs +105 -24
  144. package/scripts/static/browser.mjs +695 -0
  145. package/scripts/static/discover.mjs +284 -0
  146. package/scripts/static/output.mjs +141 -0
  147. package/scripts/static/serialize.mjs +212 -0
  148. package/scripts/static/server.mjs +167 -0
  149. package/scripts/static.mjs +205 -0
  150. package/starters/default/README.md +57 -55
  151. package/starters/default/package.json +6 -12
  152. package/starters/default/src/app.routes.ts +20 -33
  153. package/starters/default/src/components/feature-card.component.ts +40 -0
  154. package/starters/default/src/components/live-counter.component.ts +57 -0
  155. package/starters/default/src/content/guides.ts +55 -0
  156. package/starters/default/src/main.ts +9 -13
  157. package/starters/default/src/pages/app.page.ts +41 -0
  158. package/starters/default/src/pages/guide.page.ts +40 -0
  159. package/starters/default/src/pages/home.page.ts +49 -0
  160. package/starters/default/src/pages/not-found.page.ts +18 -0
  161. package/starters/default/src/styles/document.css +39 -0
  162. package/starters/default/src/styles/reset.css +37 -0
  163. package/starters/default/src/styles/tokens.css +30 -0
  164. package/starters/default/src/styles.d.ts +3 -1
  165. package/starters/default/src/vite-env.d.ts +1 -1
  166. package/starters/default/tsconfig.node.json +13 -0
  167. package/starters/default/vite.config.ts +14 -4
  168. package/starters/modular/README.md +142 -0
  169. package/starters/modular/index.html +13 -0
  170. package/starters/modular/package.json +30 -0
  171. package/starters/modular/src/app.routes.ts +39 -0
  172. package/starters/{default → modular}/src/layouts/app-shell.layout.ts +9 -7
  173. package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
  174. package/starters/modular/src/main.ts +16 -0
  175. package/starters/{default → modular}/src/modules/auth/login.page.ts +5 -12
  176. package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +3 -4
  177. package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +4 -4
  178. package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
  179. package/starters/modular/src/modules/home/not-found.page.ts +14 -0
  180. package/starters/{default → modular}/src/shared/styles/reset.css +21 -1
  181. package/starters/modular/src/styles.d.ts +1 -0
  182. package/starters/modular/src/vite-env.d.ts +1 -0
  183. package/starters/modular/tsconfig.json +33 -0
  184. package/starters/modular/tsconfig.node.json +13 -0
  185. package/starters/modular/vite.config.ts +132 -0
  186. package/TODO.md +0 -79
  187. package/dist/src/lazy.d.ts +0 -38
  188. package/dist/src/lazy.js +0 -73
  189. package/dist/src/lazy.js.map +0 -1
  190. package/docs/en/01-routing.md +0 -152
  191. package/docs/en/02-project-layout.md +0 -124
  192. package/docs/en/03-static-bake.md +0 -249
  193. package/docs/en/04-ide-setup.md +0 -162
  194. package/docs/en/07-llm-pitfalls.md +0 -724
  195. package/docs/en/08-llm-zero-history-test.md +0 -56
  196. package/docs/en/09-shadow-vs-light-dom.md +0 -174
  197. package/docs/en/11-layouts.md +0 -113
  198. package/docs/en/12-auth-and-api.md +0 -124
  199. package/docs/en/16-bake-cookbook.md +0 -100
  200. package/docs/en/17-shadow-dom-forms.md +0 -192
  201. package/docs/fr/00-the-mado-way.md +0 -85
  202. package/docs/fr/01-routing.md +0 -120
  203. package/docs/fr/02-project-layout.md +0 -84
  204. package/docs/fr/03-static-bake.md +0 -289
  205. package/docs/fr/04-ide-setup.md +0 -162
  206. package/docs/fr/05-why-mado.md +0 -193
  207. package/docs/fr/06-for-backenders.md +0 -438
  208. package/docs/fr/07-llm-pitfalls.md +0 -625
  209. package/docs/fr/08-llm-zero-history-test.md +0 -38
  210. package/docs/fr/09-shadow-vs-light-dom.md +0 -65
  211. package/docs/fr/10-app-architecture.md +0 -138
  212. package/docs/fr/11-layouts.md +0 -47
  213. package/docs/fr/12-auth-and-api.md +0 -76
  214. package/docs/fr/13-deployment.md +0 -57
  215. package/docs/fr/14-testing.md +0 -41
  216. package/docs/fr/15-error-handling.md +0 -50
  217. package/docs/fr/16-bake-cookbook.md +0 -88
  218. package/docs/fr/17-shadow-dom-forms.md +0 -196
  219. package/docs/fr/18-api-freeze-map.md +0 -63
  220. package/docs/fr/19-reactivity-ordering.md +0 -97
  221. package/docs/fr/20-v1-stability.md +0 -88
  222. package/docs/fr/README.md +0 -27
  223. package/docs/ru/00-the-mado-way.md +0 -84
  224. package/docs/ru/01-routing.md +0 -119
  225. package/docs/ru/02-project-layout.md +0 -84
  226. package/docs/ru/03-static-bake.md +0 -250
  227. package/docs/ru/04-ide-setup.md +0 -144
  228. package/docs/ru/05-why-mado.md +0 -193
  229. package/docs/ru/06-for-backenders.md +0 -428
  230. package/docs/ru/07-llm-pitfalls.md +0 -624
  231. package/docs/ru/08-llm-zero-history-test.md +0 -57
  232. package/docs/ru/09-shadow-vs-light-dom.md +0 -63
  233. package/docs/ru/10-app-architecture.md +0 -152
  234. package/docs/ru/11-layouts.md +0 -47
  235. package/docs/ru/12-auth-and-api.md +0 -75
  236. package/docs/ru/13-deployment.md +0 -66
  237. package/docs/ru/14-testing.md +0 -50
  238. package/docs/ru/15-error-handling.md +0 -56
  239. package/docs/ru/16-bake-cookbook.md +0 -95
  240. package/docs/ru/17-shadow-dom-forms.md +0 -193
  241. package/docs/ru/18-api-freeze-map.md +0 -64
  242. package/docs/ru/19-reactivity-ordering.md +0 -95
  243. package/docs/ru/20-v1-stability.md +0 -82
  244. package/docs/ru/README.md +0 -25
  245. package/docs/uk/00-the-mado-way.md +0 -82
  246. package/docs/uk/01-routing.md +0 -76
  247. package/docs/uk/02-project-layout.md +0 -73
  248. package/docs/uk/03-static-bake.md +0 -48
  249. package/docs/uk/04-ide-setup.md +0 -26
  250. package/docs/uk/05-why-mado.md +0 -34
  251. package/docs/uk/06-for-backenders.md +0 -55
  252. package/docs/uk/07-llm-pitfalls.md +0 -145
  253. package/docs/uk/08-llm-zero-history-test.md +0 -34
  254. package/docs/uk/09-shadow-vs-light-dom.md +0 -58
  255. package/docs/uk/10-app-architecture.md +0 -97
  256. package/docs/uk/11-layouts.md +0 -47
  257. package/docs/uk/12-auth-and-api.md +0 -70
  258. package/docs/uk/13-deployment.md +0 -40
  259. package/docs/uk/14-testing.md +0 -34
  260. package/docs/uk/15-error-handling.md +0 -32
  261. package/docs/uk/16-bake-cookbook.md +0 -36
  262. package/docs/uk/17-shadow-dom-forms.md +0 -193
  263. package/docs/uk/18-api-freeze-map.md +0 -61
  264. package/docs/uk/19-reactivity-ordering.md +0 -95
  265. package/docs/uk/20-v1-stability.md +0 -83
  266. package/docs/uk/README.md +0 -27
  267. package/scripts/bake.mjs +0 -570
  268. package/scripts/package-smoke.mjs +0 -77
  269. package/scripts/release-notes.mjs +0 -66
  270. package/scripts/size-budget.mjs +0 -91
  271. package/starters/default/src/modules/home/not-found.page.ts +0 -11
  272. package/starters/default/src/shared/ui/x-button.component.ts +0 -49
  273. /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
  274. /package/starters/{default → modular}/.editorconfig +0 -0
  275. /package/starters/{default → modular}/eslint.config.mjs +0 -0
  276. /package/starters/{default → modular}/public/favicon.svg +0 -0
  277. /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
  278. /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
  279. /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
  280. /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
  281. /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
  282. /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
  283. /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
  284. /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
  285. /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
  286. /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
  287. /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
  288. /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
  289. /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
  290. /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
  291. /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
  292. /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
  293. /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
  294. /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
  295. /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
  296. /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
  297. /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
  298. /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
@@ -1,289 +0,0 @@
1
- # Static intelligent (`bake`)
2
-
3
- > Générer du HTML pour le SEO sans SSR runtime. **Idée : données et vue dans un seul fichier, sortie statique.**
4
-
5
- `bake` est un **prérendu au moment du build**, pas du SSR. La sortie est des fichiers `*.html`
6
- statiques que n'importe quel nginx/Cloudflare sert comme du contenu statique ordinaire. Sur le
7
- client, les Web Components s'animent et la navigation SPA continue de fonctionner.
8
-
9
- ---
10
-
11
- ## Quand `bake` est adapté
12
-
13
- - **Pages marketing** : landing pages, sous-landings pour des campagnes publicitaires, pages produits.
14
- - **Catalogue avec un ensemble de pages relativement stable** : blog, documentation, portfolio,
15
- e-commerce jusqu'à **~10k SKUs** avec des mises à jour moins d'une fois par heure.
16
- - **Contenu identique pour tous les utilisateurs** : la page entière est identique pour un
17
- visiteur et un utilisateur authentifié (ou l'authentification est rendue côté client via `effect()`).
18
- - Vous avez besoin d'un **bon SEO** (rich snippets, OG, JSON-LD) et d'un **premier affichage
19
- rapide** sans faire tourner des serveurs node en production.
20
-
21
- ## Quand `bake` n'est **pas** adapté
22
-
23
- - **Des centaines de milliers de pages avec des changements fréquents**. `bake` parcourt tous
24
- les `paths` de façon synchrone en une seule exécution. Pour 100k+ pages, cela signifie des
25
- minutes de rebuild, et l'invalidation d'une page nécessite soit un rebake complet, soit une
26
- logique CI séparée (voir ci-dessous sur la revalidation ciblée).
27
- - **Contenu personnalisé dans le HTML**. Si la page doit afficher "Bonjour, Ivan" dans le
28
- `<title>` ou dans les meta — ce n'est pas pour `bake`. Les tableaux de bord authentifiés,
29
- les fils personnalisés, un panier avec des prix réels pour l'utilisateur — gardez-les en SPA.
30
- - **Des API uniquement serveur sont nécessaires lors du rendu** : cookies, headers, vraies
31
- requêtes réseau vers des API privées. Côté bake, seul `linkedom` est disponible, pas
32
- d'environnement Node pour les composants.
33
- - **Tests A/B et flags qui modifient le markup au premier affichage**. `bake` verrouillera
34
- une variante. Gérez le comportement dynamique côté client via `effect()`.
35
- - **Données en temps réel / qui changent fréquemment** (cours boursiers, stock entrepôt à la
36
- minute). `bake.revalidate` est des métadonnées, pas du runtime : le framework ne re-bake
37
- rien lui-même.
38
- - **Contenu derrière une authentification** (admin, outils internes). Inutile ; utilisez le
39
- mode SPA.
40
-
41
- ---
42
-
43
- ## Concept
44
-
45
- `page({...})` a quatre emplacements optionnels liés à `bake` :
46
-
47
- - `head` — meta, OG, JSON-LD.
48
- - `bake.paths` — liste des paramètres URL pour la génération (build-time, peut être `async`).
49
- - `bake.data` — données pour une URL spécifique (build-time, peut être `async`).
50
- - `bake.revalidate` — après combien de secondes le cache est périmé (écrit dans `<meta>`, la
51
- vraie invalidation est gérée par votre CI/CDN).
52
-
53
- La commande `npm run bake` parcourt toutes les entrées `page` avec `bake`, génère le HTML via
54
- `linkedom`, et le place dans `out/<chemin>/index.html`. **Pas de Chromium nécessaire** —
55
- `linkedom` fait ~50 Ko.
56
-
57
- ---
58
-
59
- ## Exemple
60
-
61
- ```ts
62
- // src/pages/product.ts
63
- import { page, component, html } from "@madojs/mado";
64
- import { findProduct, products, type Product } from "../lib/products.js";
65
-
66
- component("x-product-page", ({ host }) => {
67
- return () => {
68
- const p = findProduct(host.dataset.slug);
69
- return p
70
- ? html`<h1>${p.name}</h1><p>${p.description}</p>`
71
- : html`<p>Introuvable.</p>`;
72
- };
73
- });
74
-
75
- export default page<{ slug: string }, Product | undefined>({
76
- title: ({ slug }) => `${findProduct(slug)?.name} — MaBoutique`,
77
-
78
- head: ({ slug }, baked) => {
79
- const p = baked ?? findProduct(slug);
80
- if (!p) return {};
81
- return {
82
- description: p.description,
83
- canonical: `/product/${p.slug}`,
84
- og: { title: p.name, image: p.image, type: "product" },
85
- jsonLd: {
86
- "@context": "https://schema.org",
87
- "@type": "Product",
88
- name: p.name,
89
- offers: { "@type": "Offer", price: p.price, priceCurrency: p.currency },
90
- },
91
- };
92
- },
93
-
94
- bake: {
95
- paths: () => products.map((p) => ({ slug: p.slug })),
96
- data: ({ slug }) => findProduct(slug),
97
- revalidate: 3600,
98
- },
99
-
100
- view: ({ params }) =>
101
- html`<x-product-page data-slug=${params.slug}></x-product-page>`,
102
- });
103
- ```
104
-
105
- ```ts
106
- // src/routes.ts
107
- import { routes, type RoutesMap } from "@madojs/mado";
108
-
109
- // Exporter À LA FOIS default (RouterApi pour le runtime) ET manifest (pour le script bake).
110
- export const manifest: RoutesMap = {
111
- "/": () => import("./pages/home.js"),
112
- "/product/:slug": () => import("./pages/product.js"),
113
- "*": () => import("./pages/not-found.js"),
114
- };
115
-
116
- export default routes(manifest, { titleSuffix: " · MaBoutique" });
117
- ```
118
-
119
- ## Exécution
120
-
121
- ```bash
122
- npm install -D linkedom esbuild
123
- npm run build
124
- npm run bake
125
- ```
126
-
127
- Vous obtenez :
128
-
129
- ```
130
- out/
131
- ├── product/
132
- │ ├── mado-mug/index.html ← HTML avec meta + JSON-LD
133
- │ ├── raw-bundler/index.html
134
- │ └── shadow-dom/index.html
135
- └── sitemap.xml
136
- ```
137
-
138
- ## Contenu du HTML généré
139
-
140
- ```html
141
- <head>
142
- <title>Mado Mug — MaBoutique</title>
143
- <meta name="description" content="..." data-mado-head="baked">
144
- <link rel="canonical" href="/product/mado-mug" data-mado-head="baked">
145
- <meta property="og:title" content="Mado Mug" data-mado-head="baked">
146
- <meta property="og:image" content="..." data-mado-head="baked">
147
- <script type="application/ld+json" data-mado-head="baked">
148
- {"@context":"https://schema.org","@type":"Product","..."}
149
- </script>
150
- <meta name="bake-revalidate" content="3600" data-mado-head="baked">
151
- </head>
152
- <body>
153
- <div id="app">
154
- <x-product-page data-slug="mado-mug">
155
- <h1>Mado Mug</h1>
156
- <p>Un mug avec l'inscription "zéro dépendances".</p>
157
- <strong>12 EUR</strong>
158
- </x-product-page>
159
- </div>
160
-
161
- <!-- données préchargées pour l'hydratation -->
162
- <script id="bake" type="application/json">
163
- {"slug":"mado-mug","name":"Mado Mug","price":12,"..."}
164
- </script>
165
-
166
- <script type="module" src="/assets/main-abc123.js"></script>
167
- </body>
168
- ```
169
-
170
- Après le chargement du JS :
171
-
172
- 1. Les Web Components `<x-product-page>` s'animent (le navigateur connaît déjà les custom elements).
173
- 2. `page.load()` reçoit `baked` comme initialData — pas d'appels `fetch` inutiles.
174
- 3. La navigation SPA continue de fonctionner normalement.
175
-
176
- ---
177
-
178
- ## Cookbook : Scénarios typiques
179
-
180
- ### Blog (Markdown → bake)
181
-
182
- ```ts
183
- // src/lib/posts.ts
184
- import { readdirSync, readFileSync } from "node:fs";
185
- // (ce module est importé uniquement depuis le script bake,
186
- // il ne doit pas se retrouver dans le graph navigateur — mettez-le dans lib/server/ ou excluez-le)
187
-
188
- export const allPosts = () =>
189
- readdirSync("content/blog").map((file) => ({
190
- slug: file.replace(/\.md$/, ""),
191
- ...parseFrontmatter(readFileSync(`content/blog/${file}`, "utf-8")),
192
- }));
193
- ```
194
-
195
- ```ts
196
- // src/pages/blog-post.ts
197
- import { page, html } from "@madojs/mado";
198
- import { allPosts } from "../lib/posts.js";
199
-
200
- export default page<{ slug: string }>({
201
- title: ({ slug }) => allPosts().find((p) => p.slug === slug)?.title ?? slug,
202
- head: ({ slug }, post) => ({
203
- description: post?.excerpt,
204
- canonical: `/blog/${slug}`,
205
- og: { title: post?.title, type: "article" },
206
- }),
207
- bake: {
208
- paths: () => allPosts().map(({ slug }) => ({ slug })),
209
- data: ({ slug }) => allPosts().find((p) => p.slug === slug),
210
- },
211
- view: ({ params }) =>
212
- html`<x-blog-post data-slug=${params.slug}></x-blog-post>`,
213
- });
214
- ```
215
-
216
- ### Catalogue produits (e-commerce, ≤ 10k SKUs)
217
-
218
- - `bake.paths` → SELECT slug FROM products
219
- - `bake.data` → SELECT * FROM products WHERE slug=?
220
- - Invalidation complète toutes les N heures via cron + `npm run bake`
221
- - Invalidation ciblée d'un seul produit : webhook → rebuild uniquement cette entrée `paths`
222
-
223
- ### Documentation
224
-
225
- - `bake.paths` — parcours du système de fichiers `docs/**/*.md`
226
- - `bake.data` — parsing Markdown
227
- - `head.jsonLd` — `TechArticle`
228
-
229
- ---
230
-
231
- ## Revalidate / CDN
232
-
233
- `bake.revalidate: 3600` écrit `<meta name="bake-revalidate" content="3600">`
234
- dans le HTML. C'est des **métadonnées** — le framework ne re-bake rien lui-même. Stratégies :
235
-
236
- 1. **Option la plus simple** : cron dans CI — `npm run bake && rsync out/ origin:/var/www/`.
237
- 2. **Via CDN** (Cloudflare/Fastly) : servir le HTML avec `Cache-Control: max-age=3600`. Le CDN
238
- s'invalide lui-même.
239
- 3. **Déclencheur webhook** : API boutique → POST `/_revalidate?path=/product/mado-mug` → CI
240
- re-bake uniquement cette page (vous pouvez implémenter `bake.paths` pour retourner une liste
241
- ciblée basée sur un paramètre d'environnement).
242
-
243
- ---
244
-
245
- ## Comparaison avec les alternatives
246
-
247
- | | Next.js SSG/ISR | playwright-prerender | **mado bake** |
248
- |--------------------------|--------------------|----------------------|-----------------|
249
- | Chrome requis en CI | non | **oui** (~300 Mo) | **non** |
250
- | Node requis en production | pour ISR | non | **non** |
251
- | Temps pour 1000 pages | minutes | minutes | **secondes** |
252
- | Niveau de magie | élevé | faible | **zéro** |
253
- | Parser HTML | moteur React | navigateur | linkedom (~50 Ko) |
254
- | Configuration | next.config.js + … | script unique | script unique |
255
- | Source de vérité vue+données | séparées | page | **une seule page** |
256
-
257
- ---
258
-
259
- ## Limitations et pièges
260
-
261
- - **Il n'y a pas de navigateur côté bake.** Ne fonctionnent pas : `setTimeout` (techniquement
262
- ça marche, mais bake se termine avant qu'il ne se déclenche), `fetch` vers des URLs relatives,
263
- tous les effets de bord `effect()`/`signal()`, le vrai `requestAnimationFrame`. La fonction
264
- de rendu doit être déterministe selon `params` / `data`.
265
- - **`linkedom` ≠ navigateur.** Toutes les API DOM ne sont pas supportées (par exemple,
266
- `HTMLElement.click()` se comporte plus simplement). La logique complexe dans les Web Components
267
- ne s'exécutera dans le navigateur qu'après `connectedCallback` ; seul ce qui a été rendu
268
- de façon synchrone lors du premier passage se retrouvera dans le HTML baked.
269
- - **Rendre le contenu dynamique côté client.** L'heure actuelle, les tests A/B, les
270
- banners géo, le panier de l'utilisateur — ceux-ci ne doivent pas être dans le HTML baked.
271
- Utilisez `effect()` pour le rendu côté client.
272
- - **Les imports côté serveur ne doivent pas se retrouver dans le graph client.** Si
273
- `lib/posts.ts` importe `node:fs`, il ne peut pas être importé depuis `view`. Gardez ces
274
- modules dans un dossier séparé (`lib/build/`) et utilisez-les uniquement depuis
275
- `bake.paths`/`bake.data`.
276
- - **`paths` et `data` sont exécutés à chaque exécution de bake.** S'ils impliquent une
277
- requête de base de données lourde — mettez en cache au niveau du script.
278
-
279
- ---
280
-
281
- ## TL;DR
282
-
283
- Si une page est **identique pour tous les utilisateurs**, a **un ensemble d'URLs relativement
284
- stable**, et que **le SEO + le premier affichage** comptent — ajoutez `bake: { paths, data }`
285
- et obtenez du HTML statique avec meta/JSON-LD/sitemap en millisecondes. Pas de serveur node,
286
- pas de Chrome, pas de magie.
287
-
288
- Si la page est personnalisée, ou qu'il y a des millions d'URLs, ou que le contenu change en
289
- temps réel — `bake` n'est pas votre outil. Gardez-la en SPA ou intégrez un framework SSR séparé.
@@ -1,162 +0,0 @@
1
- # Support IDE pour `html\`\`` et `css\`\``
2
-
3
- Par défaut, `html\`...\`` et `css\`...\`` ne sont que des tagged-template strings.
4
- TypeScript ne les connaît pas, l'IDE ne les colore pas. C'est un **compromis délibéré**
5
- en faveur de zéro dépendances runtime et pas de plugins de build.
6
-
7
- La bonne nouvelle : Mado utilise les mêmes conventions que [lit](https://lit.dev), donc les
8
- outils IDE **prêts à l'emploi** de l'écosystème lit fonctionnent directement.
9
-
10
- ---
11
-
12
- ## VS Code (configuration recommandée)
13
-
14
- ### 1. Installer [lit-plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin)
15
-
16
- VS Code → Extensions → chercher **"lit-plugin"** (par runem) → Installer.
17
-
18
- Ce que vous obtenez :
19
-
20
- - Coloration HTML à l'intérieur de `html\`\``.
21
- - Coloration CSS à l'intérieur de `css\`\``.
22
- - Auto-complétion pour les tags HTML, attributs et événements.
23
- - Vérification des fautes de frappe dans les attributs.
24
- - Aller à la définition pour les custom elements (si décrits via `customElements.json` ou JSDoc).
25
- - Diagnostics sur les bindings invalides.
26
-
27
- ### 2. Spécifier les noms de tags
28
-
29
- `lit-plugin` cherche les identifiants `html` et `css` dans les imports. Si vous ne les
30
- renommez pas à l'import — la configuration est nulle, tout fonctionne :
31
-
32
- ```ts
33
- import { html, css } from "@madojs/mado";
34
-
35
- const tpl = html`<button @click=${fn}>${label}</button>`;
36
- ```
37
-
38
- ### 3. (Optionnel) Votre propre `customElements.json`
39
-
40
- Si vous voulez l'auto-complétion pour vos propres composants `<x-*>`, décrivez-les via
41
- [Custom Elements Manifest](https://github.com/webcomponents/custom-elements-manifest) :
42
-
43
- ```bash
44
- npm install --save-dev @custom-elements-manifest/analyzer
45
- npx cem analyze --globs "src/components/**/*.ts"
46
- ```
47
-
48
- Cela crée `custom-elements.json`, que `lit-plugin` récupère automatiquement.
49
-
50
- ---
51
-
52
- ## WebStorm / IntelliJ
53
-
54
- WebStorm comprend `html\`\`` et `css\`\`` **nativement** — support natif des template literals
55
- de style lit depuis 2021. Pas de plugins nécessaires.
56
-
57
- Si la coloration n'apparaît pas :
58
-
59
- - Settings → Languages & Frameworks → JavaScript → vérifiez que "Use types from server" est activé
60
- - Redémarrer le serveur TS : ⌘+⇧+P → "Restart TypeScript Server"
61
-
62
- ---
63
-
64
- ## Neovim / Helix
65
-
66
- Utilisez [`lit-html-server`](https://github.com/runem/lit-analyzer/tree/master/packages/lit-html-server)
67
- (serveur LSP du même auteur que lit-plugin) :
68
-
69
- ```bash
70
- npm install -g lit-html-server
71
- ```
72
-
73
- `init.lua` (pour `lspconfig`) :
74
-
75
- ```lua
76
- require('lspconfig').lit_html.setup{
77
- cmd = { 'lit-html-server', '--stdio' },
78
- filetypes = { 'typescript', 'javascript' },
79
- }
80
- ```
81
-
82
- ---
83
-
84
- ## Ce qui ne fonctionne PAS (limitations connues)
85
-
86
- - **Vérification de type des bindings de signal.** `html\`<input .value=${count}>\`` — `lit-plugin`
87
- attend une string, mais `count` est un `Signal<number>`. Supprimez avec `// @ts-expect-error`
88
- ou `<!-- @ts-ignore -->`. Sera amélioré en Phase 3+.
89
- - **Les directives personnalisées (`each`)** sont reconnues comme des fonctions ordinaires — sans
90
- sémantique spéciale dans le plugin.
91
- - **Les attributs avec préfixes `@`, `.`, `?`** sont parfois signalés comme des erreurs si
92
- `lit-plugin` a `"no-unknown-attribute": false` désactivé. Dans `.vscode/settings.json` :
93
-
94
- ```json
95
- {
96
- "lit-plugin.rules": {
97
- "no-unknown-attribute": "off",
98
- "no-incompatible-type-binding": "off"
99
- }
100
- }
101
- ```
102
-
103
- ---
104
-
105
- ## Typage JSDoc pour les composants
106
-
107
- Pour que l'IDE récupère les custom elements à l'intérieur de `html\`\``, annotez la
108
- définition `component()` via JSDoc :
109
-
110
- ```ts
111
- /**
112
- * @element x-counter
113
- * @attr {number} initial - valeur de départ
114
- * @fires {CustomEvent<number>} change - à chaque changement
115
- */
116
- component("x-counter", () => {
117
- /* ... */
118
- });
119
- ```
120
-
121
- `lit-plugin` le reconnaît et suggère des attributs quand vous tapez `<x-counter ...>`.
122
-
123
- ---
124
-
125
- ## Prettier / formatage
126
-
127
- Prettier 3.0+ formate `html\`\`` via [`@prettier/plugin-xml`](https://github.com/prettier/plugin-xml)
128
- ou le mode intégré. `.prettierrc` minimal :
129
-
130
- ```json
131
- {
132
- "semi": true,
133
- "singleQuote": false,
134
- "embeddedLanguageFormatting": "auto"
135
- }
136
- ```
137
-
138
- `embeddedLanguageFormatting: "auto"` (par défaut) formate le contenu des tagged-template
139
- literals avec des tags connus (`html`, `css`).
140
-
141
- ---
142
-
143
- ## ESLint
144
-
145
- Si vous utilisez ESLint, le plugin [`eslint-plugin-lit`](https://github.com/43081j/eslint-plugin-lit)
146
- fournit des règles spécifiques au HTML en tagged-template, et
147
- [`eslint-plugin-wc`](https://github.com/43081j/eslint-plugin-wc) couvre les Web Components
148
- en général. La configuration est à votre discrétion, elle n'est pas obligatoire.
149
-
150
- ---
151
-
152
- ## TL;DR
153
-
154
- | Éditeur | Configuration | Niveau DX |
155
- |---|---|---|
156
- | **VS Code** | installer `lit-plugin` | ★★★★ |
157
- | **WebStorm** | rien | ★★★★ |
158
- | **Neovim/Helix** | `lit-html-server` via LSP | ★★★ |
159
- | **Vim sans LSP** | manuel | ★ |
160
-
161
- Mado fonctionne aussi sans plugin IDE : `html\`\`` reste du code TS valide, tout se
162
- compile et s'exécute. La string à l'intérieur est juste colorée comme une string.
@@ -1,193 +0,0 @@
1
- # Pourquoi Mado (et pourquoi pas Lit / Solid / Alpine / htmx)
2
-
3
- > Si vous choisissez un stack frontend pour un nouveau projet, cette page est pour vous.
4
- > Si vous avez déjà quelque chose qui fonctionne — **ne migrez pas pour le plaisir de migrer**, ça coûte toujours plus cher qu'il n'y paraît.
5
-
6
- Mado n'est pas un "tueur" de React/Vue/Svelte. C'est un outil spécialisé. J'explique ici honnêtement **dans quels cas Mado est vraiment meilleur que les alternatives**, et dans lesquels il ne l'est pas.
7
-
8
- ---
9
-
10
- ## TL;DR — un seul tableau
11
-
12
- | Si vous vous souciez de… | Choisissez |
13
- |---|---|
14
- | Meilleure infrastructure d'apprentissage / grand écosystème | **React** ou **Vue** |
15
- | Design system de composants pour l'intégration dans n'importe quel framework | **Lit** |
16
- | Top performance sur les grandes listes, "proche du vanilla" avec JSX | **Solid** ou **Svelte 5** |
17
- | Amélioration progressive d'apps classiques rendues côté serveur | **htmx** + votre backend |
18
- | "Saupoudrer" de la réactivité sur un site statique | **Alpine.js** |
19
- | Outillage minimal, maximum de plateforme, tout dans une boîte (router + data + forms + SEO), lisible en une soirée | **Mado** ✓ |
20
-
21
- Si votre cas ne tombe pas dans le dernier point — Mado n'est probablement pas le meilleur choix. C'est normal.
22
-
23
- ---
24
-
25
- ## Mado vs Lit
26
-
27
- **Lit** est l'alternative la plus proche dans l'esprit. Même approche : Web Components + tagged templates + magie minimale.
28
-
29
- | | Lit | Mado |
30
- |---|---|---|
31
- | Taille | ~6 Ko | ~16 Ko |
32
- | Âge / support | ~10 ans, Google | 6 mois, auteur unique |
33
- | Réactivité | décorateurs `@property` + `requestUpdate` manuel | signals (`signal`/`computed`/`effect`) intégrés |
34
- | Router | aucun, vous devez en trouver un (`@lit-labs/router`, etc.) | inclus : `routes()` + layout groups + prefetch |
35
- | Chargement de données | aucun, vous devez l'assembler | `resource()` + `mutation()` + invalidation glob |
36
- | Forms | aucun | `useForm()` avec contraintes proches du HTML |
37
- | SEO / statique | complexe (`@lit-labs/ssr`) | `bake` (linkedom) + edge-prerender |
38
- | Build | nécessite des plugins spécifiques au framework | Vite transport + runtime natif |
39
- | Style de code | classes + décorateurs | fonctions + tagged templates |
40
- | Écosystème | réel (Shoelace, Material Web, etc.) | aucun |
41
- | Quand choisir | écrire un design system / bibliothèque Web Components pour l'intégration | écrire une application complète, vouloir tout dans une boîte |
42
-
43
- **Pitch honnête :** *"Lit est meilleur si vous écrivez un design system de composants. Mado est meilleur si vous écrivez une application et voulez des batteries incluses sans assembler 8 packages."*
44
-
45
- ---
46
-
47
- ## Mado vs Solid
48
-
49
- **Solid** est une bibliothèque réactive de premier plan construite sur les signals. Techniquement très impressionnant.
50
-
51
- | | Solid | Mado |
52
- |---|---|---|
53
- | Taille | ~7 Ko | ~16 Ko |
54
- | Performance | top-3 sur js-framework-benchmark | bonne, mais pas au top |
55
- | Réactivité | signals (même classe d'idées) | signals |
56
- | Templates | JSX (compilé en expressions réactives) | tagged template `html\`\`` |
57
- | Modèle de composant | fonctions, nœuds virtuels Solid | Web Components |
58
- | Build | Vite + babel-plugin-solid requis | Vite pour dev/build, aucune dépendance runtime |
59
- | Router | `@solidjs/router` | inclus |
60
- | Données | `createResource` | `resource()` |
61
- | SSR | sérieusement supporté (SolidStart) | intentionnellement absent |
62
- | Écosystème | en croissance, ~50 packages | aucun |
63
- | Quand choisir | besoin de top performance + JSX + prêt à configurer le build | vouloir un runtime browser-native avec tooling simple |
64
-
65
- **Pitch honnête :** *"Solid est techniquement plus rapide et plus mature. Mado est plus simple dans son idée : runtime browser-native, Web Components, tagged templates, et Vite fait le travail dev/build ennuyeux. Si vous voulez JSX et un écosystème plus large, allez avec Solid."*
66
-
67
- ---
68
-
69
- ## Mado vs Svelte 5
70
-
71
- **Svelte 5** avec les runes — aussi un modèle signal, aussi minimaliste.
72
-
73
- | | Svelte 5 | Mado |
74
- |---|---|---|
75
- | Taille runtime | ~3 Ko | ~16 Ko |
76
- | Compilateur | requis (.svelte → JS) | aucun |
77
- | Syntaxe | format .svelte personnalisé | TS + tagged templates |
78
- | Réactivité | `$state`/`$derived` (runes) | `signal`/`computed` |
79
- | SSR / SvelteKit | complet, mature | intentionnellement absent |
80
- | Écosystème | large, excellents dev-tools | aucun |
81
- | Quand choisir | nouveau projet de production avec une équipe | outil privé/interne, besoin de simplicité |
82
-
83
- **Pitch honnête :** *"Svelte est un choix produit. Mado est un choix ingénierie. Si vous avez une équipe et une app de production — Svelte. Si vous êtes seul et voulez le contrôle — Mado."*
84
-
85
- ---
86
-
87
- ## Mado vs htmx
88
-
89
- **htmx** est une autre école : des fragments HTML sur le fil.
90
-
91
- | | htmx | Mado |
92
- |---|---|---|
93
- | Architecture | HTML du serveur, mis à jour via des fragments | SPA : JS charge les données, se rend lui-même |
94
- | Dépendance backend | forte (le backend doit pouvoir servir du HTML) | faible (le backend est une API JSON) |
95
- | État client | minimal (cookies, localStorage) | complet (signal, persisted) |
96
- | Mises à jour optimistes | difficiles | faciles (mutation + invalidates) |
97
- | Offline / PWA | faible | correct |
98
- | Taille | ~14 Ko | ~16 Ko |
99
- | Quand choisir | app classique rendue côté serveur (Rails, Django, Phoenix), besoin de "revitaliser" | expérience SPA requise, backend est REST/GraphQL |
100
-
101
- **Pitch honnête :** *"htmx — si le backend est solide et peut servir du HTML. Mado — si le backend sert du JSON et que vous avez besoin d'une expérience SPA complète."*
102
-
103
- ---
104
-
105
- ## Mado vs Alpine.js
106
-
107
- **Alpine** — attributs réactifs directement dans le HTML.
108
-
109
- | | Alpine | Mado |
110
- |---|---|---|
111
- | Objectif | améliorer du HTML statique | SPA complet |
112
- | Taille | ~7 Ko | ~16 Ko |
113
- | Gestion d'état | `x-data` localement | signals + context + persisted |
114
- | Routage | aucun | inclus |
115
- | TypeScript | faible | première classe |
116
- | Quand choisir | sites statiques, landing pages, besoin de 5 boutons interactifs | app complète : pages, navigation, forms, données |
117
-
118
- **Pitch honnête :** *"Alpine — pour l'interactivité sur les sites statiques. Mado — pour une application complète."*
119
-
120
- ---
121
-
122
- ## Mado vs React + écosystème
123
-
124
- Je ne vais pas m'étendre là-dessus longtemps, car React est dans une **catégorie différente** en termes d'écosystème et de maturité. Mais si vous comparez sérieusement :
125
-
126
- **React gagne :**
127
- - écosystème massif : milliers de kits UI, milliers d'articles, tutoriels infinis ;
128
- - les assistants IA (ChatGPT, Copilot) connaissent React mieux que tout ;
129
- - meilleur marché de l'emploi ;
130
- - meilleur support SSR (Next.js).
131
-
132
- **Mado gagne :**
133
- - taille de bundle des dizaines de fois plus petite ;
134
- - zéro infrastructure (pas de Vite, pas de Babel, pas de 200 packages) ;
135
- - lisible en une soirée — si quelque chose casse, ouvrez `src/` ;
136
- - signals au lieu de hooks (pas de règles "ne peut pas être utilisé dans un if", pas de pièges de stale-closure) ;
137
- - pas besoin de migrer entre les versions majeures.
138
-
139
- **Quand choisir Mado plutôt que React :**
140
- - projet de 1–3 personnes, pour des années à venir ;
141
- - la taille du bundle est critique ;
142
- - vous êtes fatigué du React fatigue et prêt à sacrifier l'écosystème pour la simplicité.
143
-
144
- **Quand choisir React :**
145
- - équipe de 5 personnes ou plus ;
146
- - vous avez besoin de kits UI, vous avez besoin de l'écosystème ;
147
- - un projet qui recrutera de nouvelles personnes sur le marché ;
148
- - vous avez besoin de SSR avec hydratation (Next.js).
149
-
150
- ---
151
-
152
- ## L'argument le plus fort de Mado
153
-
154
- Pas la taille, pas la performance, pas les signals — tout a de meilleurs concurrents.
155
-
156
- > **"Ouvrez le source et lisez-le en une soirée. ~3500 lignes, petits modules. Si quelque chose casse — vous n'allez pas sur une issue avec 3000 commentaires. Vous allez dans `src/router/` et lisez le code."**
157
-
158
- C'est ce qu'on appelle la **propriété** — vous possédez le code, plutôt que de dépendre de celui de quelqu'un d'autre.
159
-
160
- Pour les développeurs backend habitués aux petites bibliothèques compréhensibles (chi en Go, axum en Rust, FastAPI en Python), c'est un **sentiment familier**. Pour ceux à qui ça n'importe pas — prenez ce qui est plus grand et plus mature.
161
-
162
- ---
163
-
164
- ## Qu'en est-il de la performance ?
165
-
166
- Honnêtement : **Mado n'est pas le plus rapide**. Le top-3 sur js-framework-benchmark sont Solid, Inferno et Svelte. Mado est plus proche de Lit / Preact en termes de caractéristiques.
167
-
168
- Ce que Mado fait pour la performance par défaut :
169
- - **`computed` lazy** (dirty-flag, pas eager) ;
170
- - **planificateur de microtâche par batch** pour `signal.set` ;
171
- - **réconciliation par clé** dans `each()` avec réutilisation réelle du DOM ;
172
- - **rendu synchrone** pour les pages en cache dans le router ;
173
- - **hover-prefetch** pour les chunks lazy ;
174
- - **View Transitions API** pour des transitions fluides ;
175
- - **`adoptedStyleSheets` partagés** pour le CSS ;
176
- - **hints `modulepreload`** sur le serveur de développement.
177
-
178
- C'est suffisant pour la plupart des applications. Si vous construisez Excel dans le navigateur ou une visualisation WebGL à 60fps — ce n'est pas ici (c'est Solid ou du JS natif).
179
-
180
- ---
181
-
182
- ## Résumé
183
-
184
- Mado est un outil **ciblé** avec un positionnement honnête. Il est le plus fort quand :
185
-
186
- 1. Vous voulez **posséder** le code et le lire en entier.
187
- 2. La **simplicité d'infrastructure** est critique (pas de Vite/Webpack/Babel).
188
- 3. Vous avez besoin de **batteries dans une boîte** (router + données + forms + SEO).
189
- 4. Vous n'êtes pas junior et n'avez pas peur des Web Components.
190
-
191
- Si même un seul point ne s'applique pas à vous — prenez une alternative du tableau ci-dessus. Ne vous battez pas avec un outil qui ne convient pas.
192
-
193
- — L'auteur de Mado, ex-développeur React passé au backend qui maintenant colle des frontends dans ses temps libres.