@madojs/mado 0.9.0 → 0.10.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 +58 -7
- package/CHANGELOG.md +91 -1
- package/README.md +20 -4
- package/dist/src/component.d.ts +2 -12
- package/dist/src/component.js +2 -29
- package/dist/src/component.js.map +1 -1
- package/dist/src/diagnostics.d.ts +0 -4
- package/dist/src/diagnostics.js +1 -0
- package/dist/src/diagnostics.js.map +1 -1
- package/dist/src/html/bindings.js +3 -0
- package/dist/src/html/bindings.js.map +1 -1
- package/dist/src/resource.d.ts +3 -6
- package/dist/src/resource.js +59 -10
- package/dist/src/resource.js.map +1 -1
- package/dist/src/router/manifest.d.ts +0 -3
- package/dist/src/router/manifest.js +1 -0
- package/dist/src/router/manifest.js.map +1 -1
- package/dist/src/router.d.ts +1 -1
- package/dist/src/router.js +1 -1
- package/dist/src/router.js.map +1 -1
- package/dist/src/signal.d.ts +0 -4
- package/dist/src/signal.js +1 -0
- package/dist/src/signal.js.map +1 -1
- package/docs/en/03-static-bake.md +1 -2
- package/docs/en/06-for-backenders.md +5 -0
- package/docs/en/08-llm-zero-history-test.md +5 -0
- package/docs/en/18-api-freeze-map.md +63 -0
- package/docs/en/19-reactivity-ordering.md +93 -0
- package/docs/en/20-v1-stability.md +83 -0
- package/docs/en/README.md +3 -0
- package/docs/fr/03-static-bake.md +1 -2
- package/docs/fr/06-for-backenders.md +6 -0
- package/docs/fr/08-llm-zero-history-test.md +5 -0
- package/docs/fr/18-api-freeze-map.md +63 -0
- package/docs/fr/19-reactivity-ordering.md +97 -0
- package/docs/fr/20-v1-stability.md +88 -0
- package/docs/fr/README.md +3 -0
- package/docs/ru/03-static-bake.md +2 -3
- package/docs/ru/06-for-backenders.md +6 -0
- package/docs/ru/08-llm-zero-history-test.md +5 -0
- package/docs/ru/18-api-freeze-map.md +62 -0
- package/docs/ru/19-reactivity-ordering.md +95 -0
- package/docs/ru/20-v1-stability.md +82 -0
- package/docs/ru/README.md +3 -0
- package/docs/uk/06-for-backenders.md +5 -0
- package/docs/uk/08-llm-zero-history-test.md +5 -0
- package/docs/uk/18-api-freeze-map.md +61 -0
- package/docs/uk/19-reactivity-ordering.md +95 -0
- package/docs/uk/20-v1-stability.md +83 -0
- package/docs/uk/README.md +3 -0
- package/llms.txt +59 -5
- package/package.json +8 -3
- package/scripts/bake.mjs +0 -1
- package/scripts/cli.mjs +17 -0
- package/scripts/llm-zero-history-smoke.mjs +93 -0
- package/scripts/new.mjs +1 -1
- package/scripts/package-smoke.mjs +74 -0
- package/scripts/size-budget.mjs +88 -0
- package/starters/admin/package.json +2 -2
- package/starters/crud/package.json +2 -2
- package/starters/minimal/package.json +2 -2
|
@@ -148,7 +148,6 @@ out/
|
|
|
148
148
|
{"@context":"https://schema.org","@type":"Product","..."}
|
|
149
149
|
</script>
|
|
150
150
|
<meta name="bake-revalidate" content="3600" data-mado-head="baked">
|
|
151
|
-
<meta name="bake-stamp" content="1234567890" data-mado-head="baked">
|
|
152
151
|
</head>
|
|
153
152
|
<body>
|
|
154
153
|
<div id="app">
|
|
@@ -231,7 +230,7 @@ export default page<{ slug: string }>({
|
|
|
231
230
|
|
|
232
231
|
## Revalidate / CDN
|
|
233
232
|
|
|
234
|
-
`bake.revalidate: 3600` écrit `<meta name="bake-revalidate" content="3600">`
|
|
233
|
+
`bake.revalidate: 3600` écrit `<meta name="bake-revalidate" content="3600">`
|
|
235
234
|
dans le HTML. C'est des **métadonnées** — le framework ne re-bake rien lui-même. Stratégies :
|
|
236
235
|
|
|
237
236
|
1. **Option la plus simple** : cron dans CI — `npm run bake && rsync out/ origin:/var/www/`.
|
|
@@ -154,6 +154,12 @@ await save.run(newUser);
|
|
|
154
154
|
// automatiquement : user.data() se mettra à jour si le glob correspond
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
Les clés de `resource()` sont l'identité du cache. Incluez l'endpoint, les query
|
|
158
|
+
params et la forme des données dans la clé : deux `resource()` vivants avec la
|
|
159
|
+
même clé partagent le cache et la requête in-flight. Si la même clé est utilisée
|
|
160
|
+
avec un fetcher différent, Mado avertit, car cela signifie généralement que la
|
|
161
|
+
clé de cache est trop large.
|
|
162
|
+
|
|
157
163
|
Si une telle abstraction existait dans le monde Go pour les caches côté serveur — on
|
|
158
164
|
pleurerait tous de joie.
|
|
159
165
|
|
|
@@ -53,6 +53,11 @@ Cherchez ces éléments après l'implémentation :
|
|
|
53
53
|
L'implémentation actuelle de `examples/tickets` n'a pas nécessité de nouvelles API publiques ni
|
|
54
54
|
de dépendances runtime.
|
|
55
55
|
|
|
56
|
+
CI exécute `npm run llm:smoke` comme proxy déterministe pour cette tâche :
|
|
57
|
+
il vérifie que `llms.txt` contient toujours les règles clés, compare l'artefact
|
|
58
|
+
commité `examples/tickets` à la surface API Mado requise et aux failure
|
|
59
|
+
patterns, puis build le projet et lance `test/tickets-smoke.test.mjs`.
|
|
60
|
+
|
|
56
61
|
Le principal point de pression dans la documentation reste le lifecycle : les anciens exemples
|
|
57
62
|
peuvent donner l'impression qu'il est acceptable de créer `resource()` directement dans
|
|
58
63
|
`page.view()`. L'exemple tickets utilise plutôt des composants wrapper au niveau page, de sorte
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Carte de gel de l'API
|
|
2
|
+
|
|
3
|
+
> Ce qui est public, ce qui est interne, et ce que SemVer protégera en v1.
|
|
4
|
+
|
|
5
|
+
Le contrat v1 de Mado est volontairement petit. Le code applicatif importe
|
|
6
|
+
depuis la racine du package :
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { component, html, resource, routes, signal } from "@madojs/mado";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Le seul subpath public est le module side-effect devtools :
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import "@madojs/mado/devtools.js";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Tout le reste sous `dist/src/` est un détail d'implémentation, même si le
|
|
19
|
+
fichier est visible dans le dépôt.
|
|
20
|
+
|
|
21
|
+
## API publique stable
|
|
22
|
+
|
|
23
|
+
Ces noms sont publics et protégés par SemVer une fois v1 publiée :
|
|
24
|
+
|
|
25
|
+
- Réactivité : `signal`, `computed`, `effect`, `untracked`, `batch`,
|
|
26
|
+
`flushSync`.
|
|
27
|
+
- Templates et directives : `html`, `render`, `each`, `list`, `unsafeHTML`,
|
|
28
|
+
`ref`, `classMap`, `styleMap`.
|
|
29
|
+
- Composants et CSS : `component`, `css`, `cssVars`.
|
|
30
|
+
- Routage et pages : `routes`, `router`, `page`, `layout`, `nested`,
|
|
31
|
+
`navigate`, `queryParam`, `prefetchPath`.
|
|
32
|
+
- Data : `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
|
|
33
|
+
- Formulaires : `useForm`.
|
|
34
|
+
- Head et persistence : `applyHead`, `persisted`.
|
|
35
|
+
- Context : `createContext`, `provide`, `inject`.
|
|
36
|
+
- Helpers lifecycle avancés : `createLifecycle`, `runInLifecycle`,
|
|
37
|
+
`getCurrentLifecycle`.
|
|
38
|
+
- Types TypeScript publics exportés depuis `@madojs/mado`.
|
|
39
|
+
|
|
40
|
+
## Interne ou instable
|
|
41
|
+
|
|
42
|
+
Ce n'est pas de l'API publique :
|
|
43
|
+
|
|
44
|
+
- Subpaths du package autres que `@madojs/mado` et
|
|
45
|
+
`@madojs/mado/devtools.js`.
|
|
46
|
+
- Internals du parser/binding comme `html/parser.js`, `html/bindings.js`,
|
|
47
|
+
`ChildState` et `EachEntry`.
|
|
48
|
+
- Internals du routeur comme `router/match.js`, `router/navigation.js` et
|
|
49
|
+
`router/manifest.js`.
|
|
50
|
+
- Internals de diagnostics et tous les `_testHooks`.
|
|
51
|
+
- Texte exact du bundle généré, noms des chunks et layout interne des fichiers.
|
|
52
|
+
|
|
53
|
+
Les tests du dépôt peuvent importer des fichiers internes via des chemins
|
|
54
|
+
relatifs `dist/`. Le code applicatif ne doit pas le faire.
|
|
55
|
+
|
|
56
|
+
## Ce qui peut changer
|
|
57
|
+
|
|
58
|
+
Les patch et minor releases peuvent ajouter des root exports, options,
|
|
59
|
+
diagnostics, docs ou starters. Elles peuvent aussi changer les internals, la
|
|
60
|
+
forme du bundle et les détails d'implémentation tant que l'API stable et le
|
|
61
|
+
comportement documenté restent compatibles.
|
|
62
|
+
|
|
63
|
+
Les changements cassants de l'API stable nécessitent une version majeure.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Ordre de la réactivité
|
|
2
|
+
|
|
3
|
+
> Le petit ensemble de garanties d'ordre que Mado traite comme comportement public.
|
|
4
|
+
|
|
5
|
+
La réactivité de Mado est synchrone pour les lectures et planifiée pour les
|
|
6
|
+
side effects. Le but est une mise à jour UI prévisible plutôt qu'un grand modèle
|
|
7
|
+
de scheduling.
|
|
8
|
+
|
|
9
|
+
## Signals
|
|
10
|
+
|
|
11
|
+
`signal(value)` renvoie une fonction getter. `set(next)` change la valeur
|
|
12
|
+
immédiatement sauf si `Object.is(previous, next)` vaut `true`.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
const count = signal(0);
|
|
16
|
+
count.set(1);
|
|
17
|
+
count(); // 1, immédiatement
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Les computed values sont marquées avant l'exécution des effects : un effect qui
|
|
21
|
+
lit un computed observe les dépendances courantes, pas un cache obsolète.
|
|
22
|
+
|
|
23
|
+
## Effects
|
|
24
|
+
|
|
25
|
+
`effect(fn)` s'exécute une première fois immédiatement. Les changements
|
|
26
|
+
ultérieurs de dépendances planifient une seule exécution en microtask. Les tests
|
|
27
|
+
peuvent appeler `flushSync()` pour vider cette file de façon synchrone.
|
|
28
|
+
|
|
29
|
+
Si un effect retourne une fonction de cleanup, Mado l'exécute avant l'exécution
|
|
30
|
+
suivante de l'effect et à nouveau quand le disposer est appelé.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
const stop = effect(() => {
|
|
34
|
+
const id = setInterval(tick, 1000);
|
|
35
|
+
return () => clearInterval(id);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
stop();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Dans les composants et pages, préférez `ctx.onDispose()` / page `onDispose()`
|
|
42
|
+
pour le cleanup à l'unmount. Le cleanup d'un effect est un cleanup par run.
|
|
43
|
+
|
|
44
|
+
## Batch
|
|
45
|
+
|
|
46
|
+
`batch(fn)` regroupe les écritures de signals en un seul passage des
|
|
47
|
+
subscribers. Les effects ne s'exécutent pas avant la sortie du batch le plus
|
|
48
|
+
extérieur, y compris avec des batches imbriqués.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
batch(() => {
|
|
52
|
+
first.set("Ada");
|
|
53
|
+
batch(() => last.set("Lovelace"));
|
|
54
|
+
});
|
|
55
|
+
// les effects ne voient que la paire finale
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Les `computed({ equals })` observés préservent aussi l'atomicité du batch : ils
|
|
59
|
+
se recalculent une fois après le batch extérieur, sur l'état entièrement
|
|
60
|
+
appliqué. Ils ne doivent pas observer un batch à moitié appliqué comme
|
|
61
|
+
`(new x, old y)`.
|
|
62
|
+
|
|
63
|
+
## Mises à jour DOM
|
|
64
|
+
|
|
65
|
+
`render(result, container)` réutilise l'instance de template existante quand le
|
|
66
|
+
render suivant a les mêmes template strings. Pour les child bindings qui
|
|
67
|
+
retournent un `html``` imbriqué, la même règle s'applique : mêmes strings =
|
|
68
|
+
mise à jour sur place, autres strings = reconstruction de cette branche.
|
|
69
|
+
|
|
70
|
+
Ainsi, des changements de signals sans rapport ne recréent pas un `<input>`
|
|
71
|
+
dans un template imbriqué stable : focus, état DOM et listeners survivent.
|
|
72
|
+
|
|
73
|
+
Les listes doivent utiliser `each(items, key, renderItem)`. Les keys définissent
|
|
74
|
+
l'identité DOM. Les duplicate keys avertissent en development et retombent sur
|
|
75
|
+
un suffixe positionnel pour que chaque item soit rendu, mais les duplicate keys
|
|
76
|
+
sont un bug de données.
|
|
77
|
+
|
|
78
|
+
## Teardown des composants
|
|
79
|
+
|
|
80
|
+
Les custom elements peuvent recevoir `disconnectedCallback()` puis
|
|
81
|
+
`connectedCallback()` pendant un déplacement dans le même tick. Mado diffère le
|
|
82
|
+
teardown du composant jusqu'à une microtask et l'annule si l'élément est
|
|
83
|
+
reconnecté, donc les reorders keyed préservent l'état du composant. Une vraie
|
|
84
|
+
suppression lance tout de même le cleanup lifecycle à la microtask suivante.
|
|
85
|
+
|
|
86
|
+
## Non garanti
|
|
87
|
+
|
|
88
|
+
Mado ne garantit pas le nombre exact de microtasks internes du scheduler,
|
|
89
|
+
l'ordre des effects indépendants sans dépendances communes, la forme du bundle
|
|
90
|
+
généré ni le layout interne des modules. Ce sont des détails d'implémentation.
|
|
91
|
+
|
|
92
|
+
Les tests invariants de ce contrat vivent dans :
|
|
93
|
+
|
|
94
|
+
- `test/reactivity-ordering.test.mjs`
|
|
95
|
+
- `test/signal-batch-equals.test.mjs`
|
|
96
|
+
- `test/update-nested-reuse.test.mjs`
|
|
97
|
+
- `test/each-component-state.test.mjs`
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Stabilité v1
|
|
2
|
+
|
|
3
|
+
> Ce que Mado promet après v1, et ce qui reste libre d'évoluer.
|
|
4
|
+
|
|
5
|
+
Mado v1 signifie que le contrat public côté application est assez stable pour
|
|
6
|
+
de vraies applications métier. Cela ne veut pas dire que chaque fichier interne,
|
|
7
|
+
octet généré, starter copy ou diagnostic string est gelé pour toujours.
|
|
8
|
+
|
|
9
|
+
À lire avec :
|
|
10
|
+
|
|
11
|
+
- [Carte de gel de l'API](./18-api-freeze-map.md)
|
|
12
|
+
- [Ordre de la réactivité](./19-reactivity-ordering.md)
|
|
13
|
+
|
|
14
|
+
## Stable sous SemVer
|
|
15
|
+
|
|
16
|
+
Après v1, Mado considère comme protégés par SemVer :
|
|
17
|
+
|
|
18
|
+
- Les exports publics de `@madojs/mado`.
|
|
19
|
+
- Les types TypeScript publics exportés depuis `@madojs/mado`.
|
|
20
|
+
- Le subpath side-effect `@madojs/mado/devtools.js`.
|
|
21
|
+
- La syntaxe de template binding : child `${}`, `@event`, `.prop`,
|
|
22
|
+
`?boolean`, attribute bindings, directives et `each()`.
|
|
23
|
+
- Les semantics des signals documentées dans le guide d'ordre de réactivité.
|
|
24
|
+
- Les semantics du lifecycle composant : setup une fois par connection
|
|
25
|
+
lifetime, teardown différé pour les same-tick moves, cleanup via
|
|
26
|
+
`ctx.onDispose`.
|
|
27
|
+
- Les contrats router/page/resource/form documentés dans les docs anglaises.
|
|
28
|
+
- Les noms de commandes CLI et leur intention générale (`build`, `dev`,
|
|
29
|
+
`release`, `bake`, `bundle`, `preview`, `init`, `new`).
|
|
30
|
+
|
|
31
|
+
Casser cela nécessite une version majeure.
|
|
32
|
+
|
|
33
|
+
## Autorisé en minor releases
|
|
34
|
+
|
|
35
|
+
Les minor releases peuvent ajouter :
|
|
36
|
+
|
|
37
|
+
- De nouveaux root exports.
|
|
38
|
+
- De nouvelles options sur des API existantes.
|
|
39
|
+
- De nouveaux diagnostics et warnings.
|
|
40
|
+
- De nouveaux starters, examples, docs et flags CLI.
|
|
41
|
+
- Des améliorations de performance et des rewrites internes.
|
|
42
|
+
|
|
43
|
+
Une minor release ne devrait pas forcer les apps correctes existantes à changer
|
|
44
|
+
leur code.
|
|
45
|
+
|
|
46
|
+
## Autorisé en patch releases
|
|
47
|
+
|
|
48
|
+
Les patch releases peuvent corriger des bugs, durcir les diagnostics, améliorer
|
|
49
|
+
les docs et faire des changements d'implémentation compatibles. Un patch peut
|
|
50
|
+
changer le timing seulement si l'ancien timing était un bug non documenté et
|
|
51
|
+
que le changement conserve le contrat d'ordre de réactivité.
|
|
52
|
+
|
|
53
|
+
## Non stable
|
|
54
|
+
|
|
55
|
+
Ne sont volontairement pas protégés par SemVer :
|
|
56
|
+
|
|
57
|
+
- Les subpaths internes du package autres que `@madojs/mado/devtools.js`.
|
|
58
|
+
- Les fichiers sous `src/`, `dist/src/` et les frontières de modules
|
|
59
|
+
d'implémentation.
|
|
60
|
+
- `_testHooks`, internals de diagnostics et warning codes.
|
|
61
|
+
- Le JavaScript exact généré, les noms de chunks, le contenu sourcemap et le
|
|
62
|
+
byte layout du bundle.
|
|
63
|
+
- Les structures internes du parser, des bindings, du routeur et du cache
|
|
64
|
+
resource.
|
|
65
|
+
- Le texte visuel et les données de démonstration des starters.
|
|
66
|
+
|
|
67
|
+
Les apps ne doivent pas importer de fichiers internes ni vérifier l'output exact
|
|
68
|
+
du bundle.
|
|
69
|
+
|
|
70
|
+
## Bundle et output de release
|
|
71
|
+
|
|
72
|
+
Mado gardera un size budget et des tests de release déterministe, mais la
|
|
73
|
+
stabilité v1 ne fige pas l'output du bundler octet par octet. Les hashes,
|
|
74
|
+
frontières de chunks et noms d'assets générés peuvent changer tant que le
|
|
75
|
+
contrat de déploiement documenté continue de fonctionner.
|
|
76
|
+
|
|
77
|
+
## Si une release vous casse
|
|
78
|
+
|
|
79
|
+
Si une mise à jour casse du code qui utilise seulement les exports publics et le
|
|
80
|
+
comportement documenté, traitez-le comme un bug. Ouvrez une issue avec :
|
|
81
|
+
|
|
82
|
+
- la version de Mado avant et après ;
|
|
83
|
+
- l'API publique impliquée ;
|
|
84
|
+
- une reproduction minimale ;
|
|
85
|
+
- si la casse concerne le runtime, les types TypeScript, l'output CLI ou les docs.
|
|
86
|
+
|
|
87
|
+
Si la casse dépend d'un subpath interne ou de l'output généré exact, cela peut
|
|
88
|
+
quand même valoir un rapport, mais ce n'est pas considéré comme une casse SemVer.
|
package/docs/fr/README.md
CHANGED
|
@@ -22,3 +22,6 @@ Documentation française.
|
|
|
22
22
|
| Gestion des erreurs | [15-error-handling.md](./15-error-handling.md) |
|
|
23
23
|
| Guide de recettes bake | [16-bake-cookbook.md](./16-bake-cookbook.md) |
|
|
24
24
|
| Shadow DOM + formulaires | [17-shadow-dom-forms.md](./17-shadow-dom-forms.md) |
|
|
25
|
+
| Carte de gel de l'API | [18-api-freeze-map.md](./18-api-freeze-map.md) |
|
|
26
|
+
| Ordre de la réactivité | [19-reactivity-ordering.md](./19-reactivity-ordering.md) |
|
|
27
|
+
| Stabilité v1 | [20-v1-stability.md](./20-v1-stability.md) |
|
|
@@ -129,7 +129,6 @@ out/
|
|
|
129
129
|
{"@context":"https://schema.org","@type":"Product","..."}
|
|
130
130
|
</script>
|
|
131
131
|
<meta name="bake-revalidate" content="3600" data-mado-head="baked">
|
|
132
|
-
<meta name="bake-stamp" content="1234567890" data-mado-head="baked">
|
|
133
132
|
</head>
|
|
134
133
|
<body>
|
|
135
134
|
<div id="app">
|
|
@@ -212,7 +211,7 @@ export default page<{ slug: string }>({
|
|
|
212
211
|
|
|
213
212
|
## Revalidate / CDN
|
|
214
213
|
|
|
215
|
-
`bake.revalidate: 3600` пишет в HTML `<meta name="bake-revalidate" content="3600"
|
|
214
|
+
`bake.revalidate: 3600` пишет в HTML `<meta name="bake-revalidate" content="3600">`. Это **метаданные** — фреймворк сам ничего не перевыпекает. Стратегии:
|
|
216
215
|
|
|
217
216
|
1. **Простейший вариант**: cron в CI — `npm run bake && rsync out/ origin:/var/www/`.
|
|
218
217
|
2. **Через CDN** (Cloudflare/Fastly): кладёте HTML с `Cache-Control: max-age=3600`. CDN сам инвалидирует.
|
|
@@ -248,4 +247,4 @@ export default page<{ slug: string }>({
|
|
|
248
247
|
|
|
249
248
|
Если страница **общая для всех пользователей**, имеет **относительно стабильный набор URL'ов** и важен **SEO + первый paint** — добавьте `bake: { paths, data }` и получите статический HTML с meta/JSON-LD/sitemap за миллисекунды. Без node-сервера, без Chrome, без магии.
|
|
250
249
|
|
|
251
|
-
Если страница персонализирована, или URL'ов миллион, или контент меняется в реальном времени — `bake` не ваш инструмент. Оставляйте SPA или подключайте отдельный SSR-фреймворк.
|
|
250
|
+
Если страница персонализирована, или URL'ов миллион, или контент меняется в реальном времени — `bake` не ваш инструмент. Оставляйте SPA или подключайте отдельный SSR-фреймворк.
|
|
@@ -150,6 +150,12 @@ await save.run(newUser);
|
|
|
150
150
|
// автоматически: user.data() обновится, если совпал glob
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
Ключи `resource()` — это identity кеша. Включайте endpoint, query params и
|
|
154
|
+
форму данных в ключ: два живых `resource()` с одинаковым ключом разделяют кеш
|
|
155
|
+
и in-flight request. Если один и тот же ключ используется с другим fetcher,
|
|
156
|
+
Mado предупреждает, потому что обычно это значит, что ключ кеша слишком
|
|
157
|
+
широкий.
|
|
158
|
+
|
|
153
159
|
Если бы такая абстракция была в Go-мире для серверных кешей — мы бы все плакали от счастья.
|
|
154
160
|
|
|
155
161
|
---
|
|
@@ -51,6 +51,11 @@
|
|
|
51
51
|
Текущая реализация `examples/tickets` не потребовала новых публичных API или
|
|
52
52
|
runtime-зависимостей.
|
|
53
53
|
|
|
54
|
+
CI запускает `npm run llm:smoke` как детерминированный proxy для этой задачи:
|
|
55
|
+
проверяет, что `llms.txt` всё ещё содержит ключевые правила, сверяет
|
|
56
|
+
зафиксированный артефакт `examples/tickets` с нужной Mado API surface и
|
|
57
|
+
failure patterns, затем собирает проект и запускает `test/tickets-smoke.test.mjs`.
|
|
58
|
+
|
|
54
59
|
Основная болевая точка в документации остается lifecycle: старые примеры могут
|
|
55
60
|
создать впечатление, что создание `resource()` прямо в `page.view()` допустимо.
|
|
56
61
|
Пример tickets использует page-level wrapper-компоненты вместо этого, поэтому
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Карта заморозки API
|
|
2
|
+
|
|
3
|
+
> Что публично, что внутреннее, и что SemVer будет защищать в v1.
|
|
4
|
+
|
|
5
|
+
Контракт Mado v1 намеренно небольшой. Код приложения импортирует API из корня
|
|
6
|
+
пакета:
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { component, html, resource, routes, signal } from "@madojs/mado";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Единственный публичный subpath — side-effect модуль devtools:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import "@madojs/mado/devtools.js";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Все остальное под `dist/src/` — деталь реализации, даже если файл виден в
|
|
19
|
+
репозитории.
|
|
20
|
+
|
|
21
|
+
## Стабильный публичный API
|
|
22
|
+
|
|
23
|
+
Эти имена публичны и будут защищены SemVer после v1:
|
|
24
|
+
|
|
25
|
+
- Reactivity: `signal`, `computed`, `effect`, `untracked`, `batch`,
|
|
26
|
+
`flushSync`.
|
|
27
|
+
- Templates и directives: `html`, `render`, `each`, `list`, `unsafeHTML`,
|
|
28
|
+
`ref`, `classMap`, `styleMap`.
|
|
29
|
+
- Components и CSS: `component`, `css`, `cssVars`.
|
|
30
|
+
- Routing и pages: `routes`, `router`, `page`, `layout`, `nested`,
|
|
31
|
+
`navigate`, `queryParam`, `prefetchPath`.
|
|
32
|
+
- Data: `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
|
|
33
|
+
- Forms: `useForm`.
|
|
34
|
+
- Head и persistence: `applyHead`, `persisted`.
|
|
35
|
+
- Context: `createContext`, `provide`, `inject`.
|
|
36
|
+
- Advanced lifecycle helpers: `createLifecycle`, `runInLifecycle`,
|
|
37
|
+
`getCurrentLifecycle`.
|
|
38
|
+
- Публичные TypeScript-типы, экспортируемые из `@madojs/mado`.
|
|
39
|
+
|
|
40
|
+
## Внутреннее или нестабильное
|
|
41
|
+
|
|
42
|
+
Это не публичный API:
|
|
43
|
+
|
|
44
|
+
- Package subpaths кроме `@madojs/mado` и `@madojs/mado/devtools.js`.
|
|
45
|
+
- Internals парсера/биндингов: `html/parser.js`, `html/bindings.js`,
|
|
46
|
+
`ChildState`, `EachEntry`.
|
|
47
|
+
- Internals роутера: `router/match.js`, `router/navigation.js`,
|
|
48
|
+
`router/manifest.js`.
|
|
49
|
+
- Diagnostics internals и все `_testHooks`.
|
|
50
|
+
- Точный текст bundle, имена chunks и внутренняя структура файлов.
|
|
51
|
+
|
|
52
|
+
Тесты репозитория могут импортировать внутренние файлы через относительные
|
|
53
|
+
пути `dist/`. Код приложений так делать не должен.
|
|
54
|
+
|
|
55
|
+
## Что может меняться
|
|
56
|
+
|
|
57
|
+
Patch и minor релизы могут добавлять root exports, опции, diagnostics, docs или
|
|
58
|
+
starter files. Они также могут менять internals, форму bundle и детали
|
|
59
|
+
реализации, если стабильный API и задокументированное поведение остаются
|
|
60
|
+
совместимыми.
|
|
61
|
+
|
|
62
|
+
Ломающие изменения стабильного API требуют major version.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Порядок reactivity
|
|
2
|
+
|
|
3
|
+
> Небольшой набор ordering-гарантий, которые Mado считает публичным поведением.
|
|
4
|
+
|
|
5
|
+
Reactivity в Mado синхронна для чтения и планирует side effects. Цель —
|
|
6
|
+
предсказуемые UI-обновления без большой scheduling-модели.
|
|
7
|
+
|
|
8
|
+
## Signals
|
|
9
|
+
|
|
10
|
+
`signal(value)` возвращает getter-функцию. `set(next)` меняет значение сразу,
|
|
11
|
+
если `Object.is(previous, next)` не вернул `true`.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
const count = signal(0);
|
|
15
|
+
count.set(1);
|
|
16
|
+
count(); // 1, сразу
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`computed` помечается до запуска effects, поэтому effect, читающий computed,
|
|
20
|
+
видит актуальные dependencies, а не старый кеш.
|
|
21
|
+
|
|
22
|
+
## Effects
|
|
23
|
+
|
|
24
|
+
`effect(fn)` запускается один раз сразу. Последующие изменения dependencies
|
|
25
|
+
планируют один запуск effect в microtask. В тестах можно вызвать `flushSync()`,
|
|
26
|
+
чтобы синхронно очистить очередь.
|
|
27
|
+
|
|
28
|
+
Если effect возвращает cleanup-функцию, Mado запускает ее перед следующим
|
|
29
|
+
запуском effect и еще раз при вызове disposer.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const stop = effect(() => {
|
|
33
|
+
const id = setInterval(tick, 1000);
|
|
34
|
+
return () => clearInterval(id);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
stop();
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
В компонентах и pages для unmount cleanup предпочитайте `ctx.onDispose()` /
|
|
41
|
+
page `onDispose()`. Cleanup effect — это cleanup между запусками.
|
|
42
|
+
|
|
43
|
+
## Batch
|
|
44
|
+
|
|
45
|
+
`batch(fn)` группирует записи signals в один subscriber pass. Effects не
|
|
46
|
+
запускаются до выхода из внешнего batch, включая вложенные batches.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
batch(() => {
|
|
50
|
+
first.set("Ada");
|
|
51
|
+
batch(() => last.set("Lovelace"));
|
|
52
|
+
});
|
|
53
|
+
// effects увидят только финальную пару
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Наблюдаемые `computed({ equals })` также сохраняют batch atomicity: они
|
|
57
|
+
пересчитываются один раз после внешнего batch на полностью примененном state.
|
|
58
|
+
Они не должны видеть половинчатый batch вроде `(new x, old y)`.
|
|
59
|
+
|
|
60
|
+
## DOM updates
|
|
61
|
+
|
|
62
|
+
`render(result, container)` переиспользует существующий template instance, когда
|
|
63
|
+
следующий render имеет те же template strings. Для child bindings, возвращающих
|
|
64
|
+
вложенный `html```, действует то же правило: те же strings обновляются на
|
|
65
|
+
месте, другие strings пересобирают ветку.
|
|
66
|
+
|
|
67
|
+
Это значит, что несвязанные изменения signals не пересоздают `<input>` внутри
|
|
68
|
+
стабильного вложенного template, поэтому focus, DOM state и listeners
|
|
69
|
+
сохраняются.
|
|
70
|
+
|
|
71
|
+
Списки должны использовать `each(items, key, renderItem)`. Keys задают DOM
|
|
72
|
+
identity. Duplicate keys предупреждают в development и получают positional
|
|
73
|
+
suffix, чтобы все элементы все равно отрендерились, но duplicate keys — это
|
|
74
|
+
ошибка данных.
|
|
75
|
+
|
|
76
|
+
## Teardown компонентов
|
|
77
|
+
|
|
78
|
+
Custom elements могут получить `disconnectedCallback()`, а затем
|
|
79
|
+
`connectedCallback()` во время same-tick move. Mado откладывает teardown
|
|
80
|
+
компонента до microtask и отменяет его при reconnect, поэтому keyed reorders
|
|
81
|
+
сохраняют state компонента. Настоящее удаление все равно запускает cleanup на
|
|
82
|
+
следующей microtask.
|
|
83
|
+
|
|
84
|
+
## Не гарантируется
|
|
85
|
+
|
|
86
|
+
Mado не гарантирует точное число внутренних scheduler microtasks, порядок
|
|
87
|
+
независимых effects без общих dependencies, форму generated bundle или
|
|
88
|
+
внутреннюю структуру modules. Это детали реализации.
|
|
89
|
+
|
|
90
|
+
Invariant tests для этого контракта:
|
|
91
|
+
|
|
92
|
+
- `test/reactivity-ordering.test.mjs`
|
|
93
|
+
- `test/signal-batch-equals.test.mjs`
|
|
94
|
+
- `test/update-nested-reuse.test.mjs`
|
|
95
|
+
- `test/each-component-state.test.mjs`
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Стабильность v1
|
|
2
|
+
|
|
3
|
+
> Что Mado обещает после v1, и что остается свободным для развития.
|
|
4
|
+
|
|
5
|
+
Mado v1 означает, что публичный app-facing contract достаточно стабилен для
|
|
6
|
+
реальных business apps. Это не значит, что каждый внутренний файл, generated
|
|
7
|
+
byte, starter copy или diagnostic string заморожены навсегда.
|
|
8
|
+
|
|
9
|
+
Читайте вместе с:
|
|
10
|
+
|
|
11
|
+
- [Карта заморозки API](./18-api-freeze-map.md)
|
|
12
|
+
- [Порядок reactivity](./19-reactivity-ordering.md)
|
|
13
|
+
|
|
14
|
+
## Стабильно под SemVer
|
|
15
|
+
|
|
16
|
+
После v1 Mado считает SemVer-protected:
|
|
17
|
+
|
|
18
|
+
- Public exports из `@madojs/mado`.
|
|
19
|
+
- Public TypeScript types из `@madojs/mado`.
|
|
20
|
+
- Side-effect subpath `@madojs/mado/devtools.js`.
|
|
21
|
+
- Template binding syntax: child `${}`, `@event`, `.prop`, `?boolean`,
|
|
22
|
+
attribute bindings, directives и `each()`.
|
|
23
|
+
- Signal semantics, описанные в reactivity ordering guide.
|
|
24
|
+
- Component lifecycle semantics: setup один раз за connection lifetime,
|
|
25
|
+
deferred teardown для same-tick moves, cleanup через `ctx.onDispose`.
|
|
26
|
+
- Router/page/resource/form contracts, описанные в English docs.
|
|
27
|
+
- Имена CLI commands и широкий смысл команд (`build`, `dev`, `release`,
|
|
28
|
+
`bake`, `bundle`, `preview`, `init`, `new`).
|
|
29
|
+
|
|
30
|
+
Ломать это можно только в major version.
|
|
31
|
+
|
|
32
|
+
## Разрешено в minor releases
|
|
33
|
+
|
|
34
|
+
Minor releases могут добавлять:
|
|
35
|
+
|
|
36
|
+
- New root exports.
|
|
37
|
+
- New options на существующих API.
|
|
38
|
+
- New diagnostics и warnings.
|
|
39
|
+
- New starters, examples, docs и CLI flags.
|
|
40
|
+
- Performance improvements и внутренние rewrites.
|
|
41
|
+
|
|
42
|
+
Minor release не должен требовать изменений в уже корректных apps.
|
|
43
|
+
|
|
44
|
+
## Разрешено в patch releases
|
|
45
|
+
|
|
46
|
+
Patch releases могут исправлять bugs, ужесточать diagnostics, улучшать docs и
|
|
47
|
+
делать совместимые implementation changes. Patch может изменить timing только
|
|
48
|
+
когда старый timing был незадокументированным bug и новое поведение сохраняет
|
|
49
|
+
reactivity ordering contract.
|
|
50
|
+
|
|
51
|
+
## Нестабильно
|
|
52
|
+
|
|
53
|
+
Это намеренно не защищено SemVer:
|
|
54
|
+
|
|
55
|
+
- Internal package subpaths кроме `@madojs/mado/devtools.js`.
|
|
56
|
+
- Файлы под `src/`, `dist/src/` и implementation module boundaries.
|
|
57
|
+
- `_testHooks`, diagnostics internals и warning codes.
|
|
58
|
+
- Точный JavaScript output, chunk names, sourcemap content и bundle byte layout.
|
|
59
|
+
- Internal parser, binding, router и resource cache data structures.
|
|
60
|
+
- Visual copy и demo data в starters.
|
|
61
|
+
|
|
62
|
+
Apps не должны импортировать internal files или проверять точный bundle output.
|
|
63
|
+
|
|
64
|
+
## Bundle и release output
|
|
65
|
+
|
|
66
|
+
Mado держит size budget и deterministic release tests, но v1 stability не
|
|
67
|
+
замораживает byte-for-byte bundler output. Hashes, chunk boundaries и asset
|
|
68
|
+
names могут меняться, если задокументированный deployment contract продолжает
|
|
69
|
+
работать.
|
|
70
|
+
|
|
71
|
+
## Если релиз вас сломал
|
|
72
|
+
|
|
73
|
+
Если update ломает код, который использует только public exports и
|
|
74
|
+
задокументированное поведение, считайте это bug. Откройте issue и укажите:
|
|
75
|
+
|
|
76
|
+
- версию Mado до и после;
|
|
77
|
+
- задействованный public API;
|
|
78
|
+
- минимальную репродукцию;
|
|
79
|
+
- это runtime behaviour, TypeScript types, CLI output или docs.
|
|
80
|
+
|
|
81
|
+
Если поломка зависит от internal subpath или точного generated output, ее все
|
|
82
|
+
равно можно зарепортить, но это не считается SemVer break.
|
package/docs/ru/README.md
CHANGED
|
@@ -20,3 +20,6 @@
|
|
|
20
20
|
| Обработка ошибок | [15-error-handling.md](./15-error-handling.md) |
|
|
21
21
|
| Рецепты bake | [16-bake-cookbook.md](./16-bake-cookbook.md) |
|
|
22
22
|
| Shadow DOM + формы | [17-shadow-dom-forms.md](./17-shadow-dom-forms.md) |
|
|
23
|
+
| Карта заморозки API | [18-api-freeze-map.md](./18-api-freeze-map.md) |
|
|
24
|
+
| Порядок reactivity | [19-reactivity-ordering.md](./19-reactivity-ordering.md) |
|
|
25
|
+
| Стабильность v1 | [20-v1-stability.md](./20-v1-stability.md) |
|
|
@@ -26,6 +26,11 @@ const save = mutation(api.saveUser, {
|
|
|
26
26
|
});
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
Ключі `resource()` — це identity кешу. Додавайте endpoint, query params і форму
|
|
30
|
+
даних у ключ: два живі `resource()` з однаковим ключем ділять cache та
|
|
31
|
+
in-flight request. Якщо той самий ключ використано з іншим fetcher, Mado
|
|
32
|
+
попереджає, бо зазвичай це означає, що ключ кешу занадто широкий.
|
|
33
|
+
|
|
29
34
|
## Форми
|
|
30
35
|
|
|
31
36
|
```ts
|
|
@@ -27,5 +27,10 @@ Mado CRUD, не перетворюючи його на React у tagged templates
|
|
|
27
27
|
resources, mutations, invalidation, `queryParam`, `computed`, `signal` і
|
|
28
28
|
keyed lists.
|
|
29
29
|
|
|
30
|
+
CI запускає `npm run llm:smoke` як детермінований proxy для цієї задачі:
|
|
31
|
+
перевіряє, що `llms.txt` містить ключові правила, звіряє закомічений артефакт
|
|
32
|
+
`examples/tickets` з потрібною Mado API surface та failure patterns, потім
|
|
33
|
+
збирає проєкт і запускає `test/tickets-smoke.test.mjs`.
|
|
34
|
+
|
|
30
35
|
Критерій успіху: код виглядає як Mado, а не як React/Vue, переодягнений у
|
|
31
36
|
template strings.
|