@madojs/mado 0.10.0 → 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.
Files changed (219) hide show
  1. package/AGENTS.md +24 -26
  2. package/CHANGELOG.md +98 -0
  3. package/README.md +18 -45
  4. package/TODO.md +52 -48
  5. package/dist/src/component.d.ts +2 -1
  6. package/dist/src/component.js +5 -2
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/each.d.ts +1 -1
  9. package/dist/src/each.js +1 -1
  10. package/dist/src/each.js.map +1 -1
  11. package/dist/src/html/template.js +10 -0
  12. package/dist/src/html/template.js.map +1 -1
  13. package/dist/src/index.d.ts +11 -6
  14. package/dist/src/index.js +5 -3
  15. package/dist/src/index.js.map +1 -1
  16. package/dist/src/lazy.d.ts +1 -1
  17. package/dist/src/lazy.js +1 -1
  18. package/dist/src/lazy.js.map +1 -1
  19. package/dist/src/page.d.ts +17 -21
  20. package/dist/src/page.js +7 -12
  21. package/dist/src/page.js.map +1 -1
  22. package/dist/src/router/manifest.d.ts +1 -1
  23. package/dist/src/router/manifest.js +21 -13
  24. package/dist/src/router/manifest.js.map +1 -1
  25. package/dist/src/router/match.d.ts +2 -2
  26. package/dist/src/router/match.js +3 -3
  27. package/dist/src/router/match.js.map +1 -1
  28. package/dist/src/router/navigation.js +1 -1
  29. package/dist/src/router/navigation.js.map +1 -1
  30. package/dist/src/vite/index.d.ts +10 -0
  31. package/dist/src/vite/index.js +33 -0
  32. package/dist/src/vite/index.js.map +1 -0
  33. package/docs/en/00-the-mado-way.md +25 -12
  34. package/docs/en/01-routing.md +90 -142
  35. package/docs/en/02-project-layout.md +59 -52
  36. package/docs/en/03-static-bake.md +5 -6
  37. package/docs/en/05-why-mado.md +6 -6
  38. package/docs/en/06-for-backenders.md +18 -22
  39. package/docs/en/08-llm-zero-history-test.md +9 -14
  40. package/docs/en/09-shadow-vs-light-dom.md +28 -36
  41. package/docs/en/10-app-architecture.md +158 -96
  42. package/docs/en/11-layouts.md +22 -24
  43. package/docs/en/12-auth-and-api.md +89 -182
  44. package/docs/en/13-deployment.md +25 -26
  45. package/docs/en/14-testing.md +4 -4
  46. package/docs/en/16-bake-cookbook.md +17 -10
  47. package/docs/en/18-api-freeze-map.md +6 -4
  48. package/docs/en/20-v1-stability.md +1 -1
  49. package/docs/fr/00-the-mado-way.md +55 -90
  50. package/docs/fr/01-routing.md +70 -152
  51. package/docs/fr/02-project-layout.md +74 -48
  52. package/docs/fr/03-static-bake.md +1 -1
  53. package/docs/fr/05-why-mado.md +6 -6
  54. package/docs/fr/06-for-backenders.md +7 -7
  55. package/docs/fr/08-llm-zero-history-test.md +21 -48
  56. package/docs/fr/09-shadow-vs-light-dom.md +43 -162
  57. package/docs/fr/10-app-architecture.md +110 -33
  58. package/docs/fr/11-layouts.md +24 -12
  59. package/docs/fr/12-auth-and-api.md +63 -22
  60. package/docs/fr/13-deployment.md +30 -12
  61. package/docs/fr/14-testing.md +1 -1
  62. package/docs/fr/16-bake-cookbook.md +57 -4
  63. package/docs/fr/18-api-freeze-map.md +1 -1
  64. package/docs/fr/20-v1-stability.md +1 -1
  65. package/docs/recipes/nginx/README.md +13 -0
  66. package/docs/ru/00-the-mado-way.md +53 -75
  67. package/docs/ru/01-routing.md +68 -143
  68. package/docs/ru/02-project-layout.md +75 -48
  69. package/docs/ru/03-static-bake.md +2 -2
  70. package/docs/ru/05-why-mado.md +6 -6
  71. package/docs/ru/06-for-backenders.md +7 -7
  72. package/docs/ru/08-llm-zero-history-test.md +9 -14
  73. package/docs/ru/09-shadow-vs-light-dom.md +43 -178
  74. package/docs/ru/10-app-architecture.md +115 -63
  75. package/docs/ru/11-layouts.md +24 -24
  76. package/docs/ru/12-auth-and-api.md +57 -35
  77. package/docs/ru/13-deployment.md +19 -13
  78. package/docs/ru/14-testing.md +1 -1
  79. package/docs/ru/16-bake-cookbook.md +48 -8
  80. package/docs/ru/18-api-freeze-map.md +5 -3
  81. package/docs/ru/20-v1-stability.md +1 -1
  82. package/docs/uk/00-the-mado-way.md +70 -44
  83. package/docs/uk/01-routing.md +41 -47
  84. package/docs/uk/02-project-layout.md +68 -41
  85. package/docs/uk/03-static-bake.md +1 -2
  86. package/docs/uk/06-for-backenders.md +3 -3
  87. package/docs/uk/08-llm-zero-history-test.md +22 -24
  88. package/docs/uk/09-shadow-vs-light-dom.md +37 -86
  89. package/docs/uk/10-app-architecture.md +72 -31
  90. package/docs/uk/11-layouts.md +25 -12
  91. package/docs/uk/12-auth-and-api.md +58 -22
  92. package/docs/uk/13-deployment.md +4 -3
  93. package/docs/uk/14-testing.md +1 -1
  94. package/docs/uk/18-api-freeze-map.md +1 -1
  95. package/docs/uk/20-v1-stability.md +1 -1
  96. package/llms.txt +14 -15
  97. package/package.json +18 -11
  98. package/scripts/_config.mjs +15 -161
  99. package/scripts/bake.mjs +71 -58
  100. package/scripts/cli/generate.mjs +348 -0
  101. package/scripts/cli/help.mjs +27 -0
  102. package/scripts/cli/index.mjs +79 -0
  103. package/scripts/cli/init.mjs +153 -0
  104. package/scripts/cli/release.mjs +152 -0
  105. package/scripts/cli/run.mjs +96 -0
  106. package/scripts/cli.mjs +2 -560
  107. package/scripts/package-smoke.mjs +4 -1
  108. package/scripts/preview.mjs +17 -61
  109. package/scripts/size-budget.mjs +5 -2
  110. package/scripts/vite.default.mjs +11 -0
  111. package/starters/default/.editorconfig +12 -0
  112. package/starters/default/README.md +74 -0
  113. package/starters/default/eslint.config.mjs +256 -0
  114. package/starters/default/index.html +13 -0
  115. package/starters/default/package.json +30 -0
  116. package/starters/default/public/favicon.svg +4 -0
  117. package/starters/default/src/app.routes.ts +39 -0
  118. package/starters/default/src/layouts/app-shell.layout.ts +35 -0
  119. package/starters/default/src/layouts/auth-shell.layout.ts +17 -0
  120. package/starters/default/src/main.ts +16 -0
  121. package/starters/default/src/modules/auth/_contracts/auth-api.types.ts +17 -0
  122. package/starters/default/src/modules/auth/auth.connector.ts +45 -0
  123. package/starters/default/src/modules/auth/auth.guard.ts +22 -0
  124. package/starters/default/src/modules/auth/auth.public.ts +9 -0
  125. package/starters/default/src/modules/auth/auth.routes.ts +8 -0
  126. package/starters/default/src/modules/auth/auth.service.ts +71 -0
  127. package/starters/default/src/modules/auth/auth.types.ts +15 -0
  128. package/starters/default/src/modules/auth/login.page.ts +62 -0
  129. package/starters/default/src/modules/billing/_contracts/stripe.types.ts +17 -0
  130. package/starters/default/src/modules/billing/api/stripe.connector.ts +71 -0
  131. package/starters/default/src/modules/billing/billing.public.ts +5 -0
  132. package/starters/default/src/modules/billing/billing.routes.ts +9 -0
  133. package/starters/default/src/modules/billing/billing.types.ts +15 -0
  134. package/starters/default/src/modules/billing/components/invoice-status-badge.component.ts +43 -0
  135. package/starters/default/src/modules/billing/data/invoices.resource.ts +35 -0
  136. package/starters/default/src/modules/billing/pages/invoice-detail.page.ts +70 -0
  137. package/starters/default/src/modules/billing/pages/invoices-list.page.ts +73 -0
  138. package/starters/default/src/modules/home/home.page.ts +34 -0
  139. package/starters/default/src/modules/home/not-found.page.ts +11 -0
  140. package/starters/default/src/shared/http/http-client.ts +86 -0
  141. package/starters/default/src/shared/http/http-error.ts +37 -0
  142. package/starters/default/src/shared/http/interceptors.ts +59 -0
  143. package/starters/default/src/shared/lib/format-date.ts +19 -0
  144. package/starters/default/src/shared/styles/content.css +70 -0
  145. package/starters/default/src/shared/styles/reset.css +32 -0
  146. package/starters/default/src/shared/styles/shell.css +57 -0
  147. package/starters/default/src/shared/styles/tokens.css +44 -0
  148. package/starters/default/src/shared/ui/x-button.component.ts +49 -0
  149. package/starters/default/src/shared/ui/x-spinner.component.ts +22 -0
  150. package/starters/default/src/styles.d.ts +1 -0
  151. package/starters/default/src/vite-env.d.ts +1 -0
  152. package/starters/default/tsconfig.json +24 -0
  153. package/starters/default/vite.config.ts +9 -0
  154. package/MADO_V1_PLAN.md +0 -179
  155. package/ROADMAP.md +0 -178
  156. package/dist/src/html.d.ts +0 -18
  157. package/dist/src/html.js +0 -17
  158. package/dist/src/html.js.map +0 -1
  159. package/dist/src/router.d.ts +0 -13
  160. package/dist/src/router.js +0 -13
  161. package/dist/src/router.js.map +0 -1
  162. package/scripts/bundle.mjs +0 -212
  163. package/scripts/llm-zero-history-smoke.mjs +0 -93
  164. package/scripts/new.mjs +0 -80
  165. package/scripts/showcase-regression.mjs +0 -392
  166. package/server/serve.mjs +0 -455
  167. package/starters/admin/README.md +0 -63
  168. package/starters/admin/index.html +0 -28
  169. package/starters/admin/mado.config.json +0 -22
  170. package/starters/admin/package.json +0 -24
  171. package/starters/admin/public/favicon.svg +0 -4
  172. package/starters/admin/src/components/x-button.ts +0 -82
  173. package/starters/admin/src/components/x-input.ts +0 -105
  174. package/starters/admin/src/layouts/app.ts +0 -101
  175. package/starters/admin/src/layouts/auth.ts +0 -41
  176. package/starters/admin/src/lib/api.ts +0 -184
  177. package/starters/admin/src/lib/auth.ts +0 -83
  178. package/starters/admin/src/main.ts +0 -15
  179. package/starters/admin/src/pages/admin/dashboard.ts +0 -48
  180. package/starters/admin/src/pages/admin/order-detail.ts +0 -80
  181. package/starters/admin/src/pages/admin/orders.ts +0 -117
  182. package/starters/admin/src/pages/home.ts +0 -34
  183. package/starters/admin/src/pages/login.ts +0 -70
  184. package/starters/admin/src/pages/not-found.ts +0 -12
  185. package/starters/admin/src/routes.ts +0 -40
  186. package/starters/admin/src/styles/global.ts +0 -86
  187. package/starters/admin/tsconfig.json +0 -15
  188. package/starters/crud/README.md +0 -33
  189. package/starters/crud/index.html +0 -28
  190. package/starters/crud/mado.config.json +0 -20
  191. package/starters/crud/package.json +0 -24
  192. package/starters/crud/src/components/app-shell.ts +0 -56
  193. package/starters/crud/src/components/ticket-detail.ts +0 -33
  194. package/starters/crud/src/components/ticket-form.ts +0 -69
  195. package/starters/crud/src/components/ticket-list.ts +0 -66
  196. package/starters/crud/src/lib/api.ts +0 -76
  197. package/starters/crud/src/main.ts +0 -9
  198. package/starters/crud/src/pages/home.ts +0 -34
  199. package/starters/crud/src/pages/not-found.ts +0 -12
  200. package/starters/crud/src/pages/ticket-detail.ts +0 -7
  201. package/starters/crud/src/pages/ticket-new.ts +0 -7
  202. package/starters/crud/src/pages/tickets.ts +0 -7
  203. package/starters/crud/src/routes.ts +0 -11
  204. package/starters/crud/src/styles/global.ts +0 -155
  205. package/starters/crud/tsconfig.json +0 -15
  206. package/starters/minimal/README.md +0 -21
  207. package/starters/minimal/index.html +0 -28
  208. package/starters/minimal/mado.config.json +0 -20
  209. package/starters/minimal/package.json +0 -24
  210. package/starters/minimal/src/components/app-counter.ts +0 -31
  211. package/starters/minimal/src/main.ts +0 -9
  212. package/starters/minimal/src/pages/home.ts +0 -35
  213. package/starters/minimal/src/pages/not-found.ts +0 -14
  214. package/starters/minimal/src/routes.ts +0 -8
  215. package/starters/minimal/src/styles/global.ts +0 -60
  216. package/starters/minimal/tsconfig.json +0 -15
  217. package/templates/page-detail.ts +0 -63
  218. package/templates/page-form.ts +0 -94
  219. package/templates/page-list.ts +0 -79
