@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
package/dist/src/vite/index.js
CHANGED
|
@@ -1,32 +1,63 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
1
|
/**
|
|
3
2
|
* Vite integration for Mado apps.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Intentionally minimal: Vite owns dev serving, HTML processing, assets
|
|
5
|
+
* and bundling. This plugin is the bridge that hands the snapshot CLI the
|
|
6
|
+
* three pieces of resolved Vite config it needs and asks Vite for a
|
|
7
|
+
* Mado-flavoured full reload on TypeScript/JavaScript changes.
|
|
8
|
+
*
|
|
9
|
+
* What it owns:
|
|
10
|
+
* 1. a small `build.target` default (matches what the runtime relies on);
|
|
11
|
+
* 2. forcing a full page reload when a `.ts` / `.js` module updates,
|
|
12
|
+
* so signals / components do not have to track HMR state;
|
|
13
|
+
* 3. emitting `_mado/build.json` into the output so
|
|
14
|
+
* `scripts/static.mjs` can read the resolved Vite `base`, `assetsDir`
|
|
15
|
+
* and the user-declared `site` without parsing `vite.config.ts`.
|
|
16
|
+
*
|
|
17
|
+
* What it does NOT own:
|
|
18
|
+
* - HTML ownership (Vite keeps that),
|
|
19
|
+
* - publicDir / outDir / assetsDir defaults (Vite already supplies them),
|
|
20
|
+
* - snapshot orchestration (CLI keeps that),
|
|
21
|
+
* - SSR or hydration.
|
|
7
22
|
*/
|
|
8
|
-
export function mado(
|
|
9
|
-
let
|
|
23
|
+
export function mado(options = {}) {
|
|
24
|
+
let resolved = null;
|
|
10
25
|
return {
|
|
11
26
|
name: "mado",
|
|
12
|
-
config(
|
|
13
|
-
root = resolve(process.cwd(), userConfig.root ?? ".");
|
|
27
|
+
config() {
|
|
14
28
|
return {
|
|
15
|
-
|
|
16
|
-
publicDir: "public",
|
|
17
|
-
build: {
|
|
18
|
-
outDir: "out",
|
|
19
|
-
assetsDir: "assets",
|
|
20
|
-
target: "es2022",
|
|
21
|
-
},
|
|
29
|
+
build: { target: "es2022" },
|
|
22
30
|
};
|
|
23
31
|
},
|
|
32
|
+
configResolved(config) {
|
|
33
|
+
resolved = config;
|
|
34
|
+
},
|
|
24
35
|
handleHotUpdate(ctx) {
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
if (!/\.[cm]?[jt]s$/.test(ctx.file))
|
|
37
|
+
return;
|
|
38
|
+
// Invalidate the module graph first; otherwise the reload would
|
|
39
|
+
// serve cached modules and miss the change. Mirrors the canonical
|
|
40
|
+
// Vite "force full reload" recipe.
|
|
41
|
+
const invalidated = new Set();
|
|
42
|
+
for (const mod of ctx.modules) {
|
|
43
|
+
ctx.server.moduleGraph.invalidateModule(mod, invalidated, ctx.timestamp, true);
|
|
28
44
|
}
|
|
29
|
-
|
|
45
|
+
ctx.server.ws.send({ type: "full-reload" });
|
|
46
|
+
return [];
|
|
47
|
+
},
|
|
48
|
+
generateBundle() {
|
|
49
|
+
if (!resolved)
|
|
50
|
+
return;
|
|
51
|
+
this.emitFile({
|
|
52
|
+
type: "asset",
|
|
53
|
+
fileName: "_mado/build.json",
|
|
54
|
+
source: JSON.stringify({
|
|
55
|
+
site: options.site ?? null,
|
|
56
|
+
base: resolved.base,
|
|
57
|
+
assetsDir: resolved.build.assetsDir,
|
|
58
|
+
outDir: resolved.build.outDir,
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
30
61
|
},
|
|
31
62
|
};
|
|
32
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/vite/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/vite/index.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,IAAI,CAAC,UAAiC,EAAE;IACtD,IAAI,QAAQ,GAA0B,IAAI,CAAC;IAE3C,OAAO;QACL,IAAI,EAAE,MAAM;QAEZ,MAAM;YACJ,OAAO;gBACL,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;aAC5B,CAAC;QACJ,CAAC;QAED,cAAc,CAAC,MAAM;YACnB,QAAQ,GAAG,MAAM,CAAC;QACpB,CAAC;QAED,eAAe,CAAC,GAAG;YACjB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO;YAC5C,gEAAgE;YAChE,kEAAkE;YAClE,mCAAmC;YACnC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAW,CAAC;YACvC,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAC9B,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,gBAAgB,CACrC,GAAG,EACH,WAAyB,EACzB,GAAG,CAAC,SAAS,EACb,IAAI,CACL,CAAC;YACJ,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;YAC5C,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,cAAc;YACZ,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtB,IAAI,CAAC,QAAQ,CAAC;gBACZ,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,kBAAkB;gBAC5B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;oBACrB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;oBAC1B,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,SAAS;oBACnC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM;iBAC9B,CAAC;aACH,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/docs/README.md
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
# Mado docs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Canonical project documentation is maintained in English only.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|---|---|
|
|
7
|
-
| [Français](./fr/README.md) | translated |
|
|
8
|
-
| [English](./en/README.md) | translated |
|
|
9
|
-
| [Ukrainian](./uk/README.md) | translated |
|
|
10
|
-
| [Russian](./ru/README.md) | translated |
|
|
5
|
+
- [English documentation](./en/README.md)
|
|
11
6
|
|
|
12
|
-
|
|
7
|
+
Older translations (`fr/`, `uk/`, `ru/`) were removed at v0.12. They
|
|
8
|
+
remain available in git history and the `v0.11.1` tag for any
|
|
9
|
+
external links that still need them.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# ADR 0001 — Browser-rendered static snapshots
|
|
2
|
+
|
|
3
|
+
**Status:** Accepted (0.12.0)
|
|
4
|
+
**Date:** 2026-06-22
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Mado started as a calm browser-native SPA framework for internal tools
|
|
9
|
+
and admin panels. Two new product requirements made that scope too
|
|
10
|
+
narrow:
|
|
11
|
+
|
|
12
|
+
1. Public-facing surfaces (landing pages, docs sites, product pages)
|
|
13
|
+
need search engines and social preview bots to see a fully rendered
|
|
14
|
+
document on first request, without running JavaScript.
|
|
15
|
+
2. The same component model that powers the live SPA must produce that
|
|
16
|
+
document — we do not want a second component runtime, a hydration
|
|
17
|
+
protocol, or a server renderer.
|
|
18
|
+
|
|
19
|
+
The conventional answers (Next/Nuxt SSR, Astro, Eleventy, Lit SSR,
|
|
20
|
+
Solid Start, …) each ship at least one of:
|
|
21
|
+
|
|
22
|
+
- a separate component model for the server,
|
|
23
|
+
- a hydration boundary that introduces a second source of truth,
|
|
24
|
+
- a build-time JSX/Vue/Svelte compiler,
|
|
25
|
+
- a Node runtime in production.
|
|
26
|
+
|
|
27
|
+
Mado is positioned as "calm native-first": we cannot adopt any of
|
|
28
|
+
those without breaking the positioning.
|
|
29
|
+
|
|
30
|
+
## Decision
|
|
31
|
+
|
|
32
|
+
Adopt **browser-rendered static snapshots with Declarative Shadow
|
|
33
|
+
DOM** as the canonical SEO/static path:
|
|
34
|
+
|
|
35
|
+
1. `mado release` runs `vite build`, then opens each declared static
|
|
36
|
+
route in a real headless Chromium pointed at the build output, and
|
|
37
|
+
serialises the rendered document — including the Shadow DOM as
|
|
38
|
+
Declarative Shadow DOM — into one HTML file per route under
|
|
39
|
+
`out/`.
|
|
40
|
+
2. The client runtime treats the snapshot as an **atomic takeover**
|
|
41
|
+
target: a Mado component instance reattaches to the existing host
|
|
42
|
+
in place, with no second tree, no hydration, no diff.
|
|
43
|
+
3. Routes that are not declared `static` stay SPA-only and are served
|
|
44
|
+
through the `_mado/spa.html` fallback the same way they were
|
|
45
|
+
before.
|
|
46
|
+
4. Vite's `base` is the single source of truth for the public URL
|
|
47
|
+
prefix; the runtime reads it from `import.meta.env.BASE_URL`, the
|
|
48
|
+
CLI reads it from the build bridge (`_mado/build.json`) for
|
|
49
|
+
sitemap / canonical / preview, and the build bridge is dropped
|
|
50
|
+
before the artifact ships.
|
|
51
|
+
5. Build-time seeds for static routes are strict `JsonValue` only,
|
|
52
|
+
validated by a path-aware walker so a `Date`, `Map`, `undefined`
|
|
53
|
+
field or cycle fails the build instead of silently corrupting the
|
|
54
|
+
first client render.
|
|
55
|
+
|
|
56
|
+
## Alternatives rejected
|
|
57
|
+
|
|
58
|
+
- **SSR (Next / Nuxt / Solid Start).** Ships a second component model
|
|
59
|
+
and a Node production runtime. Hydration boundary is the largest
|
|
60
|
+
source of recurring bug classes in the ecosystem. Mado's
|
|
61
|
+
positioning rejects both.
|
|
62
|
+
|
|
63
|
+
- **Hydration via an island / partial hydration model (Astro,
|
|
64
|
+
Marko).** Splits the component graph into "static" and "interactive"
|
|
65
|
+
sub-graphs with framework-specific compilers. Adds a second mental
|
|
66
|
+
model for a public-site benefit that DSD already provides.
|
|
67
|
+
|
|
68
|
+
- **Author-time prerendering with `linkedom`/`jsdom`.** Cannot run
|
|
69
|
+
Shadow DOM, adoptedStyleSheets, layout, or any browser API.
|
|
70
|
+
Snapshots would diverge from what the browser actually renders.
|
|
71
|
+
|
|
72
|
+
- **External prerender service (Prerender.io and friends).** Adds an
|
|
73
|
+
external dependency, runs on each request, and Mado has no canonical
|
|
74
|
+
way to detect when to flush its cache.
|
|
75
|
+
|
|
76
|
+
- **Embed a Node runtime that pretends to be a browser.** Same
|
|
77
|
+
divergence problem as `linkedom`, plus a custom DOM polyfill we
|
|
78
|
+
would have to maintain forever.
|
|
79
|
+
|
|
80
|
+
## Consequences
|
|
81
|
+
|
|
82
|
+
- A compatible Chromium is required at **release time** (not at
|
|
83
|
+
request time, not in production) for projects that declare any
|
|
84
|
+
static route. `mado release` documents how to install one
|
|
85
|
+
(Playwright-managed Chromium, system Chrome, or operator-provided
|
|
86
|
+
path) and CI gates the round-trip with `npx playwright install
|
|
87
|
+
--with-deps chromium` plus `MADO_REQUIRE_BROWSER=1`.
|
|
88
|
+
|
|
89
|
+
- `page.static.paths()` and `page.static.initialData()` must be
|
|
90
|
+
**browser-safe and secret-free**: they execute during the discovery
|
|
91
|
+
pass AND remain in the client bundle. The strict `JsonValue`
|
|
92
|
+
validator catches the common shapes that would otherwise leak.
|
|
93
|
+
|
|
94
|
+
- The framework now has a documented HTTP policy for snapshot capture:
|
|
95
|
+
documents, scripts, stylesheets and tracked resources are fatal;
|
|
96
|
+
favicon-class endpoints are ignored; fonts and paint frames are
|
|
97
|
+
quality hints with bounded timeouts.
|
|
98
|
+
|
|
99
|
+
- The product surface widens from "internal tools / admin panels" to
|
|
100
|
+
"sites and apps". Marketing copy, package metadata, GitHub topics
|
|
101
|
+
and the default starter all change accordingly. The previous
|
|
102
|
+
modular reference architecture is preserved as
|
|
103
|
+
`mado init --starter modular` for long-lived business apps.
|
|
104
|
+
|
|
105
|
+
## Known limits
|
|
106
|
+
|
|
107
|
+
- Static routes cannot use `Date`, `Map`, `Set`, class instances,
|
|
108
|
+
`undefined` values, cycles, or non-finite numbers in their
|
|
109
|
+
`initialData`. The validator gives a path-aware error.
|
|
110
|
+
|
|
111
|
+
- `mado release` snapshots are deterministic only in a pinned
|
|
112
|
+
environment (same Chromium revision, same source tree). We document
|
|
113
|
+
that determinism contract; reproducing it across CI vendors is the
|
|
114
|
+
operator's responsibility.
|
|
115
|
+
|
|
116
|
+
- Static `paths()` runs at build time. We do not currently support
|
|
117
|
+
incremental re-snapshot from a webhook; a static-content change
|
|
118
|
+
requires a fresh release.
|
|
119
|
+
|
|
120
|
+
- Public client-only state inside a static route (canvas, media
|
|
121
|
+
controllers, transient timers) survives takeover but is not part of
|
|
122
|
+
the snapshot — it materialises only after JS executes.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Original implementation plan (for history)
|
|
127
|
+
|
|
128
|
+
The remainder of this document is the original implementation plan
|
|
129
|
+
that drove the work up to 0.12.0. It is preserved verbatim for
|
|
130
|
+
historical context.
|
|
131
|
+
|
|
132
|
+
---
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
> Goal: have a Mado app running locally, edited from VS Code, and shipped to
|
|
4
|
+
> a static host — in under 10 minutes.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Scaffold
|
|
9
|
+
|
|
10
|
+
Mado 0.12 ships with two starters: the **universal** starter (default) and
|
|
11
|
+
the **modular** reference architecture.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Universal starter (default) — ~15 files, one shared component
|
|
15
|
+
npm exec --package @madojs/mado -- mado init my-app
|
|
16
|
+
|
|
17
|
+
# Modular reference starter — auth shell, guarded zones, billing module
|
|
18
|
+
npm exec --package @madojs/mado -- mado init my-app --starter modular
|
|
19
|
+
|
|
20
|
+
cd my-app
|
|
21
|
+
npm install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
What you get either way:
|
|
25
|
+
|
|
26
|
+
- exactly one runtime dependency: `@madojs/mado`;
|
|
27
|
+
- `vite.config.ts` with `mado()` from `@madojs/mado/vite`;
|
|
28
|
+
- `src/main.ts` mounting the router into `#app`;
|
|
29
|
+
- `src/app.routes.ts` (a default export + a named `manifest` export);
|
|
30
|
+
- a `package.json` whose scripts wrap the Mado CLI.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. The dev loop
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm run dev # Vite dev server, fast HMR for templates/styles
|
|
38
|
+
npm run typecheck # tsc --noEmit
|
|
39
|
+
npm run test # node --test (if your project has tests)
|
|
40
|
+
npm run build # SPA build only (out/ without snapshots)
|
|
41
|
+
npm run release # typecheck + vite build + static snapshots + deploy files
|
|
42
|
+
npm run preview # serve out/ like a real static host
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`mado release` is the single command you ship. It produces one folder,
|
|
46
|
+
`out/`, that you can `rsync`/upload to any static host:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm run release
|
|
50
|
+
rsync -avz out/ user@server:/var/www/my-app/
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
See [20-deployment.md](./20-deployment.md) for nginx / Cloudflare Pages /
|
|
54
|
+
GitHub Pages / S3 recipes.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 3. Your first page
|
|
59
|
+
|
|
60
|
+
Two primitives, that's it (see [10-pages-and-components.md](./10-pages-and-components.md)
|
|
61
|
+
for the full mental model):
|
|
62
|
+
|
|
63
|
+
- **`page()`** — a route. Lives at a URL. Renders in light DOM. Has
|
|
64
|
+
`title` / `head` / `load` / `view` / optional `static`.
|
|
65
|
+
- **`component()`** — a reusable `<x-tag>`. Shadow DOM by default.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// src/pages/home.page.ts
|
|
69
|
+
import { html, page } from "@madojs/mado";
|
|
70
|
+
|
|
71
|
+
export default page({
|
|
72
|
+
title: "Home",
|
|
73
|
+
head: () => ({ description: "Hello from Mado" }),
|
|
74
|
+
view: () => html`<h1>Hello, Mado</h1>`,
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// src/app.routes.ts
|
|
80
|
+
import { routes } from "@madojs/mado";
|
|
81
|
+
|
|
82
|
+
export const manifest = {
|
|
83
|
+
"/": () => import("./pages/home.page"),
|
|
84
|
+
"*": () => import("./pages/not-found.page"),
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default routes(manifest);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Always export both `default` (for the router) and `manifest` (so
|
|
91
|
+
`mado static` can discover bakeable pages).
|
|
92
|
+
|
|
93
|
+
Internal links must be base-aware:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { routeUrl } from "@madojs/mado";
|
|
97
|
+
|
|
98
|
+
html`<a data-link href=${routeUrl("/about")}>About</a>`;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`data-link` lets the router intercept the click — including across
|
|
102
|
+
Shadow DOM. `routeUrl()` resolves against `import.meta.env.BASE_URL`,
|
|
103
|
+
so the same code works whether your app is hosted at `/` or at
|
|
104
|
+
`/docs/`.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 4. IDE setup
|
|
109
|
+
|
|
110
|
+
Out of the box `html` and `css` are tagged-template strings. TypeScript
|
|
111
|
+
and most editors don't highlight them by default. The lit ecosystem's
|
|
112
|
+
tools work because Mado uses the same tag names and binding shapes.
|
|
113
|
+
|
|
114
|
+
### VS Code (recommended)
|
|
115
|
+
|
|
116
|
+
1. **Extensions → install [lit-plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin)** (by `runem`).
|
|
117
|
+
2. Import `html` / `css` directly — no rename:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { html, css } from "@madojs/mado";
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
3. (Optional) Recommended settings for Mado in `.vscode/settings.json`:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"lit-plugin.rules": {
|
|
128
|
+
"no-unknown-attribute": "off",
|
|
129
|
+
"no-incompatible-type-binding": "off"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`no-incompatible-type-binding: off` is needed because Mado bindings
|
|
135
|
+
accept signals (`Signal<T>`) where the plugin expects raw values.
|
|
136
|
+
|
|
137
|
+
You get: HTML/CSS highlighting inside templates, attribute/event
|
|
138
|
+
auto-complete, go-to-definition for custom elements, typo checking.
|
|
139
|
+
|
|
140
|
+
### WebStorm / IntelliJ
|
|
141
|
+
|
|
142
|
+
Native support for lit-style template literals since 2021. Nothing to
|
|
143
|
+
install. If highlighting is missing, restart the TS server.
|
|
144
|
+
|
|
145
|
+
### Neovim / Helix
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npm install -g lit-html-server
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Wire it into your LSP config (`lit_html` in `lspconfig`).
|
|
152
|
+
|
|
153
|
+
### Optional extras
|
|
154
|
+
|
|
155
|
+
- **Custom Elements Manifest** for auto-complete on your own
|
|
156
|
+
`<x-*>` components: `npx cem analyze --globs "src/**/*.ts"`.
|
|
157
|
+
- **Prettier 3+** formats `html`/`css` template literals via
|
|
158
|
+
`embeddedLanguageFormatting: "auto"` (default).
|
|
159
|
+
- **eslint-plugin-lit** + **eslint-plugin-wc** provide
|
|
160
|
+
template-aware lint rules. Not required.
|
|
161
|
+
|
|
162
|
+
### What does NOT work today
|
|
163
|
+
|
|
164
|
+
- Type-checking of signal bindings: `<input .value=${count}>` is
|
|
165
|
+
flagged because the plugin expects a string, not a `Signal<number>`.
|
|
166
|
+
Suppress with `// @ts-expect-error` or the settings override above.
|
|
167
|
+
- The `each()` directive is recognised as a plain function — no
|
|
168
|
+
special-case checking inside.
|
|
169
|
+
|
|
170
|
+
Mado works without any IDE plugin — the templates remain valid TS,
|
|
171
|
+
they just won't be syntax-highlighted as HTML.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 5. Where to go next
|
|
176
|
+
|
|
177
|
+
- [10 — Pages and components](./10-pages-and-components.md) — the one rule.
|
|
178
|
+
- [11 — Templates and signals](./11-templates-and-signals.md) — binding shapes.
|
|
179
|
+
- [12 — Routing](./12-routing.md) — manifest, layouts, guards, prefetch.
|
|
180
|
+
- [13 — Data](./13-data.md) — `resource()` / `mutation()` / auth.
|
|
181
|
+
- [14 — Forms](./14-forms.md) — `useForm()` + Shadow DOM input recipes.
|
|
182
|
+
- [15 — Static snapshots](./15-static-snapshots.md) — SEO without SSR.
|
|
183
|
+
- [16 — App architecture](./16-app-architecture.md) — the modular starter, ESLint boundaries.
|