@madojs/mado 0.10.1 → 0.11.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 +24 -26
- package/CHANGELOG.md +68 -0
- package/README.md +18 -45
- package/TODO.md +52 -48
- package/dist/src/component.d.ts +2 -1
- package/dist/src/component.js +5 -2
- package/dist/src/component.js.map +1 -1
- package/dist/src/each.d.ts +1 -1
- package/dist/src/each.js +1 -1
- package/dist/src/each.js.map +1 -1
- package/dist/src/index.d.ts +11 -6
- package/dist/src/index.js +5 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/lazy.d.ts +1 -1
- package/dist/src/lazy.js +1 -1
- package/dist/src/lazy.js.map +1 -1
- package/dist/src/page.d.ts +17 -21
- package/dist/src/page.js +7 -12
- package/dist/src/page.js.map +1 -1
- package/dist/src/router/manifest.d.ts +1 -1
- package/dist/src/router/manifest.js +21 -13
- package/dist/src/router/manifest.js.map +1 -1
- package/dist/src/router/match.d.ts +2 -2
- package/dist/src/router/match.js +3 -3
- package/dist/src/router/match.js.map +1 -1
- package/dist/src/router/navigation.js +1 -1
- package/dist/src/router/navigation.js.map +1 -1
- package/dist/src/vite/index.d.ts +10 -0
- package/dist/src/vite/index.js +33 -0
- package/dist/src/vite/index.js.map +1 -0
- package/docs/en/00-the-mado-way.md +25 -12
- package/docs/en/01-routing.md +90 -142
- package/docs/en/02-project-layout.md +59 -53
- package/docs/en/03-static-bake.md +5 -6
- package/docs/en/05-why-mado.md +6 -6
- package/docs/en/06-for-backenders.md +18 -22
- package/docs/en/08-llm-zero-history-test.md +9 -14
- package/docs/en/09-shadow-vs-light-dom.md +28 -36
- package/docs/en/10-app-architecture.md +158 -96
- package/docs/en/11-layouts.md +22 -24
- package/docs/en/12-auth-and-api.md +89 -182
- package/docs/en/13-deployment.md +18 -22
- package/docs/en/14-testing.md +4 -4
- package/docs/en/16-bake-cookbook.md +11 -12
- package/docs/en/18-api-freeze-map.md +6 -4
- package/docs/en/20-v1-stability.md +1 -1
- package/docs/fr/00-the-mado-way.md +55 -90
- package/docs/fr/01-routing.md +70 -152
- package/docs/fr/02-project-layout.md +61 -42
- package/docs/fr/03-static-bake.md +1 -1
- package/docs/fr/05-why-mado.md +6 -6
- package/docs/fr/06-for-backenders.md +7 -7
- package/docs/fr/08-llm-zero-history-test.md +21 -48
- package/docs/fr/09-shadow-vs-light-dom.md +43 -162
- package/docs/fr/10-app-architecture.md +110 -33
- package/docs/fr/11-layouts.md +24 -12
- package/docs/fr/12-auth-and-api.md +63 -22
- package/docs/fr/13-deployment.md +7 -10
- package/docs/fr/14-testing.md +1 -1
- package/docs/fr/16-bake-cookbook.md +2 -2
- package/docs/fr/18-api-freeze-map.md +1 -1
- package/docs/fr/20-v1-stability.md +1 -1
- package/docs/recipes/nginx/README.md +13 -0
- package/docs/ru/00-the-mado-way.md +53 -75
- package/docs/ru/01-routing.md +68 -143
- package/docs/ru/02-project-layout.md +61 -41
- package/docs/ru/03-static-bake.md +2 -2
- package/docs/ru/05-why-mado.md +6 -6
- package/docs/ru/06-for-backenders.md +7 -7
- package/docs/ru/08-llm-zero-history-test.md +9 -14
- package/docs/ru/09-shadow-vs-light-dom.md +43 -178
- package/docs/ru/10-app-architecture.md +115 -63
- package/docs/ru/11-layouts.md +24 -24
- package/docs/ru/12-auth-and-api.md +57 -35
- package/docs/ru/13-deployment.md +7 -11
- package/docs/ru/14-testing.md +1 -1
- package/docs/ru/16-bake-cookbook.md +12 -6
- package/docs/ru/18-api-freeze-map.md +5 -3
- package/docs/ru/20-v1-stability.md +1 -1
- package/docs/uk/00-the-mado-way.md +70 -44
- package/docs/uk/01-routing.md +41 -47
- package/docs/uk/02-project-layout.md +68 -41
- package/docs/uk/03-static-bake.md +1 -2
- package/docs/uk/06-for-backenders.md +3 -3
- package/docs/uk/08-llm-zero-history-test.md +22 -24
- package/docs/uk/09-shadow-vs-light-dom.md +37 -86
- package/docs/uk/10-app-architecture.md +72 -31
- package/docs/uk/11-layouts.md +25 -12
- package/docs/uk/12-auth-and-api.md +58 -22
- package/docs/uk/13-deployment.md +4 -3
- package/docs/uk/14-testing.md +1 -1
- package/docs/uk/18-api-freeze-map.md +1 -1
- package/docs/uk/20-v1-stability.md +1 -1
- package/llms.txt +14 -15
- package/package.json +18 -11
- package/scripts/_config.mjs +15 -161
- package/scripts/bake.mjs +67 -57
- package/scripts/cli/generate.mjs +348 -0
- package/scripts/cli/help.mjs +27 -0
- package/scripts/cli/index.mjs +79 -0
- package/scripts/cli/init.mjs +153 -0
- package/scripts/cli/release.mjs +152 -0
- package/scripts/cli/run.mjs +96 -0
- package/scripts/cli.mjs +2 -621
- package/scripts/package-smoke.mjs +4 -1
- package/scripts/preview.mjs +13 -37
- package/scripts/size-budget.mjs +5 -2
- package/scripts/vite.default.mjs +11 -0
- package/starters/default/.editorconfig +12 -0
- package/starters/default/README.md +74 -0
- package/starters/default/eslint.config.mjs +256 -0
- package/starters/default/index.html +13 -0
- package/starters/default/package.json +30 -0
- package/starters/default/public/favicon.svg +4 -0
- package/starters/default/src/app.routes.ts +39 -0
- package/starters/default/src/layouts/app-shell.layout.ts +35 -0
- package/starters/default/src/layouts/auth-shell.layout.ts +17 -0
- package/starters/default/src/main.ts +16 -0
- package/starters/default/src/modules/auth/_contracts/auth-api.types.ts +17 -0
- package/starters/default/src/modules/auth/auth.connector.ts +45 -0
- package/starters/default/src/modules/auth/auth.guard.ts +22 -0
- package/starters/default/src/modules/auth/auth.public.ts +9 -0
- package/starters/default/src/modules/auth/auth.routes.ts +8 -0
- package/starters/default/src/modules/auth/auth.service.ts +71 -0
- package/starters/default/src/modules/auth/auth.types.ts +15 -0
- package/starters/default/src/modules/auth/login.page.ts +62 -0
- package/starters/default/src/modules/billing/_contracts/stripe.types.ts +17 -0
- package/starters/default/src/modules/billing/api/stripe.connector.ts +71 -0
- package/starters/default/src/modules/billing/billing.public.ts +5 -0
- package/starters/default/src/modules/billing/billing.routes.ts +9 -0
- package/starters/default/src/modules/billing/billing.types.ts +15 -0
- package/starters/default/src/modules/billing/components/invoice-status-badge.component.ts +43 -0
- package/starters/default/src/modules/billing/data/invoices.resource.ts +35 -0
- package/starters/default/src/modules/billing/pages/invoice-detail.page.ts +70 -0
- package/starters/default/src/modules/billing/pages/invoices-list.page.ts +73 -0
- package/starters/default/src/modules/home/home.page.ts +34 -0
- package/starters/default/src/modules/home/not-found.page.ts +11 -0
- package/starters/default/src/shared/http/http-client.ts +86 -0
- package/starters/default/src/shared/http/http-error.ts +37 -0
- package/starters/default/src/shared/http/interceptors.ts +59 -0
- package/starters/default/src/shared/lib/format-date.ts +19 -0
- package/starters/default/src/shared/styles/content.css +70 -0
- package/starters/default/src/shared/styles/reset.css +32 -0
- package/starters/default/src/shared/styles/shell.css +57 -0
- package/starters/default/src/shared/styles/tokens.css +44 -0
- package/starters/default/src/shared/ui/x-button.component.ts +49 -0
- package/starters/default/src/shared/ui/x-spinner.component.ts +22 -0
- package/starters/default/src/styles.d.ts +1 -0
- package/starters/default/src/vite-env.d.ts +1 -0
- package/starters/default/tsconfig.json +24 -0
- package/starters/default/vite.config.ts +9 -0
- package/MADO_V1_PLAN.md +0 -179
- package/ROADMAP.md +0 -178
- package/dist/src/html.d.ts +0 -18
- package/dist/src/html.js +0 -17
- package/dist/src/html.js.map +0 -1
- package/dist/src/router.d.ts +0 -13
- package/dist/src/router.js +0 -13
- package/dist/src/router.js.map +0 -1
- package/scripts/bundle.mjs +0 -212
- package/scripts/llm-zero-history-smoke.mjs +0 -93
- package/scripts/new.mjs +0 -80
- package/scripts/showcase-regression.mjs +0 -392
- package/server/serve.mjs +0 -455
- package/starters/admin/README.md +0 -63
- package/starters/admin/index.html +0 -28
- package/starters/admin/mado.config.json +0 -22
- package/starters/admin/package.json +0 -24
- package/starters/admin/public/favicon.svg +0 -4
- package/starters/admin/src/components/x-button.ts +0 -82
- package/starters/admin/src/components/x-input.ts +0 -105
- package/starters/admin/src/layouts/app.ts +0 -101
- package/starters/admin/src/layouts/auth.ts +0 -41
- package/starters/admin/src/lib/api.ts +0 -184
- package/starters/admin/src/lib/auth.ts +0 -83
- package/starters/admin/src/main.ts +0 -15
- package/starters/admin/src/pages/admin/dashboard.ts +0 -48
- package/starters/admin/src/pages/admin/order-detail.ts +0 -80
- package/starters/admin/src/pages/admin/orders.ts +0 -117
- package/starters/admin/src/pages/home.ts +0 -34
- package/starters/admin/src/pages/login.ts +0 -70
- package/starters/admin/src/pages/not-found.ts +0 -12
- package/starters/admin/src/routes.ts +0 -40
- package/starters/admin/src/styles/global.ts +0 -86
- package/starters/admin/tsconfig.json +0 -15
- package/starters/crud/README.md +0 -33
- package/starters/crud/index.html +0 -28
- package/starters/crud/mado.config.json +0 -20
- package/starters/crud/package.json +0 -24
- package/starters/crud/src/components/app-shell.ts +0 -56
- package/starters/crud/src/components/ticket-detail.ts +0 -33
- package/starters/crud/src/components/ticket-form.ts +0 -69
- package/starters/crud/src/components/ticket-list.ts +0 -66
- package/starters/crud/src/lib/api.ts +0 -76
- package/starters/crud/src/main.ts +0 -9
- package/starters/crud/src/pages/home.ts +0 -34
- package/starters/crud/src/pages/not-found.ts +0 -12
- package/starters/crud/src/pages/ticket-detail.ts +0 -7
- package/starters/crud/src/pages/ticket-new.ts +0 -7
- package/starters/crud/src/pages/tickets.ts +0 -7
- package/starters/crud/src/routes.ts +0 -11
- package/starters/crud/src/styles/global.ts +0 -155
- package/starters/crud/tsconfig.json +0 -15
- package/starters/minimal/README.md +0 -21
- package/starters/minimal/index.html +0 -28
- package/starters/minimal/mado.config.json +0 -20
- package/starters/minimal/package.json +0 -24
- package/starters/minimal/src/components/app-counter.ts +0 -31
- package/starters/minimal/src/main.ts +0 -9
- package/starters/minimal/src/pages/home.ts +0 -35
- package/starters/minimal/src/pages/not-found.ts +0 -14
- package/starters/minimal/src/routes.ts +0 -8
- package/starters/minimal/src/styles/global.ts +0 -60
- package/starters/minimal/tsconfig.json +0 -15
- package/templates/page-detail.ts +0 -63
- package/templates/page-form.ts +0 -94
- package/templates/page-list.ts +0 -79
|
@@ -1,35 +1,76 @@
|
|
|
1
1
|
# Auth et API
|
|
2
2
|
|
|
3
|
-
Le starter
|
|
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/`.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
```txt
|
|
7
|
+
src/shared/http/
|
|
8
|
+
http-client.ts
|
|
9
|
+
http-error.ts
|
|
10
|
+
interceptors.ts
|
|
8
11
|
|
|
9
|
-
|
|
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.
|
|
10
29
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- les routes protégées utilisent un group guard.
|
|
30
|
+
## Auth Service
|
|
31
|
+
|
|
32
|
+
Auth state est un ES module singleton :
|
|
15
33
|
|
|
16
34
|
```ts
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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);
|
|
22
40
|
```
|
|
23
41
|
|
|
24
|
-
|
|
42
|
+
Exposez seulement la surface nécessaire via `auth.public.ts`.
|
|
25
43
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
44
|
+
## Guards
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export function requireAuth(): boolean | string {
|
|
48
|
+
if (isAuthed()) return true;
|
|
49
|
+
return "/login";
|
|
31
50
|
}
|
|
32
51
|
```
|
|
33
52
|
|
|
34
|
-
|
|
35
|
-
|
|
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
CHANGED
|
@@ -10,14 +10,11 @@ Résultat :
|
|
|
10
10
|
|
|
11
11
|
```txt
|
|
12
12
|
out/
|
|
13
|
-
├── index.html ← shell SPA ou HTML baked
|
|
14
|
-
├── assets/ ←
|
|
13
|
+
├── index.html ← shell SPA ou HTML baked pour /
|
|
14
|
+
├── assets/ ← assets Vite hashés
|
|
15
15
|
│ ├── *.gz ← gzip précompressé
|
|
16
16
|
│ └── *.br ← brotli précompressé
|
|
17
|
-
├──
|
|
18
|
-
│ ├── <route>/index.html
|
|
19
|
-
│ └── sitemap.xml
|
|
20
|
-
├── <route>/index.html ← HTML baked promu pour les hébergeurs statiques
|
|
17
|
+
├── <route>/index.html ← HTML baked pour les hébergeurs statiques
|
|
21
18
|
├── sitemap.xml ← sitemap à la racine du site
|
|
22
19
|
├── _redirects ← fallback SPA Cloudflare Pages / Netlify
|
|
23
20
|
└── _headers ← règles de cache
|
|
@@ -35,8 +32,7 @@ mado preview
|
|
|
35
32
|
|
|
36
33
|
`mado preview` sert le `out/` final comme un hébergeur statique : fichiers réels
|
|
37
34
|
d'abord (`/<route>/index.html` si la route est baked), fallback SPA ensuite.
|
|
38
|
-
Preview
|
|
39
|
-
exactement ce qui sera déployé.
|
|
35
|
+
Preview vérifie exactement ce qui sera déployé.
|
|
40
36
|
|
|
41
37
|
## VPS + nginx
|
|
42
38
|
|
|
@@ -45,8 +41,9 @@ mado release
|
|
|
45
41
|
rsync -avz --delete out/ user@server:/var/www/myapp/
|
|
46
42
|
```
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
pour HTML, et le fallback SPA pour les deep
|
|
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.
|
|
50
47
|
|
|
51
48
|
## Cloudflare / Netlify
|
|
52
49
|
|
package/docs/fr/14-testing.md
CHANGED
|
@@ -22,7 +22,7 @@ globalThis.document = window.document;
|
|
|
22
22
|
globalThis.Node = window.Node;
|
|
23
23
|
globalThis.HTMLElement = window.HTMLElement;
|
|
24
24
|
|
|
25
|
-
const { html, render } = await import("../dist/src/html.js");
|
|
25
|
+
const { html, render } = await import("../dist/src/html/template.js");
|
|
26
26
|
|
|
27
27
|
test("renders", () => {
|
|
28
28
|
const root = document.createElement("div");
|
|
@@ -84,5 +84,5 @@ signale une directive non supportée :
|
|
|
84
84
|
|
|
85
85
|
## Canonical Links
|
|
86
86
|
|
|
87
|
-
Passe `--base-url`
|
|
88
|
-
|
|
87
|
+
Passe `--base-url` pour que les liens canonical et le sitemap pointent vers la
|
|
88
|
+
production.
|
|
@@ -27,7 +27,7 @@ Ces noms sont publics et protégés par SemVer une fois v1 publiée :
|
|
|
27
27
|
- Templates et directives : `html`, `render`, `each`, `list`, `unsafeHTML`,
|
|
28
28
|
`ref`, `classMap`, `styleMap`.
|
|
29
29
|
- Composants et CSS : `component`, `css`, `cssVars`.
|
|
30
|
-
- Routage et pages : `routes`, `router`, `page`, `layout`,
|
|
30
|
+
- Routage et pages : `routes`, `router`, `page`, `layout`,
|
|
31
31
|
`navigate`, `queryParam`, `prefetchPath`.
|
|
32
32
|
- Data : `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
|
|
33
33
|
- Formulaires : `useForm`.
|
|
@@ -26,7 +26,7 @@ Après v1, Mado considère comme protégés par SemVer :
|
|
|
26
26
|
`ctx.onDispose`.
|
|
27
27
|
- Les contrats router/page/resource/form documentés dans les docs anglaises.
|
|
28
28
|
- Les noms de commandes CLI et leur intention générale (`build`, `dev`,
|
|
29
|
-
`release`, `bake`, `
|
|
29
|
+
`release`, `bake`, `preview`, `init`, `new`).
|
|
30
30
|
|
|
31
31
|
Casser cela nécessite une version majeure.
|
|
32
32
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Nginx Container Recipe
|
|
2
|
+
|
|
3
|
+
Optional static deployment recipe for a generated Mado app.
|
|
4
|
+
|
|
5
|
+
Copy this directory into your app as `docker/`, then build from the app root:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
docker build -f docker/Containerfile -t myapp .
|
|
9
|
+
docker run --rm -p 8080:80 myapp
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The container runs `npm run release` and serves the resulting `out/` directory
|
|
13
|
+
with nginx. This is a recipe, not a framework runtime requirement.
|
|
@@ -2,105 +2,83 @@
|
|
|
2
2
|
|
|
3
3
|
> Один правильный путь. Жёсткие контракты. Никакой магии.
|
|
4
4
|
|
|
5
|
-
Mado — фреймворк для команд, которые строят админки, внутренние инструменты
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
нарушаешь — типы и линтер скажут об этом сразу.
|
|
5
|
+
Mado — фреймворк для команд, которые строят админки, внутренние инструменты и
|
|
6
|
+
business SPA. Такие приложения должны быть простыми в разработке и скучными в
|
|
7
|
+
поддержке. Поэтому Mado задает соглашения, а не предлагает пять равноценных
|
|
8
|
+
стилей.
|
|
10
9
|
|
|
11
10
|
## Принципы
|
|
12
11
|
|
|
13
|
-
1. **Один способ.**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
1. **Один способ.** Если пишешь что-то необычное, сначала проверь, нет ли уже
|
|
13
|
+
каноничного helper/API.
|
|
14
|
+
2. **Явность над магией.** Никаких file-system scanners, implicit globals и
|
|
15
|
+
скрытых side effects.
|
|
16
|
+
3. **Платформа сначала.** Web Components, History API, `<form>`, `fetch` и
|
|
17
|
+
Shadow DOM остаются платформой, а не прячутся под тяжелыми абстракциями.
|
|
18
|
+
4. **Strict types.** `tsc --strict --noUncheckedIndexedAccess` всегда.
|
|
19
|
+
5. **No runtime dependencies.** Dev/build tooling допустим, runtime Mado
|
|
20
|
+
остается нативным.
|
|
18
21
|
|
|
19
|
-
##
|
|
22
|
+
## Структура проекта
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
+
```txt
|
|
24
25
|
src/
|
|
25
|
-
├──
|
|
26
|
-
├──
|
|
27
|
-
├──
|
|
28
|
-
├──
|
|
29
|
-
|
|
30
|
-
└──
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// src/components/user-card.ts
|
|
39
|
-
import { component, html, css } from "@madojs/mado";
|
|
40
|
-
|
|
41
|
-
component(
|
|
42
|
-
"x-user-card",
|
|
43
|
-
() => {
|
|
44
|
-
return () => html`<div class="card"><slot /></div>`;
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
styles: css`
|
|
48
|
-
.card {
|
|
49
|
-
padding: 1rem;
|
|
50
|
-
}
|
|
51
|
-
`,
|
|
52
|
-
},
|
|
53
|
-
);
|
|
26
|
+
├── main.ts ← boot: global CSS/providers + render router
|
|
27
|
+
├── app.routes.ts ← readable app map, exports `manifest` + default routes()
|
|
28
|
+
├── layouts/ ← app-zone wrappers (`page({ view: ({ child }) => ... })`)
|
|
29
|
+
├── shared/ ← UI bricks, http client, pure lib, global CSS
|
|
30
|
+
└── modules/ ← bounded contexts
|
|
31
|
+
└── billing/
|
|
32
|
+
├── billing.routes.ts
|
|
33
|
+
├── billing.public.ts
|
|
34
|
+
├── billing.types.ts
|
|
35
|
+
├── pages/
|
|
36
|
+
├── data/
|
|
37
|
+
├── api/
|
|
38
|
+
└── _contracts/
|
|
54
39
|
```
|
|
55
40
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
### Один способ загрузки данных
|
|
41
|
+
Default starter — каноничная версия этой формы. Если docs и старые примеры
|
|
42
|
+
расходятся, starter и `docs/10-app-architecture.md` главнее.
|
|
59
43
|
|
|
60
|
-
|
|
44
|
+
## Один компонент = один файл
|
|
61
45
|
|
|
62
46
|
```ts
|
|
63
|
-
|
|
64
|
-
const user = resource(() => `/api/users/${id()}`, jsonFetcher());
|
|
47
|
+
import { component, css, html } from "@madojs/mado";
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
|
|
49
|
+
component("x-user-card", () => () => html`<div class="card"><slot></slot></div>`, {
|
|
50
|
+
styles: css`
|
|
51
|
+
.card { padding: 1rem; }
|
|
52
|
+
`,
|
|
53
|
+
});
|
|
68
54
|
```
|
|
69
55
|
|
|
70
|
-
|
|
56
|
+
Import component file registers the element. Import it where the tag is used.
|
|
71
57
|
|
|
72
|
-
|
|
58
|
+
## Один способ описать страницу
|
|
73
59
|
|
|
74
60
|
```ts
|
|
75
|
-
|
|
76
|
-
import { page, html, resource, jsonFetcher } from "@madojs/mado";
|
|
61
|
+
import { html, page, resource, jsonFetcher } from "@madojs/mado";
|
|
77
62
|
|
|
78
63
|
export default page({
|
|
79
64
|
title: ({ id }) => `User #${id}`,
|
|
80
|
-
view: ({ params }) =>
|
|
65
|
+
view: ({ params }) => {
|
|
66
|
+
const user = resource(() => `/api/users/${params.id}`, jsonFetcher());
|
|
67
|
+
return html`...`;
|
|
68
|
+
},
|
|
81
69
|
});
|
|
82
70
|
```
|
|
83
71
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
### Один способ объявить роуты
|
|
87
|
-
|
|
88
|
-
См. [`01-routing.md`](./01-routing.md).
|
|
72
|
+
Page-local signals, resources and forms live inside `view()`. Module-wide state
|
|
73
|
+
belongs in `*.service.ts`.
|
|
89
74
|
|
|
90
75
|
## Чего НЕ делаем
|
|
91
76
|
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
- ❌ Не подключаем pkg без обсуждения. Каждая зависимость — обязательство.
|
|
98
|
-
|
|
99
|
-
## Когда сомневаешься
|
|
100
|
-
|
|
101
|
-
Если ты задаёшься вопросом "а как тут лучше?" — это сигнал, что:
|
|
102
|
-
|
|
103
|
-
1. Либо есть встроенный хелпер, который ты не знаешь (загляни в `docs/`).
|
|
104
|
-
2. Либо это новая ситуация — её надо обсудить и **зафиксировать** в этом документе как ещё одно соглашение.
|
|
77
|
+
- Не используем JSX/Vue/Svelte syntax.
|
|
78
|
+
- Не пишем custom elements без дефиса.
|
|
79
|
+
- Не читаем signals через `.value`; signal читается как function.
|
|
80
|
+
- Не используем `innerHTML` напрямую.
|
|
81
|
+
- Не добавляем runtime packages без обсуждения.
|
|
105
82
|
|
|
106
|
-
|
|
83
|
+
Когда сомневаешься, лучше записать один честный рецепт в docs, чем добавить
|
|
84
|
+
новый primitive в core.
|
package/docs/ru/01-routing.md
CHANGED
|
@@ -1,194 +1,119 @@
|
|
|
1
1
|
# Routing
|
|
2
2
|
|
|
3
|
-
> Один
|
|
3
|
+
> Один app map. Никаких folder scanners. Никаких специальных path symbols.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Mado не выводит routes из файлов. Composition должна читаться в одном месте.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## App Manifest
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- Спецсимволы в путях: `[id]`, `(group)`, `_layout`, `+page.svelte`, `...slug`.
|
|
11
|
-
- Server-route vs client-route путаются.
|
|
12
|
-
- Тестировать роутинг — мука: нужен эмулятор сборщика.
|
|
13
|
-
|
|
14
|
-
Mado считает это **слишком магией**. Мы делаем иначе.
|
|
15
|
-
|
|
16
|
-
## Манифест
|
|
17
|
-
|
|
18
|
-
Один файл — `src/routes.ts`. В нём один объект. Читается сверху вниз.
|
|
9
|
+
Используйте `src/app.routes.ts` как карту приложения:
|
|
19
10
|
|
|
20
11
|
```ts
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
12
|
+
import { layout, routes } from "@madojs/mado";
|
|
13
|
+
import { requireAuth } from "./modules/auth/auth.public";
|
|
14
|
+
import { authRoutes } from "./modules/auth/auth.routes";
|
|
15
|
+
import { billingRoutes } from "./modules/billing/billing.routes";
|
|
16
|
+
|
|
17
|
+
export const manifest = {
|
|
18
|
+
"/": () => import("./modules/home/home.page.js"),
|
|
19
|
+
"/login": layout({
|
|
20
|
+
layout: () => import("./layouts/auth-shell.layout.js"),
|
|
21
|
+
routes: authRoutes,
|
|
22
|
+
}),
|
|
23
|
+
"/billing": layout({
|
|
24
|
+
layout: () => import("./layouts/app-shell.layout.js"),
|
|
25
|
+
guard: requireAuth,
|
|
26
|
+
routes: billingRoutes,
|
|
27
|
+
}),
|
|
28
|
+
"*": () => import("./modules/home/not-found.page.js"),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default routes(manifest);
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
Открываешь `app.routes.ts` и видишь все зоны приложения: public pages, auth,
|
|
35
|
+
protected app zones, guards и shells.
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
`manifest` экспортируется отдельно, чтобы `mado bake` мог его прочитать.
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
## Module Routes
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
Modules экспортируют plain route maps. Они не вызывают `layout()` и не решают,
|
|
42
|
+
какой shell их оборачивает.
|
|
40
43
|
|
|
41
44
|
```ts
|
|
42
|
-
|
|
45
|
+
export const billingRoutes = {
|
|
46
|
+
"/invoices": () => import("./pages/invoices-list.page.js"),
|
|
47
|
+
"/invoices/:id": () => import("./pages/invoice-detail.page.js"),
|
|
48
|
+
};
|
|
43
49
|
```
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Между навигациями результат кэшируется.
|
|
51
|
+
Prefix применяет `src/app.routes.ts`, когда module монтируется под
|
|
52
|
+
`"/billing"`.
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
## Layout Group
|
|
50
55
|
|
|
51
56
|
```ts
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
"/admin": layout({
|
|
58
|
+
layout: () => import("./layouts/app-shell.layout.js"),
|
|
59
|
+
guard: requireAuth,
|
|
60
|
+
routes: adminRoutes,
|
|
61
|
+
}),
|
|
55
62
|
```
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### 3. Nested с layout
|
|
64
|
+
Layout — обычный `page({...})` file:
|
|
60
65
|
|
|
61
66
|
```ts
|
|
62
|
-
import {
|
|
63
|
-
|
|
64
|
-
export default routes({
|
|
65
|
-
'/': () => import('./pages/home.js'),
|
|
66
|
-
|
|
67
|
-
'/admin/*': nested({
|
|
68
|
-
layout: () => import('./layouts/admin.js'),
|
|
69
|
-
routes: {
|
|
70
|
-
'': () => import('./pages/admin/dashboard.js'),
|
|
71
|
-
'users': () => import('./pages/admin/users.js'),
|
|
72
|
-
'logs': () => import('./pages/admin/logs.js'),
|
|
73
|
-
},
|
|
74
|
-
}),
|
|
75
|
-
});
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Layout — это **обычный** `page({...})`, который рендерит `ctx.child` куда хочет:
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
// src/layouts/admin.ts
|
|
82
|
-
import { page, html, css, component } from '@madojs/mado';
|
|
67
|
+
import { html, page } from "@madojs/mado";
|
|
83
68
|
|
|
84
69
|
export default page({
|
|
85
70
|
view: ({ child }) => html`
|
|
86
|
-
<div class="
|
|
87
|
-
<
|
|
88
|
-
<main>${child}</main>
|
|
71
|
+
<div class="layout layout--app">
|
|
72
|
+
<main class="app-main">${child}</main>
|
|
89
73
|
</div>
|
|
90
74
|
`,
|
|
91
75
|
});
|
|
92
76
|
```
|
|
93
77
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
```ts
|
|
97
|
-
import { page, html, resource, jsonFetcher } from '@madojs/mado';
|
|
98
|
-
|
|
99
|
-
export default page({
|
|
100
|
-
title: ({ id }) => `User #${id}`, // string | (params) => string
|
|
101
|
-
load: ({ id }) => resource(...), // опц., возвращает Resource или данные
|
|
102
|
-
view: ({ params, data, path, child }) => html`...`, // ОБЯЗАТЕЛЬНО
|
|
103
|
-
});
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Три слота, всё. Если ты экспортируешь не `page({...})`, а просто функцию — `routes()` кинет понятную ошибку:
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
[Mado] Lazy-роут не вернул page({...}) как default-экспорт.
|
|
110
|
-
```
|
|
78
|
+
Layout view держим stateless. Page-specific signals, resources и forms живут в
|
|
79
|
+
pages/components/resources, не в layout locals.
|
|
111
80
|
|
|
112
|
-
##
|
|
81
|
+
## Page Contract
|
|
113
82
|
|
|
114
83
|
```ts
|
|
115
|
-
|
|
116
|
-
```
|
|
84
|
+
import { html, page } from "@madojs/mado";
|
|
117
85
|
|
|
118
|
-
```ts
|
|
119
86
|
export default page<{ id: string }>({
|
|
120
87
|
title: ({ id }) => `User ${id}`,
|
|
121
|
-
view:
|
|
88
|
+
view: ({ params }) => html`<h1>${params.id}</h1>`,
|
|
122
89
|
});
|
|
123
90
|
```
|
|
124
91
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
## Глобальные опции
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
export default routes(
|
|
131
|
-
{ '/': home, '/about': about, '*': nf },
|
|
132
|
-
{
|
|
133
|
-
titleSuffix: ' · MyApp', // → "Главная · MyApp"
|
|
134
|
-
loading: () => html`<x-spinner/>`, // пока модуль грузится
|
|
135
|
-
error: (err) => html`<x-fatal-error .err=${err}/>`,
|
|
136
|
-
},
|
|
137
|
-
);
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## Программная навигация
|
|
92
|
+
## Navigation
|
|
141
93
|
|
|
142
94
|
```ts
|
|
143
|
-
import
|
|
95
|
+
import appRoutes from "./app.routes.js";
|
|
144
96
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
97
|
+
appRoutes.navigate("/billing/invoices");
|
|
98
|
+
appRoutes.navigate("/billing/invoices?page=2");
|
|
99
|
+
appRoutes.navigate("/login", { replace: true });
|
|
148
100
|
```
|
|
149
101
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
## Query-параметры
|
|
102
|
+
## Query Parameters
|
|
153
103
|
|
|
154
104
|
```ts
|
|
155
|
-
import { queryParam } from
|
|
156
|
-
|
|
157
|
-
const page = queryParam('page', '1');
|
|
158
|
-
page(); // '1'
|
|
159
|
-
page.set('2'); // history.replaceState + перерисовка
|
|
160
|
-
page.set(null); // удалить параметр
|
|
161
|
-
page.set('3', { push: true }); // history.pushState
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
`queryParam` — обычный сигнал. Использовать можно где угодно: в страницах, компонентах, computed.
|
|
165
|
-
|
|
166
|
-
## Что осознанно отсутствует
|
|
105
|
+
import { queryParam } from "@madojs/mado";
|
|
167
106
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
## FAQ
|
|
174
|
-
|
|
175
|
-
**А если у меня 100 роутов? Не разрастётся ли файл?**
|
|
176
|
-
Разрастётся до ~150 строк. Это всё ещё **один источник правды** против сотни файлов в `pages/` с магическими именами. На практике даже у больших проектов (1000+ страниц) можно бить на feature-манифесты:
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
import { routes } from '@madojs/mado';
|
|
180
|
-
import adminRoutes from './features/admin/routes.js';
|
|
181
|
-
import billingRoutes from './features/billing/routes.js';
|
|
182
|
-
|
|
183
|
-
export default routes({
|
|
184
|
-
...adminRoutes,
|
|
185
|
-
...billingRoutes,
|
|
186
|
-
'*': () => import('./pages/not-found.js'),
|
|
187
|
-
});
|
|
107
|
+
const page = queryParam("page", "1");
|
|
108
|
+
page();
|
|
109
|
+
page.set("2");
|
|
110
|
+
page.set(null);
|
|
111
|
+
page.set("3", { push: true });
|
|
188
112
|
```
|
|
189
113
|
|
|
190
|
-
|
|
191
|
-
Импортируешь `routes.ts` — это просто объект. Подставляешь свой mock-router. Никакой эмуляции сборщика не нужно.
|
|
114
|
+
## Чего нет намеренно
|
|
192
115
|
|
|
193
|
-
|
|
194
|
-
|
|
116
|
+
- Auto-scan of page folders.
|
|
117
|
+
- Filesystem syntax вроде `[id]`, `(group)`, `_layout`.
|
|
118
|
+
- Server routes в client manifest.
|
|
119
|
+
- Hidden layout discovery.
|