@@ -1,194 +1,119 @@
1
1
  # Routing
2
2
 
3
- > Один файл-манифест. Никаких сканеров папок. Никаких спецсимволов.
3
+ > Один app map. Никаких folder scanners. Никаких специальных path symbols.
4
4
 
5
- ## Зачем не file-based
5
+ Mado не выводит routes из файлов. Composition должна читаться в одном месте.
6
6
 
7
- В Next/SvelteKit/SolidStart роут возникает «магически» по имени файла. У этого есть плюсы (видно структуру URL по `pages/`), но в проде это означает:
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
- // src/routes.ts
22
- import { routes } from '@madojs/mado';
23
-
24
- export default routes({
25
- '/': () => import('./pages/home.js'),
26
- '/about': () => import('./pages/about.js'),
27
- '/users/:id': () => import('./pages/user-profile.js'),
28
- '/users/:id/edit':() => import('./pages/user-edit.js'),
29
- '*': () => import('./pages/not-found.js'),
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
- Хочешь увидеть все роуты? Открой `routes.ts`. Никаких сюрпризов.
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
- ### 1. Lazy import (рекомендовано)
41
+ Modules экспортируют plain route maps. Они не вызывают `layout()` и не решают,
42
+ какой shell их оборачивает.
40
43
 
41
44
  ```ts
42
- '/posts': () => import('./pages/posts.js'),
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
- - Браузер сам сделает chunk при бандлинге (esbuild --bundle --splitting).
46
- - Модуль загрузится только при заходе на роут.
47
- - Между навигациями результат кэшируется.
51
+ Prefix применяет `src/app.routes.ts`, когда module монтируется под
52
+ `"/billing"`.
48
53
 
49
- ### 2. Готовая Page (eager)
54
+ ## Layout Group
50
55
 
51
56
  ```ts
52
- import about from './pages/about.js';
53
-
54
- '/about': about,
57
+ "/admin": layout({
58
+ layout: () => import("./layouts/app-shell.layout.js"),
59
+ guard: requireAuth,
60
+ routes: adminRoutes,
61
+ }),
55
62
  ```
56
63
 
57
- Сразу в графе, без задержек. Используй для критичных страниц (home, login).
58
-
59
- ### 3. Nested с layout
64
+ Layout обычный `page({...})` file:
60
65
 
61
66
  ```ts
62
- import { routes, nested } from '@madojs/mado';
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="admin">
87
- <aside><nav>...</nav></aside>
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
- ## Параметры URL
81
+ ## Page Contract
113
82
 
114
83
  ```ts
115
- '/users/:id': () => import('./pages/user.js'),
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: ({ params }) => html`<h1>${params.id}</h1>`,
88
+ view: ({ params }) => html`<h1>${params.id}</h1>`,
122
89
  });
123
90
  ```
124
91
 
125
- Типы передаются в `page<Params>` — `tsc` проверит что вы не обратились к `params.foo`, которого нет в роуте.
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 route from './routes.js';
95
+ import appRoutes from "./app.routes.js";
144
96
 
145
- route.navigate('/posts');
146
- route.navigate('/posts?page=2');
147
- route.navigate('/posts', { replace: true });
97
+ appRoutes.navigate("/billing/invoices");
98
+ appRoutes.navigate("/billing/invoices?page=2");
99
+ appRoutes.navigate("/login", { replace: true });
148
100
  ```
149
101
 
150
- Клики по `<a href="/foo" data-link>` перехватываются глобально (без атрибута — браузер сделает full reload, как и положено для внешних ссылок).
151
-
152
- ## Query-параметры
102
+ ## Query Parameters
153
103
 
154
104
  ```ts
155
- import { queryParam } from '@madojs/mado';
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
- - Авто-сканирование `pages/`. **Один файл-манифест явный**.
169
- - ❌ Спецсимволы в путях (`[id]`, `(group)`, `_layout`). **Параметры — только `:name`, ничего больше**.
170
- - ❌ Server-side роутинг в этом же манифесте. Mado — клиентский фреймворк.
171
- - ❌ Auto-prefetch при наведении. Если очень нужно — можно сделать вручную: `link.addEventListener('mouseenter', loader)`. Но обычно лишнее.
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
- **Code splitting работает?**
194
- Да. При `esbuild --bundle --splitting --format=esm` каждый `() => import('./pages/x.js')` становится отдельным chunk'ом.
116
+ - Auto-scan of page folders.
117
+ - Filesystem syntax вроде `[id]`, `(group)`, `_layout`.
118
+ - Server routes в client manifest.
119
+ - Hidden layout discovery.
@@ -1,57 +1,84 @@
1
- # Project layout
1
+ # Project Layout
2
2
 
3
- Каждый new-проект на Mado имеет одинаковую структуру. Это **обязательное** соглашение.
3
+ Каждое Mado-приложение использует одну каноничную форму. Это не примерная
4
+ рекомендация, а соглашение, чтобы люди и AI-ассистенты одинаково понимали,
5
+ куда класть код.
4
6
 
5
- ```
7
+ ```txt
6
8
  my-app/
7
- ├── package.json # ровно 1 dep: typescript (esbuild опц.)
8
- ├── tsconfig.json # с paths "@madojs/mado" импорт без относительных путей
9
- ├── Dockerfile + nginx.conf # копируем из Mado/ при scaffold
10
- ├── .gitlab-ci.yml | .github/workflows/ci.yml
11
- ├── server/serve.mjs # dev-сервер из Mado, без deps
12
- ├── scripts/
13
- │ ├── bundle.mjs # esbuild прод-бандл
14
- │ └── new.mjs # скаффолд страницы
15
- ├── templates/ # шаблоны для new.mjs
16
- ├── docs/ # проектные доки (можно копировать наши гайды)
17
- ├── public/ # статика (favicon, манифесты)
9
+ ├── package.json # runtime dep: @madojs/mado
10
+ ├── tsconfig.json # strict TS, ES2022, Bundler resolution
11
+ ├── vite.config.ts # mado() from @madojs/mado/vite
12
+ ├── index.html # Vite entry + SPA shell
13
+ ├── public/ # статика: favicon, images, robots.txt
18
14
  └── src/
19
- ├── main.ts # точка входа: провайдеры + монтаж <x-app>
20
- ├── routes.ts # манифест роутов
21
- ├── pages/ # одна страница = один файл = `export default page({...})`
22
- ├── components/ # переиспользуемые компоненты (x-*)
23
- ├── layouts/ # layout-страницы (для nested)
24
- └── lib/
25
- ├── api.ts # все fetch-обёртки
26
- ├── contexts.ts # createContext(...)
27
- ├── theme.ts # темы
28
- └── ... # утилиты, типы, бизнес-правила
15
+ ├── main.ts # импорт CSS и mount router в #app
16
+ ├── app.routes.ts # app map: manifest + default routes(...)
17
+ ├── layouts/ # layouts app-зон, не доменные модули
18
+ ├── shared/ # ui, http, lib, styles
19
+ └── modules/ # bounded contexts
20
+ └── billing/
21
+ ├── billing.routes.ts
22
+ ├── billing.public.ts
23
+ ├── billing.types.ts
24
+ ├── pages/
25
+ ├── data/
26
+ ├── api/
27
+ └── _contracts/
29
28
  ```
30
29
 
30
+ ## Artifact States
31
+
32
+ | Folder | Что это | Кто пишет | Deploy? |
33
+ | --- | --- | --- | --- |
34
+ | `src/` | исходники TypeScript | ты | no |
35
+ | `public/` | статика, копируется как есть | ты | через `out/` |
36
+ | `out/` | deploy artifact: SPA shell + assets + baked HTML | `mado release` | yes |
37
+
38
+ `mado release` = `typecheck` + Vite build (`out/index.html`, `out/assets/`,
39
+ `public/*`) + `bake` прямо в route paths + `sitemap.xml` + precompression.
40
+
41
+ `index.html` лежит в корне, потому что для Vite это entry template. В
42
+ `public/` кладите только файлы, которые нужно скопировать как есть.
43
+
31
44
  ## Куда положить новый файл?
32
45
 
33
46
  | Что | Куда |
34
- |---|---|
35
- | Страница на новый URL | `src/pages/foo.ts` + добавить в `src/routes.ts` |
36
- | Переиспользуемая UI-штука | `src/components/foo-bar.ts` |
37
- | Обёртка над API | `src/lib/api.ts` (добавить метод) |
38
- | Глобальный контекст (тема, юзер, i18n) | `src/lib/<name>.ts` |
39
- | Чистая функция без UI | `src/lib/util/<name>.ts` |
40
-
41
- Если не понимаешь куда это сигнал что **архитектура страдает**. Спроси команду, **зафиксируй** ответ в `docs/`.
42
-
43
- ## Правила именования
44
-
45
- | Что | Стиль | Пример |
46
- |---|---|---|
47
- | Файл | kebab-case | `user-profile.ts` |
48
- | Тэг компонента | `x-` + kebab | `<x-user-profile>` |
49
- | Контекст | PascalCase + `Ctx` | `ThemeCtx`, `AuthCtx` |
50
- | Сигнал | camelCase | `userId`, `isLoggedIn` |
51
- | Page-функция (внутренний компонент) | `x-<route>-page` | `<x-posts-page>` |
52
-
53
- ## Что НЕ кладём в src/
54
-
55
- - Конфиги билдеров (webpack, rollup, vite) — у нас их нет.
56
- - ❌ `.env`-файлы — env читается из `process.env`/`import.meta.env` в `lib/config.ts`.
57
- - ❌ Тесты вперемешку с кодом — все в `test/`.
47
+ | --- | --- |
48
+ | Страница на новый URL | `src/modules/<module>/pages/<name>.page.ts` + module routes |
49
+ | Module route map | `src/modules/<module>/<module>.routes.ts` |
50
+ | App shell/layout | `src/layouts/<zone>.layout.ts` |
51
+ | Shared UI widget | `src/shared/ui/<x-name>.component.ts` |
52
+ | Module-only UI widget | `src/modules/<module>/components/<name>.component.ts` |
53
+ | API connector | `src/modules/<module>/api/<provider>.connector.ts` |
54
+ | Data resource/mutation | `src/modules/<module>/data/<name>.resource.ts` |
55
+ | Auth/session | `src/modules/auth/` |
56
+ | Public module surface | `src/modules/<module>/<module>.public.ts` |
57
+ | Pure function без UI | `src/shared/lib/<name>.ts` |
58
+ | Static image / favicon | `public/<file>` |
59
+ | App-zone shell CSS | `src/shared/styles/shell.css` |
60
+ | Page-level CSS | `src/shared/styles/content.css` |
61
+
62
+ ## Vite Config
63
+
64
+ ```ts
65
+ import { defineConfig } from "vite";
66
+ import { mado } from "@madojs/mado/vite";
67
+
68
+ export default defineConfig({
69
+ plugins: [mado()],
70
+ css: {
71
+ transformer: "lightningcss",
72
+ },
73
+ });
74
+ ```
75
+
76
+ Starter включает Vite Lightning CSS transformer. Mado не владеет prefixing,
77
+ CSS lowering или minification.
78
+
79
+ ## Что НЕ кладём в `src/`
80
+
81
+ - Лишние build-tool configs — настройка живет в `vite.config.ts`.
82
+ - `.env` files — читайте env в `src/shared/lib/config.ts` и импортируйте этот
83
+ модуль.
84
+ - Tests рядом с кодом — держите их в `test/`.
@@ -100,7 +100,7 @@ export default routes(manifest, { titleSuffix: " · MyShop" });
100
100
  ## Запуск
101
101
 
102
102
  ```bash
103
- npm install -D linkedom esbuild
103
+ npm install -D linkedom vite
104
104
  npm run build
105
105
  npm run bake
106
106
  ```
@@ -144,7 +144,7 @@ out/
144
144
  {"slug":"mado-mug","name":"Mado-кружка","price":12,"..."}
145
145
  </script>
146
146
 
147
- <script type="module" src="/dist/examples/main.js"></script>
147
+ <script type="module" src="/assets/index-HASH.js"></script>
148
148
  </body>
149
149
  ```
150
150
 
@@ -31,11 +31,11 @@ Mado — не «убийца» React/Vue/Svelte. Это узкоспециали
31
31
  | Размер | ~6 КБ | ~16 КБ |
32
32
  | Возраст / поддержка | ~10 лет, Google | 6 месяцев, один автор |
33
33
  | Реактивность | декораторы `@property` + ручной `requestUpdate` | сигналы (`signal`/`computed`/`effect`) из коробки |
34
- | Роутер | нет, нужно искать (`@lit-labs/router`, etc) | в комплекте: `routes()` + nested + prefetch + sync-cache |
34
+ | Роутер | нет, нужно искать (`@lit-labs/router`, etc) | в комплекте: `routes()` + layout groups + prefetch |
35
35
  | Data fetching | нет, нужно собирать | `resource()` + `mutation()` + glob-инвалидация |
36
36
  | Формы | нет | `useForm()` с HTML-like constraints |
37
37
  | SEO / static | сложно (`@lit-labs/ssr`) | `bake` (linkedom) + edge-prerender |
38
- | Билд | нужен esbuild/rollup/webpack | хватает `tsc` |
38
+ | Билд | нужны framework-specific build plugins | Vite transport + native runtime |
39
39
  | Стиль кода | классы + декораторы | функции + tagged templates |
40
40
  | Экосистема | реальная (Shoelace, Material Web, и т.д.) | нет |
41
41
  | Когда выбрать | пишете дизайн-систему / Web-Components-библиотеку для встраивания | пишете приложение целиком, хотите всё в одной коробке |
@@ -55,14 +55,14 @@ Mado — не «убийца» React/Vue/Svelte. Это узкоспециали
55
55
  | Реактивность | сигналы (тот же класс идей) | сигналы |
56
56
  | Шаблоны | JSX (компилируется в реактивные expressions) | tagged template `html\`\`` |
57
57
  | Компонентная модель | функции, виртуальные узлы Solid | Web Components |
58
- | Билд | Vite + babel-plugin-solid обязательны | только `tsc` |
58
+ | Билд | Vite + babel-plugin-solid обязательны | Vite для dev/build, без runtime-зависимостей |
59
59
  | Роутер | `@solidjs/router` | в комплекте |
60
60
  | Data | `createResource` | `resource()` |
61
61
  | SSR | поддерживается серьёзно (SolidStart) | намеренно нет |
62
62
  | Экосистема | растёт, ~50 пакетов | нет |
63
- | Когда выбрать | нужен топовый перф + JSX + готов настраивать билд | хотите запустить без билда / минимум инфраструктуры |
63
+ | Когда выбрать | нужен топовый перф + JSX + готов настраивать билд | нужен browser-native runtime с простым tooling |
64
64
 
65
- **Честный pitch:** *«Solid технически быстрее и зрелее. Но Solid требует Vite + babel-плагин. Mado не требует ничего, кроме `tsc` это «открой VS Code, F5 и работай». Если эта разница не критична — берите Solid.»*
65
+ **Честный pitch:** *«Solid технически быстрее и зрелее. Mado проще концептуально: browser-native runtime, Web Components, tagged templates, а Vite забирает на себя скучный dev/build. Если нужны JSX и большая экосистема — берите Solid.»*
66
66
 
67
67
  ---
68
68
 
@@ -153,7 +153,7 @@ Mado — не «убийца» React/Vue/Svelte. Это узкоспециали
153
153
 
154
154
  Не размер, не перф, не сигналы — у всего этого есть конкуренты лучше.
155
155
 
156
- > **«Открой исходник и прочитай его за вечер. ~3500 строк, 12 модулей. Если что-то сломалось — ты не идёшь в issue на 3000 комментариев. Ты идёшь в `src/router.ts` и читаешь 500 строк.»**
156
+ > **«Открой исходник и прочитай его за вечер. ~3500 строк, маленькие модули. Если что-то сломалось — ты не идёшь в issue на 3000 комментариев. Ты идёшь в `src/router/` и читаешь код.»**
157
157
 
158
158
  Это называется **ownership** — ты владеешь кодом, а не зависишь от чужого.
159
159
 
@@ -13,7 +13,7 @@ Mado устроен **как HTTP-сервер**. Серьёзно:
13
13
  |---|---|
14
14
  | HTTP-роутер (chi, axum, mux) | `routes()` — манифест путей |
15
15
  | Handler `func(req, resp)` | `page({ view: (ctx) => html\`...\` })` |
16
- | Middleware | `layout` в `nested()` (оборачивает handler) |
16
+ | Middleware | route group через `layout()` (оборачивает handler) |
17
17
  | Шаблонизатор (Jinja, Handlebars) | `html\`\`` tagged template |
18
18
  | HTTP-клиент с кешем | `resource()` — fetch + cache + invalidation |
19
19
  | Reactive variable / atom | `signal()` — реактивный геттер |
@@ -350,17 +350,17 @@ export default page({
350
350
  ```
351
351
 
352
352
  ```ts
353
- // src/routes.ts
354
- import { routes, nested } from "@madojs/mado";
353
+ // src/app.routes.ts
354
+ import { layout, routes } from "@madojs/mado";
355
355
 
356
356
  export default routes({
357
357
  "/login": () => import("./pages/login.js"),
358
358
 
359
- "/app/*": nested({
359
+ "/app": layout({
360
360
  layout: () => import("./layouts/auth-layout.js"),
361
361
  routes: {
362
- "dashboard": () => import("./pages/dashboard.js"),
363
- "users": () => import("./pages/users.js"),
362
+ "/dashboard": () => import("./pages/dashboard.js"),
363
+ "/users": () => import("./pages/users.js"),
364
364
  },
365
365
  }),
366
366
  });
@@ -423,6 +423,6 @@ export const api = new ApiClient("/api");
423
423
  - **[`01-routing.md`](./01-routing.md)** — детально про роутер.
424
424
  - **[`02-project-layout.md`](./02-project-layout.md)** — структура проекта.
425
425
  - **[`03-static-bake.md`](./03-static-bake.md)** — SEO без SSR.
426
- - **[`examples/showcase/`](../../examples/showcase/)**полный пример (landing + admin).
426
+ - **Внешний workspace `madojs-examples`**полные демо (landing + admin).
427
427
 
428
428
  Если что-то непонятно — open issue, или просто открой исходник. Это правда читается за вечер.
@@ -13,15 +13,15 @@
13
13
  - `AGENTS.md`
14
14
  - `README.md`
15
15
  - `docs/en/07-llm-pitfalls.md`
16
- - `examples/basic/README.md` если нужен минимальный обзор API
17
- - конкретные файлы из `examples/showcase/**` только если агент сам попросит паттерн более крупного приложения
16
+ - файлы из внешнего workspace `madojs-examples` только если агент сам попросит
17
+ паттерн более крупного приложения
18
18
 
19
19
  Агент может искать целевые API в `src/` когда заблокирован, но не должен
20
20
  загружать весь фреймворк в контекст.
21
21
 
22
22
  ## Задание
23
23
 
24
- Построить `examples/tickets`: маленький ticket-admin SPA для соло/бекенд-разработчика.
24
+ Построить маленький ticket-admin SPA для соло/бекенд-разработчика.
25
25
 
26
26
  Требуемое поведение:
27
27
 
@@ -48,15 +48,10 @@
48
48
 
49
49
  ## Заметки по результатам
50
50
 
51
- Текущая реализация `examples/tickets` не потребовала новых публичных API или
52
- runtime-зависимостей.
51
+ Историческая реализация tickets живет во внешнем workspace `madojs-examples`.
52
+ Core-репозиторий больше не поставляет этот артефакт и отдельную smoke-команду;
53
+ используйте этот документ как ручной сценарий оценки при обновлении LLM-guidance.
53
54
 
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
-
59
- Основная болевая точка в документации остается lifecycle: старые примеры могут
60
- создать впечатление, что создание `resource()` прямо в `page.view()` допустимо.
61
- Пример tickets использует page-level wrapper-компоненты вместо этого, поэтому
62
- ресурсы регистрируются внутри component setup и очищаются вместе с компонентом.
55
+ Основная болевая точка в документации остается lifecycle: примеры не должны
56
+ создавать впечатление, что long-lived `resource()` можно случайно держать на
57
+ module scope или в route-коде без cleanup.