@madojs/mado 0.11.0 → 0.12.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.
- package/AGENTS.md +102 -25
- package/CHANGELOG.md +185 -1
- package/README.md +137 -172
- package/dist/src/component.d.ts +3 -2
- package/dist/src/component.js +98 -6
- package/dist/src/component.js.map +1 -1
- package/dist/src/css.js +34 -5
- package/dist/src/css.js.map +1 -1
- package/dist/src/head.d.ts +6 -6
- package/dist/src/head.js +6 -6
- package/dist/src/html/bindings.js +3 -3
- package/dist/src/html/bindings.js.map +1 -1
- package/dist/src/html/parser.d.ts +1 -1
- package/dist/src/html/parser.js +1 -1
- package/dist/src/html/template.js +24 -10
- package/dist/src/html/template.js.map +1 -1
- package/dist/src/index.d.ts +8 -4
- package/dist/src/index.js +13 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/page.d.ts +62 -28
- package/dist/src/page.js +5 -0
- package/dist/src/page.js.map +1 -1
- package/dist/src/resource.js +2 -1
- package/dist/src/resource.js.map +1 -1
- package/dist/src/router/base.d.ts +65 -0
- package/dist/src/router/base.js +168 -0
- package/dist/src/router/base.js.map +1 -0
- package/dist/src/router/manifest.js +75 -31
- package/dist/src/router/manifest.js.map +1 -1
- package/dist/src/router/match.d.ts +16 -2
- package/dist/src/router/match.js +41 -1
- package/dist/src/router/match.js.map +1 -1
- package/dist/src/router/navigation.js +58 -9
- package/dist/src/router/navigation.js.map +1 -1
- package/dist/src/static-runtime.d.ts +81 -0
- package/dist/src/static-runtime.js +209 -0
- package/dist/src/static-runtime.js.map +1 -0
- package/dist/src/vite/index.d.ts +31 -3
- package/dist/src/vite/index.js +49 -18
- package/dist/src/vite/index.js.map +1 -1
- package/docs/README.md +5 -8
- package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
- package/docs/en/00-the-mado-way.md +1 -1
- package/docs/en/01-quickstart.md +183 -0
- package/docs/en/10-pages-and-components.md +271 -0
- package/docs/en/11-templates-and-signals.md +211 -0
- package/docs/en/12-routing.md +229 -0
- package/docs/en/13-data.md +225 -0
- package/docs/en/14-forms.md +244 -0
- package/docs/en/15-static-snapshots.md +181 -0
- package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +53 -2
- package/docs/en/{13-deployment.md → 20-deployment.md} +59 -10
- package/docs/en/{14-testing.md → 22-testing.md} +6 -5
- package/docs/en/23-cookbook.md +292 -0
- package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +12 -3
- package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +3 -3
- package/docs/en/40-llm-guide.md +776 -0
- package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +15 -16
- package/docs/en/{05-why-mado.md → 42-why-mado.md} +1 -1
- package/docs/en/README.md +97 -27
- package/docs/recipes/nginx/Containerfile +26 -0
- package/docs/recipes/nginx/nginx.conf +42 -0
- package/llms.txt +246 -211
- package/package.json +17 -10
- package/scripts/bake.mjs +4 -568
- package/scripts/cli/generate.mjs +55 -5
- package/scripts/cli/help.mjs +11 -5
- package/scripts/cli/index.mjs +20 -4
- package/scripts/cli/init.mjs +7 -2
- package/scripts/cli/release.mjs +20 -68
- package/scripts/docs-lint.mjs +170 -0
- package/scripts/package-smoke.mjs +67 -9
- package/scripts/preview.mjs +95 -6
- package/scripts/size-budget.mjs +5 -1
- package/scripts/static/browser.mjs +654 -0
- package/scripts/static/discover.mjs +281 -0
- package/scripts/static/output.mjs +141 -0
- package/scripts/static/serialize.mjs +212 -0
- package/scripts/static/server.mjs +167 -0
- package/scripts/static.mjs +191 -0
- package/starters/default/README.md +57 -55
- package/starters/default/package.json +3 -9
- package/starters/default/src/app.routes.ts +20 -33
- package/starters/default/src/components/feature-card.component.ts +40 -0
- package/starters/default/src/components/live-counter.component.ts +57 -0
- package/starters/default/src/content/guides.ts +55 -0
- package/starters/default/src/main.ts +9 -13
- package/starters/default/src/pages/app.page.ts +41 -0
- package/starters/default/src/pages/guide.page.ts +40 -0
- package/starters/default/src/pages/home.page.ts +49 -0
- package/starters/default/src/pages/not-found.page.ts +18 -0
- package/starters/default/src/styles/document.css +39 -0
- package/starters/default/src/styles/reset.css +37 -0
- package/starters/default/src/styles/tokens.css +30 -0
- package/starters/default/src/styles.d.ts +3 -1
- package/starters/default/src/vite-env.d.ts +1 -1
- package/starters/default/vite.config.ts +14 -1
- package/starters/modular/README.md +142 -0
- package/starters/modular/index.html +13 -0
- package/starters/modular/package.json +30 -0
- package/starters/modular/src/app.routes.ts +39 -0
- package/starters/{default → modular}/src/layouts/app-shell.layout.ts +8 -5
- package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
- package/starters/modular/src/main.ts +16 -0
- package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +3 -3
- package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
- package/starters/modular/src/modules/home/not-found.page.ts +14 -0
- package/starters/modular/src/styles.d.ts +1 -0
- package/starters/modular/src/vite-env.d.ts +1 -0
- package/starters/modular/tsconfig.json +24 -0
- package/starters/modular/vite.config.ts +131 -0
- package/TODO.md +0 -79
- package/docs/en/01-routing.md +0 -152
- package/docs/en/02-project-layout.md +0 -124
- package/docs/en/03-static-bake.md +0 -249
- package/docs/en/04-ide-setup.md +0 -162
- package/docs/en/07-llm-pitfalls.md +0 -724
- package/docs/en/08-llm-zero-history-test.md +0 -56
- package/docs/en/09-shadow-vs-light-dom.md +0 -174
- package/docs/en/11-layouts.md +0 -113
- package/docs/en/12-auth-and-api.md +0 -124
- package/docs/en/16-bake-cookbook.md +0 -100
- package/docs/en/17-shadow-dom-forms.md +0 -192
- package/docs/fr/00-the-mado-way.md +0 -85
- package/docs/fr/01-routing.md +0 -120
- package/docs/fr/02-project-layout.md +0 -84
- package/docs/fr/03-static-bake.md +0 -289
- package/docs/fr/04-ide-setup.md +0 -162
- package/docs/fr/05-why-mado.md +0 -193
- package/docs/fr/06-for-backenders.md +0 -438
- package/docs/fr/07-llm-pitfalls.md +0 -625
- package/docs/fr/08-llm-zero-history-test.md +0 -38
- package/docs/fr/09-shadow-vs-light-dom.md +0 -65
- package/docs/fr/10-app-architecture.md +0 -138
- package/docs/fr/11-layouts.md +0 -47
- package/docs/fr/12-auth-and-api.md +0 -76
- package/docs/fr/13-deployment.md +0 -57
- package/docs/fr/14-testing.md +0 -41
- package/docs/fr/15-error-handling.md +0 -50
- package/docs/fr/16-bake-cookbook.md +0 -88
- package/docs/fr/17-shadow-dom-forms.md +0 -196
- package/docs/fr/18-api-freeze-map.md +0 -63
- package/docs/fr/19-reactivity-ordering.md +0 -97
- package/docs/fr/20-v1-stability.md +0 -88
- package/docs/fr/README.md +0 -27
- package/docs/ru/00-the-mado-way.md +0 -84
- package/docs/ru/01-routing.md +0 -119
- package/docs/ru/02-project-layout.md +0 -84
- package/docs/ru/03-static-bake.md +0 -250
- package/docs/ru/04-ide-setup.md +0 -144
- package/docs/ru/05-why-mado.md +0 -193
- package/docs/ru/06-for-backenders.md +0 -428
- package/docs/ru/07-llm-pitfalls.md +0 -624
- package/docs/ru/08-llm-zero-history-test.md +0 -57
- package/docs/ru/09-shadow-vs-light-dom.md +0 -63
- package/docs/ru/10-app-architecture.md +0 -152
- package/docs/ru/11-layouts.md +0 -47
- package/docs/ru/12-auth-and-api.md +0 -75
- package/docs/ru/13-deployment.md +0 -66
- package/docs/ru/14-testing.md +0 -50
- package/docs/ru/15-error-handling.md +0 -56
- package/docs/ru/16-bake-cookbook.md +0 -95
- package/docs/ru/17-shadow-dom-forms.md +0 -193
- package/docs/ru/18-api-freeze-map.md +0 -64
- package/docs/ru/19-reactivity-ordering.md +0 -95
- package/docs/ru/20-v1-stability.md +0 -82
- package/docs/ru/README.md +0 -25
- package/docs/uk/00-the-mado-way.md +0 -82
- package/docs/uk/01-routing.md +0 -76
- package/docs/uk/02-project-layout.md +0 -73
- package/docs/uk/03-static-bake.md +0 -48
- package/docs/uk/04-ide-setup.md +0 -26
- package/docs/uk/05-why-mado.md +0 -34
- package/docs/uk/06-for-backenders.md +0 -55
- package/docs/uk/07-llm-pitfalls.md +0 -145
- package/docs/uk/08-llm-zero-history-test.md +0 -34
- package/docs/uk/09-shadow-vs-light-dom.md +0 -58
- package/docs/uk/10-app-architecture.md +0 -97
- package/docs/uk/11-layouts.md +0 -47
- package/docs/uk/12-auth-and-api.md +0 -70
- package/docs/uk/13-deployment.md +0 -40
- package/docs/uk/14-testing.md +0 -34
- package/docs/uk/15-error-handling.md +0 -32
- package/docs/uk/16-bake-cookbook.md +0 -36
- package/docs/uk/17-shadow-dom-forms.md +0 -193
- package/docs/uk/18-api-freeze-map.md +0 -61
- package/docs/uk/19-reactivity-ordering.md +0 -95
- package/docs/uk/20-v1-stability.md +0 -83
- package/docs/uk/README.md +0 -27
- package/starters/default/src/modules/home/not-found.page.ts +0 -11
- /package/docs/en/{15-error-handling.md → 21-error-handling.md} +0 -0
- /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
- /package/starters/{default → modular}/.editorconfig +0 -0
- /package/starters/{default → modular}/eslint.config.mjs +0 -0
- /package/starters/{default → modular}/public/favicon.svg +0 -0
- /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/login.page.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +0 -0
- /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
- /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
- /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
- /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
- /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
- /package/starters/{default → modular}/src/shared/styles/reset.css +0 -0
- /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
- /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
- /package/starters/{default → modular}/src/shared/ui/x-button.component.ts +0 -0
- /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# Shadow DOM vs Light DOM
|
|
2
|
-
|
|
3
|
-
Les composants Mado utilisent Shadow DOM par défaut. C'est un bon défaut pour
|
|
4
|
-
les widgets autonomes, mais les zones d'application et les pages restent
|
|
5
|
-
généralement de simples templates light DOM.
|
|
6
|
-
|
|
7
|
-
## Règle
|
|
8
|
-
|
|
9
|
-
Utilisez les route layouts pour les zones d'application :
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
export default page({
|
|
13
|
-
view: ({ child }) => html`<main class="app-main">${child}</main>`,
|
|
14
|
-
});
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Ces fichiers vivent dans `src/layouts/` et sont composés depuis
|
|
18
|
-
`src/app.routes.ts` avec `layout()`. Ils sont stylés par
|
|
19
|
-
`src/shared/styles/shell.css`.
|
|
20
|
-
|
|
21
|
-
Utilisez les page files pour les écrans :
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
export default page({
|
|
25
|
-
view: () => html`<section><h1>Users</h1></section>`,
|
|
26
|
-
});
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Les tables, forms, prose et états simples de page sont stylés par
|
|
30
|
-
`src/shared/styles/content.css`.
|
|
31
|
-
|
|
32
|
-
Utilisez Shadow DOM components pour les widgets feuilles :
|
|
33
|
-
|
|
34
|
-
- buttons, badges, cards, metrics ;
|
|
35
|
-
- spinners, modals, toasts ;
|
|
36
|
-
- widgets qui doivent posséder leur CSS.
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
component("x-status-badge", ({ attr }) => {
|
|
40
|
-
const status = attr("status", "draft");
|
|
41
|
-
return () => html`<span>${status}</span>`;
|
|
42
|
-
}, {
|
|
43
|
-
styles: css`
|
|
44
|
-
:host { display: inline-block; }
|
|
45
|
-
span { color: var(--color-text-muted); }
|
|
46
|
-
`,
|
|
47
|
-
});
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Comment les styles se comportent
|
|
51
|
-
|
|
52
|
-
- `tokens.css` définit des CSS custom properties ; `var(...)` traverse Shadow
|
|
53
|
-
DOM.
|
|
54
|
-
- `reset.css`, `shell.css`, `content.css` s'appliquent seulement au document /
|
|
55
|
-
light DOM.
|
|
56
|
-
- Les sélecteurs de classe comme `.data`, `.app-main`, `.error` ne traversent
|
|
57
|
-
pas Shadow DOM.
|
|
58
|
-
- Les styles locaux des composants vivent dans ``css`...` `` dans les options de
|
|
59
|
-
`component()`.
|
|
60
|
-
- Si un Shadow component accepte des enfants, utilisez `<slot>` et stylisez le
|
|
61
|
-
frame dans les styles du composant.
|
|
62
|
-
|
|
63
|
-
Si une page semble sans style, vous avez probablement utilisé des classes
|
|
64
|
-
globales dans un Shadow DOM component. Déplacez le markup dans une page/layout
|
|
65
|
-
ou déplacez le CSS dans les styles du composant.
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
# Architecture d'application
|
|
2
|
-
|
|
3
|
-
Le starter officiel est la forme canonique d'une application Mado en
|
|
4
|
-
production. Ce n'est pas un framework dans le framework : seulement des
|
|
5
|
-
fichiers, des imports, les primitives Mado et des limites ESLint.
|
|
6
|
-
|
|
7
|
-
## Structure
|
|
8
|
-
|
|
9
|
-
```txt
|
|
10
|
-
src/
|
|
11
|
-
├── main.ts
|
|
12
|
-
├── app.routes.ts
|
|
13
|
-
├── layouts/
|
|
14
|
-
│ ├── app-shell.layout.ts
|
|
15
|
-
│ └── auth-shell.layout.ts
|
|
16
|
-
├── shared/
|
|
17
|
-
│ ├── http/
|
|
18
|
-
│ ├── lib/
|
|
19
|
-
│ ├── styles/
|
|
20
|
-
│ └── ui/
|
|
21
|
-
└── modules/
|
|
22
|
-
├── auth/
|
|
23
|
-
│ ├── auth.routes.ts
|
|
24
|
-
│ ├── auth.public.ts
|
|
25
|
-
│ ├── auth.service.ts
|
|
26
|
-
│ ├── auth.connector.ts
|
|
27
|
-
│ ├── auth.guard.ts
|
|
28
|
-
│ ├── login.page.ts
|
|
29
|
-
│ └── _contracts/
|
|
30
|
-
└── billing/
|
|
31
|
-
├── billing.routes.ts
|
|
32
|
-
├── billing.public.ts
|
|
33
|
-
├── billing.types.ts
|
|
34
|
-
├── api/
|
|
35
|
-
├── data/
|
|
36
|
-
├── pages/
|
|
37
|
-
├── components/
|
|
38
|
-
└── _contracts/
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## App Map
|
|
42
|
-
|
|
43
|
-
`src/app.routes.ts` est la carte de toute l'application. Les modules exportent
|
|
44
|
-
des route maps simples ; les app routes décident quel shell et quel guard
|
|
45
|
-
enveloppent chaque zone.
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
import { layout, routes } from "@madojs/mado";
|
|
49
|
-
import { requireAuth } from "./modules/auth/auth.public";
|
|
50
|
-
import { authRoutes } from "./modules/auth/auth.routes";
|
|
51
|
-
import { billingRoutes } from "./modules/billing/billing.routes";
|
|
52
|
-
|
|
53
|
-
export const manifest = {
|
|
54
|
-
"/": () => import("./modules/home/home.page"),
|
|
55
|
-
"/login": layout({
|
|
56
|
-
layout: () => import("./layouts/auth-shell.layout"),
|
|
57
|
-
routes: authRoutes,
|
|
58
|
-
}),
|
|
59
|
-
"/billing": layout({
|
|
60
|
-
layout: () => import("./layouts/app-shell.layout"),
|
|
61
|
-
guard: requireAuth,
|
|
62
|
-
routes: billingRoutes,
|
|
63
|
-
}),
|
|
64
|
-
"*": () => import("./modules/home/not-found.page"),
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export default routes(manifest);
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Rules:
|
|
71
|
-
|
|
72
|
-
- Export `manifest` pour `mado bake`.
|
|
73
|
-
- Les modules n'appellent jamais `layout()`.
|
|
74
|
-
- Les layouts décrivent des zones d'application, pas des domaines.
|
|
75
|
-
- Ne cachez pas le router dans un custom element ou un second shell dans
|
|
76
|
-
`main.ts`.
|
|
77
|
-
|
|
78
|
-
## File Forms
|
|
79
|
-
|
|
80
|
-
| Suffix | Role |
|
|
81
|
-
| --- | --- |
|
|
82
|
-
| `*.page.ts` | route page, default `page({...})` |
|
|
83
|
-
| `*.layout.ts` | app-zone wrapper, default `page(...)` |
|
|
84
|
-
| `*.connector.ts` | one external API system |
|
|
85
|
-
| `*.resource.ts` | `resource()` and `mutation()` layer |
|
|
86
|
-
| `*.service.ts` | module singleton state |
|
|
87
|
-
| `*.guard.ts` | route guard |
|
|
88
|
-
| `*.routes.ts` | module-local route map |
|
|
89
|
-
| `*.public.ts` | only public module surface |
|
|
90
|
-
| `*.types.ts` | domain types |
|
|
91
|
-
| `*.component.ts` | Web Component registration |
|
|
92
|
-
|
|
93
|
-
Les signals, resources et forms locaux à une page vivent dans `view()`. L'état
|
|
94
|
-
partagé par un module vit dans `*.service.ts`.
|
|
95
|
-
|
|
96
|
-
## Data Flow
|
|
97
|
-
|
|
98
|
-
```txt
|
|
99
|
-
shared/http/http-client.ts
|
|
100
|
-
▲
|
|
101
|
-
modules/<x>/api/*.connector.ts DTO -> domain mapping
|
|
102
|
-
▲
|
|
103
|
-
modules/<x>/data/*.resource.ts cache keys + mutations
|
|
104
|
-
▲
|
|
105
|
-
modules/<x>/pages/*.page.ts UI consumes domain types
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Styles
|
|
109
|
-
|
|
110
|
-
| File | Role |
|
|
111
|
-
| --- | --- |
|
|
112
|
-
| `src/shared/styles/tokens.css` | design tokens as CSS custom properties |
|
|
113
|
-
| `src/shared/styles/reset.css` | document/light DOM reset |
|
|
114
|
-
| `src/shared/styles/shell.css` | app-zone layouts from `src/layouts/` |
|
|
115
|
-
| `src/shared/styles/content.css` | page-level forms, tables, prose and states |
|
|
116
|
-
|
|
117
|
-
Les composants feuilles gardent leurs styles dans ``css`...` `` dans les
|
|
118
|
-
options de `component()` et dépendent des tokens, pas de classes globales.
|
|
119
|
-
|
|
120
|
-
`vite.config.ts` active le transformer Lightning CSS de Vite. Mado ne possède
|
|
121
|
-
pas le prefixing, le lowering CSS ou la minification.
|
|
122
|
-
|
|
123
|
-
## CLI
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
mado new module billing
|
|
127
|
-
mado new page billing/pages/invoices-list
|
|
128
|
-
mado new connector billing/api/stripe
|
|
129
|
-
mado new resource billing/data/invoices
|
|
130
|
-
mado new service billing/cart
|
|
131
|
-
mado new form billing/invoice
|
|
132
|
-
mado new component billing/components/invoice-status-badge
|
|
133
|
-
mado new guard billing/billing
|
|
134
|
-
mado new layout app-shell
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Le générateur écrit seulement de nouveaux fichiers. Il ne modifie pas
|
|
138
|
-
`app.routes.ts`.
|
package/docs/fr/11-layouts.md
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Layouts
|
|
2
|
-
|
|
3
|
-
Le chemin recommandé pour les layouts Mado est un route group dans
|
|
4
|
-
`src/app.routes.ts`. Ne mettez pas un shell global dans `main.ts` si l'app a
|
|
5
|
-
plusieurs zones : public, auth, app, embed.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { layout, routes } from "@madojs/mado";
|
|
9
|
-
import { requireAuth } from "./modules/auth/auth.public";
|
|
10
|
-
import { authRoutes } from "./modules/auth/auth.routes";
|
|
11
|
-
import { billingRoutes } from "./modules/billing/billing.routes";
|
|
12
|
-
|
|
13
|
-
export const manifest = {
|
|
14
|
-
"/": () => import("./modules/home/home.page.js"),
|
|
15
|
-
"/login": layout({
|
|
16
|
-
layout: () => import("./layouts/auth-shell.layout.js"),
|
|
17
|
-
routes: authRoutes,
|
|
18
|
-
}),
|
|
19
|
-
"/billing": layout({
|
|
20
|
-
layout: () => import("./layouts/app-shell.layout.js"),
|
|
21
|
-
guard: requireAuth,
|
|
22
|
-
routes: billingRoutes,
|
|
23
|
-
}),
|
|
24
|
-
"*": () => import("./modules/home/not-found.page.js"),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default routes(manifest);
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Un layout est une `page({ view })` qui rend `child` :
|
|
31
|
-
|
|
32
|
-
```ts
|
|
33
|
-
export default page({
|
|
34
|
-
view: ({ child }) => html`
|
|
35
|
-
<div class="layout layout--app">
|
|
36
|
-
<main class="app-main">${child}</main>
|
|
37
|
-
</div>
|
|
38
|
-
`,
|
|
39
|
-
});
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Rules:
|
|
43
|
-
|
|
44
|
-
- one shell per route group, not per page;
|
|
45
|
-
- modules export plain route maps and do not call `layout()`;
|
|
46
|
-
- a guard on the group protects the whole subtree;
|
|
47
|
-
- layout view stays stateless; page-local state lives in pages/components/resources.
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Auth et API
|
|
2
|
-
|
|
3
|
-
Le starter par défaut est la recette recommandée. La mécanique HTTP vit dans
|
|
4
|
-
`src/shared/http/`, l'état auth dans `src/modules/auth/`.
|
|
5
|
-
|
|
6
|
-
```txt
|
|
7
|
-
src/shared/http/
|
|
8
|
-
http-client.ts
|
|
9
|
-
http-error.ts
|
|
10
|
-
interceptors.ts
|
|
11
|
-
|
|
12
|
-
src/modules/auth/
|
|
13
|
-
auth.connector.ts
|
|
14
|
-
auth.service.ts
|
|
15
|
-
auth.guard.ts
|
|
16
|
-
auth.routes.ts
|
|
17
|
-
auth.public.ts
|
|
18
|
-
_contracts/
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Flow pour un business module :
|
|
22
|
-
|
|
23
|
-
```txt
|
|
24
|
-
connector -> resource/mutation -> page
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Les pages n'importent pas de DTOs et n'appellent pas `fetch()` directement. Les
|
|
28
|
-
connectors n'importent pas la réactivité Mado ou l'UI.
|
|
29
|
-
|
|
30
|
-
## Auth Service
|
|
31
|
-
|
|
32
|
-
Auth state est un ES module singleton :
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
const _user = signal<User | null>(null);
|
|
36
|
-
const _token = signal<string | null>(null);
|
|
37
|
-
|
|
38
|
-
export const user = () => _user();
|
|
39
|
-
export const isAuthed = computed(() => _user() !== null);
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Exposez seulement la surface nécessaire via `auth.public.ts`.
|
|
43
|
-
|
|
44
|
-
## Guards
|
|
45
|
-
|
|
46
|
-
```ts
|
|
47
|
-
export function requireAuth(): boolean | string {
|
|
48
|
-
if (isAuthed()) return true;
|
|
49
|
-
return "/login";
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Use in `src/app.routes.ts`:
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
"/billing": layout({
|
|
57
|
-
layout: () => import("./layouts/app-shell.layout"),
|
|
58
|
-
guard: requireAuth,
|
|
59
|
-
routes: billingRoutes,
|
|
60
|
-
}),
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Dev Proxy
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
export default defineConfig({
|
|
67
|
-
plugins: [mado()],
|
|
68
|
-
server: {
|
|
69
|
-
proxy: { "/api": "http://localhost:3000" },
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Rule: `shared/http` connaît HTTP, connectors connaissent un système externe,
|
|
75
|
-
resources connaissent les cache keys, pages connaissent l'UI, `*.public.ts` est
|
|
76
|
-
la surface cross-module.
|
package/docs/fr/13-deployment.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# Déploiement
|
|
2
|
-
|
|
3
|
-
Une commande, un artefact déployable :
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
mado release
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Résultat :
|
|
10
|
-
|
|
11
|
-
```txt
|
|
12
|
-
out/
|
|
13
|
-
├── index.html ← shell SPA ou HTML baked pour /
|
|
14
|
-
├── assets/ ← assets Vite hashés
|
|
15
|
-
│ ├── *.gz ← gzip précompressé
|
|
16
|
-
│ └── *.br ← brotli précompressé
|
|
17
|
-
├── <route>/index.html ← HTML baked pour les hébergeurs statiques
|
|
18
|
-
├── sitemap.xml ← sitemap à la racine du site
|
|
19
|
-
├── _redirects ← fallback SPA Cloudflare Pages / Netlify
|
|
20
|
-
└── _headers ← règles de cache
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Déploie `out/` sur nginx, Cloudflare Pages, Netlify, S3/CloudFront ou GitHub
|
|
24
|
-
Pages. Ne déploie pas `dist/` : c'est un output interne.
|
|
25
|
-
|
|
26
|
-
## Preview
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
mado release
|
|
30
|
-
mado preview
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
`mado preview` sert le `out/` final comme un hébergeur statique : fichiers réels
|
|
34
|
-
d'abord (`/<route>/index.html` si la route est baked), fallback SPA ensuite.
|
|
35
|
-
Preview vérifie exactement ce qui sera déployé.
|
|
36
|
-
|
|
37
|
-
## VPS + nginx
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
mado release
|
|
41
|
-
rsync -avz --delete out/ user@server:/var/www/myapp/
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
La recette nginx optionnelle vit dans `docs/recipes/nginx/`. Elle gère le cache
|
|
45
|
-
immutable pour `/assets/*`, no-cache pour HTML, et le fallback SPA pour les deep
|
|
46
|
-
links.
|
|
47
|
-
|
|
48
|
-
## Cloudflare / Netlify
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
mado release
|
|
52
|
-
npx wrangler pages deploy out --project-name=myapp
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
`_redirects` et `_headers` sont générés automatiquement si tu n'en fournis pas.
|
|
56
|
-
Les routes baked sont promues en vrais fichiers (`out/<route>/index.html`), donc
|
|
57
|
-
l'hébergeur statique les sert avant le fallback SPA.
|
package/docs/fr/14-testing.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Tests
|
|
2
|
-
|
|
3
|
-
Mado utilise TypeScript et les APIs du navigateur. Le dépôt du framework teste
|
|
4
|
-
avec le test runner de Node et `linkedom`.
|
|
5
|
-
|
|
6
|
-
```bash
|
|
7
|
-
npm run typecheck
|
|
8
|
-
npm run build
|
|
9
|
-
npm test
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
Un test DOM minimal :
|
|
13
|
-
|
|
14
|
-
```js
|
|
15
|
-
import test from "node:test";
|
|
16
|
-
import assert from "node:assert/strict";
|
|
17
|
-
|
|
18
|
-
const { parseHTML } = await import("linkedom");
|
|
19
|
-
const { window } = parseHTML("<!doctype html><html><body></body></html>");
|
|
20
|
-
globalThis.window = window;
|
|
21
|
-
globalThis.document = window.document;
|
|
22
|
-
globalThis.Node = window.Node;
|
|
23
|
-
globalThis.HTMLElement = window.HTMLElement;
|
|
24
|
-
|
|
25
|
-
const { html, render } = await import("../dist/src/html/template.js");
|
|
26
|
-
|
|
27
|
-
test("renders", () => {
|
|
28
|
-
const root = document.createElement("div");
|
|
29
|
-
render(html`<p>${"hello"}</p>`, root);
|
|
30
|
-
assert.equal(root.querySelector("p").textContent, "hello");
|
|
31
|
-
});
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
À couvrir :
|
|
35
|
-
|
|
36
|
-
- signals/computed/effect : scheduling et nettoyage ;
|
|
37
|
-
- bindings HTML : children, attributs, événements, directives ;
|
|
38
|
-
- routes : guards, redirects, scroll/focus, error boundaries ;
|
|
39
|
-
- formulaires : validation sync/async, races, field arrays ;
|
|
40
|
-
- resources/mutations : clés de cache, invalidation, lifecycle ;
|
|
41
|
-
- CLI : `mado release`, `mado bake`, `mado preview`.
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Gestion des erreurs
|
|
2
|
-
|
|
3
|
-
Traite les erreurs au niveau où l'utilisateur peut récupérer : routes, données,
|
|
4
|
-
actions utilisateur.
|
|
5
|
-
|
|
6
|
-
## Routes
|
|
7
|
-
|
|
8
|
-
```ts
|
|
9
|
-
export default routes(manifest, {
|
|
10
|
-
errorPage: (err) => html`
|
|
11
|
-
<main>
|
|
12
|
-
<h1>Une erreur est survenue</h1>
|
|
13
|
-
<pre>${err.message}</pre>
|
|
14
|
-
<a data-link href="/">Accueil</a>
|
|
15
|
-
</main>
|
|
16
|
-
`,
|
|
17
|
-
});
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
`page({ errorView })` a priorité sur cette boundary globale.
|
|
21
|
-
|
|
22
|
-
## Données
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
const users = resource(() => "/api/users", jsonFetcher<User[]>());
|
|
26
|
-
|
|
27
|
-
html`
|
|
28
|
-
${() => users.error()
|
|
29
|
-
? html`<p role="alert">${users.error()!.message}</p>
|
|
30
|
-
<button @click=${users.refresh}>Réessayer</button>`
|
|
31
|
-
: null}
|
|
32
|
-
`;
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Formulaires et mutations
|
|
36
|
-
|
|
37
|
-
La validation va dans `useForm()`. Les erreurs serveur d'écriture restent près
|
|
38
|
-
du bouton de soumission.
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
const form = useForm(
|
|
42
|
-
{ email: { required: true, type: "email" } },
|
|
43
|
-
{ validateAsync: (values) => api.validateUser(values) },
|
|
44
|
-
);
|
|
45
|
-
const save = mutation((values) => api.post("/users", values), {
|
|
46
|
-
invalidates: ["/api/users*"],
|
|
47
|
-
});
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Nettoie les subscriptions navigateur externes avec `ctx.onDispose()`.
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# Bake Cookbook
|
|
2
|
-
|
|
3
|
-
`mado bake` rend certaines routes en HTML statique. C'est pour le SEO et un
|
|
4
|
-
premier rendu rapide, pas pour SSR + hydration.
|
|
5
|
-
|
|
6
|
-
## Page Minimale
|
|
7
|
-
|
|
8
|
-
```ts
|
|
9
|
-
export default page({
|
|
10
|
-
head: () => ({ title: "Products", description: "Catalog" }),
|
|
11
|
-
view: ({ data }) => html`
|
|
12
|
-
<main>
|
|
13
|
-
<h1>Products</h1>
|
|
14
|
-
${data.products.map((p) => html`<article><h2>${p.name}</h2></article>`)}
|
|
15
|
-
</main>
|
|
16
|
-
`,
|
|
17
|
-
bake: {
|
|
18
|
-
paths: () => [{}],
|
|
19
|
-
data: async () => ({ products: await api.products() }),
|
|
20
|
-
revalidate: 3600,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Dans les vues baked, préfère les tableaux simples (`items.map(...)`). Les
|
|
26
|
-
directives runtime comme keyed `each()` sont pour le navigateur.
|
|
27
|
-
|
|
28
|
-
## Routes Dynamiques
|
|
29
|
-
|
|
30
|
-
```ts
|
|
31
|
-
export default page<{ slug: string }>({
|
|
32
|
-
head: ({ slug }, data) => ({ title: data.title, canonical: `/blog/${slug}` }),
|
|
33
|
-
view: ({ data }) => html`<article>${unsafeHTML(data.html)}</article>`,
|
|
34
|
-
bake: {
|
|
35
|
-
paths: async () => (await api.posts()).map((p) => ({ slug: p.slug })),
|
|
36
|
-
data: ({ slug }) => api.post(slug),
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Utilise `unsafeHTML()` seulement pour du HTML fiable ou déjà nettoyé.
|
|
42
|
-
|
|
43
|
-
## Route Manifest
|
|
44
|
-
|
|
45
|
-
`mado bake` a besoin du manifest source :
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
export const manifest = {
|
|
49
|
-
"/": () => import("./pages/home.js"),
|
|
50
|
-
"/blog/:slug": () => import("./pages/blog-post.js"),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export default routes(manifest);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Output
|
|
57
|
-
|
|
58
|
-
Standalone `mado bake` écrit les pages baked dans `out/baked/` par défaut.
|
|
59
|
-
`mado release` utilise le shell de production bundlé, garde cette copie
|
|
60
|
-
`out/baked/` pour inspection, promeut le HTML dans les vrais chemins de route
|
|
61
|
-
dans `out/`, et copie le sitemap vers `out/sitemap.xml`.
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
mado release
|
|
65
|
-
tree out
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Le dossier déployable est `out/`, pas `dist/`.
|
|
69
|
-
|
|
70
|
-
## Client Boot
|
|
71
|
-
|
|
72
|
-
Le HTML baked marque `#app` avec `data-mado-baked`. Ce n'est pas de
|
|
73
|
-
l'hydration : au démarrage, `render()` remplace le DOM baked par les bindings
|
|
74
|
-
vivants de l'application.
|
|
75
|
-
|
|
76
|
-
## Valeurs Non Supportées
|
|
77
|
-
|
|
78
|
-
Bake échoue volontairement au lieu d'écrire `[object Object]`. Si une vue baked
|
|
79
|
-
signale une directive non supportée :
|
|
80
|
-
|
|
81
|
-
- remplace `each()` par `items.map(...)` dans le markup baked ;
|
|
82
|
-
- garde les widgets interactifs dans des routes client-only ;
|
|
83
|
-
- assure-toi que chaque valeur peut être sérialisée en HTML statique.
|
|
84
|
-
|
|
85
|
-
## Canonical Links
|
|
86
|
-
|
|
87
|
-
Passe `--base-url` pour que les liens canonical et le sitemap pointent vers la
|
|
88
|
-
production.
|