@love-sqjm/magic 2026.4.15

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 (56) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +93 -0
  3. package/app.js +51 -0
  4. package/doc/api/examples.md +563 -0
  5. package/doc/api/index.md +563 -0
  6. package/doc/architecture.md +322 -0
  7. package/doc/config-reference.md +646 -0
  8. package/doc/data-model.md +622 -0
  9. package/doc/development-guide.md +582 -0
  10. package/doc/magic-file/index.md +610 -0
  11. package/doc/user-guide/index.md +485 -0
  12. package/doc/workflow.md +548 -0
  13. package/index.js +157 -0
  14. package/magic.bat +2 -0
  15. package/magic.ps1 +5 -0
  16. package/package.json +44 -0
  17. package/script/build-project.js +16 -0
  18. package/script/config.js +23 -0
  19. package/script/create-project.js +73 -0
  20. package/script/global/printf.js +13 -0
  21. package/script/global/project-build-config.js +161 -0
  22. package/script/global/support-platform.js +5 -0
  23. package/script/module/compiler/global.js +43 -0
  24. package/script/module/compiler/id-generate.js +18 -0
  25. package/script/module/compiler/index-dom.js +78 -0
  26. package/script/module/compiler/macro-replace.js +22 -0
  27. package/script/module/compiler/macro.js +6 -0
  28. package/script/module/compiler/start.js +10 -0
  29. package/script/module/compiler/step/1.js +253 -0
  30. package/script/module/compiler/step/2.js +79 -0
  31. package/script/module/compiler/step/3.js +37 -0
  32. package/script/module/compiler/step/4.js +20 -0
  33. package/script/module/compiler/step/5.js +634 -0
  34. package/script/module/compiler/step/6.js +304 -0
  35. package/script/module/compiler/step/end.js +124 -0
  36. package/script/run-project.js +249 -0
  37. package/script/util/bun-fs.js +40 -0
  38. package/script/util/copy-dir.js +21 -0
  39. package/script/util/create-simple-dom-element.js +23 -0
  40. package/script/util/file-util.js +95 -0
  41. package/script/util/filtration-file.js +20 -0
  42. package/script/util/get-dir-all-file.js +28 -0
  43. package/script/util/get-first-object-key.js +9 -0
  44. package/script/util/is-empty-object.js +8 -0
  45. package/script/util/is-string-over-size.js +4 -0
  46. package/script/util/is.js +18 -0
  47. package/script/util/logging.js +142 -0
  48. package/script/util/task.js +16 -0
  49. package/script/util/traversal.js +28 -0
  50. package/template/platform-config/node-webkit +23 -0
  51. package/template/platform-config/web +1 -0
  52. package/template/project-base/app.xml +5 -0
  53. package/template/project-base/build.module.toml +37 -0
  54. package/template/project-base/build.toml +43 -0
  55. package/template/runtime/runtime.css +3 -0
  56. package/template/runtime/runtime.js +895 -0
@@ -0,0 +1,548 @@
1
+ # Magic 业务流程文档
2
+
3
+ ## 概述
4
+
5
+ 本文档描述 Magic 框架的核心业务流程,包括项目创建、编译构建、开发运行等关键环节。
6
+
7
+ ---
8
+
9
+ ## 1. 项目创建流程
10
+
11
+ ### 1.1 流程图
12
+
13
+ ```
14
+ 用户执行
15
+
16
+
17
+ ┌──────────────────────────────────────────────────────────────┐
18
+ │ magic init [name] --web │
19
+ └──────────────────────────┬───────────────────────────────────┘
20
+
21
+
22
+ ┌──────────────────────────────────────────────────────────────┐
23
+ │ createProject(name, "web") │
24
+ │ ┌────────────────────────────────────────────────────────┐ │
25
+ │ │ 1. 获取平台配置模板 (template/platform-config/web) │ │
26
+ │ │ 2. 读取项目基础模板 (template/project-base/build.toml) │ │
27
+ │ │ 3. 替换模板变量 ($name, $target, $config) │ │
28
+ │ │ 4. 创建目录结构 (name/app/) │ │
29
+ │ │ 5. 写入 build.toml 和 app/app.xml │ │
30
+ │ │ 6. 创建 app/index.m 入口文件 │ │
31
+ │ └────────────────────────────────────────────────────────┘ │
32
+ └──────────────────────────┬───────────────────────────────────┘
33
+
34
+
35
+ 项目创建完成
36
+ ```
37
+
38
+ ### 1.2 详细步骤
39
+
40
+ | 步骤 | 函数 | 说明 |
41
+ |------|------|------|
42
+ | 1 | `createProject(name, platform)` | 入口函数 |
43
+ | 2 | `app.templateDir.platformConfig.get(platform)` | 获取平台配置 |
44
+ | 3 | `app.templateDir.projectBase.get("build.toml")` | 获取项目模板 |
45
+ | 4 | 替换 `$name`, `$target`, `$config` | 填充配置 |
46
+ | 5 | `fs.mkdirSync()` | 创建目录 |
47
+ | 6 | `fs.writeFileSync()` | 写入配置文件 |
48
+ | 7 | 创建 `app/index.m` | 创建入口组件文件 |
49
+
50
+ ---
51
+
52
+ ## 2. 项目构建流程
53
+
54
+ ### 2.1 完整编译流水线
55
+
56
+ ```
57
+ magic build
58
+
59
+
60
+ ┌──────────────────────────────────────────────────────────────┐
61
+ │ BuildProject() │
62
+ └──────────────────────────┬───────────────────────────────────┘
63
+
64
+
65
+ ┌──────────────────────────────────────────────────────────────┐
66
+ │ Step 1: 配置解析 │
67
+ │ ┌────────────────────────────────────────────────────────┐ │
68
+ │ │ examine_BuildConfig() │ │
69
+ │ │ 1. 加载 build.toml │ │
70
+ │ │ 2. 校验配置项类型和范围 │ │
71
+ │ │ 3. 解析 app.xml │ │
72
+ │ │ 4. 解析 import 标签 │ │
73
+ │ └────────────────────────────────────────────────────────┘ │
74
+ └──────────────────────────┬───────────────────────────────────┘
75
+
76
+
77
+ ┌──────────────────────────────────────────────────────────────┐
78
+ │ Step 2: 文件扫描 │
79
+ │ ┌────────────────────────────────────────────────────────┐ │
80
+ │ │ _2(build_config, app_config) │ │
81
+ │ │ 1. 添加默认排除项 (app.xml, magic/) │ │
82
+ │ │ 2. filtrationFile() 扫描所有源文件 │ │
83
+ │ │ 3. 按扩展名分组创建 source 对象 │ │
84
+ │ └────────────────────────────────────────────────────────┘ │
85
+ └──────────────────────────┬───────────────────────────────────┘
86
+
87
+
88
+ ┌──────────────────────────────────────────────────────────────┐
89
+ │ Step 3: 目录初始化 │
90
+ │ ┌────────────────────────────────────────────────────────┐ │
91
+ │ │ _3() │ │
92
+ │ │ 1. fs.rmSync() 清空输出目录 │ │
93
+ │ │ 2. fs.mkdirSync() 创建输出目录 │ │
94
+ │ │ 3. 复制 runtime.js 和 runtime.css │ │
95
+ │ └────────────────────────────────────────────────────────┘ │
96
+ └──────────────────────────┬───────────────────────────────────┘
97
+
98
+
99
+ ┌──────────────────────────────────────────────────────────────┐
100
+ │ Step 4: 文件分类 │
101
+ │ ┌────────────────────────────────────────────────────────┘ │
102
+ │ │ _4() │ │
103
+ │ │ 1. 遍历所有源文件 │ │
104
+ │ │ 2. .m 文件收集到数组待处理 │ │
105
+ │ │ 3. 其他文件直接复制到输出目录 │ │
106
+ │ └────────────────────────────────────────────────────────┘ │
107
+ └──────────────────────────┬───────────────────────────────────┘
108
+
109
+
110
+ ┌──────────────────────────────────────────────────────────────┐
111
+ │ Step 5: 核心编译 │
112
+ │ ┌────────────────────────────────────────────────────────┐ │
113
+ │ │ _5(m source[]) │ │
114
+ │ │ 1. 解析 import 标签 │ │
115
+ │ │ 2. 解析 template DOM 树 │ │
116
+ │ │ 3. 分类处理 script 标签 │ │
117
+ │ │ 4. 处理 css 标签和作用域 │ │
118
+ │ │ 5. 处理 expose-event │ │
119
+ │ │ 6. Babel AST 宏替换 │ │
120
+ │ │ 7. 生成 mData 对象数组 │ │
121
+ │ └────────────────────────────────────────────────────────┘ │
122
+ └──────────────────────────┬───────────────────────────────────┘
123
+
124
+
125
+ ┌──────────────────────────────────────────────────────────────┐
126
+ │ Step 6: 代码生成 │
127
+ │ ┌────────────────────────────────────────────────────────┐ │
128
+ │ │ _6(mDatas, CSS_VAR) │ │
129
+ │ │ 1. 处理模块导入 │ │
130
+ │ │ 2. 创建 M*.js 和 M*.css 文件 │ │
131
+ │ │ 3. 更新 index_dom │ │
132
+ │ │ 4. debug/release 模式分别处理 │ │
133
+ │ └────────────────────────────────────────────────────────┘ │
134
+ └──────────────────────────┬───────────────────────────────────┘
135
+
136
+
137
+ ┌──────────────────────────────────────────────────────────────┐
138
+ │ End: 压缩输出 │
139
+ │ ┌────────────────────────────────────────────────────────┐ │
140
+ │ │ _end(paths) │ │
141
+ │ │ 1. 生成 index.html │ │
142
+ │ │ 2. HTML/JS/CSS 压缩 │ │
143
+ │ │ 3. PostCSS Autoprefixer 处理 │ │
144
+ │ │ 4. 输出到 build/ 目录 │ │
145
+ │ └────────────────────────────────────────────────────────┘ │
146
+ └──────────────────────────┬───────────────────────────────────┘
147
+
148
+
149
+ 构建完成
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 3. Step 5 核心编译详解
155
+
156
+ ### 3.1 .m 文件解析流程
157
+
158
+ ```
159
+ .m 文件内容
160
+
161
+
162
+ ┌──────────────────────────────────────────────────────────────┐
163
+ │ parse() 解析 DOM │
164
+ └──────────────────────────┬───────────────────────────────────┘
165
+
166
+
167
+ ┌──────────────────────────────────────────────────────────────┐
168
+ │ 各标签并行处理 │
169
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
170
+ │ │ <import> │ │<template>│ │ <script> │ │ <css> │ │
171
+ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
172
+ └───────┼─────────────┼─────────────┼─────────────┼────────────┘
173
+ │ │ │ │
174
+ ▼ ▼ ▼ ▼
175
+ ┌──────────────────────────────────────────────────────────────┐
176
+ │ Babel AST 处理 │
177
+ │ ┌────────────────────────────────────────────────────────┐ │
178
+ │ │ 1. magic_define_include 宏替换 │ │
179
+ │ │ 2. magic_define_ui_data 转换 │ │
180
+ │ │ 3. magic_dynamic_value_bind 标记 │ │
181
+ │ │ 4. 提取事件/接口/监听函数 │ │
182
+ │ └────────────────────────────────────────────────────────┘ │
183
+ └──────────────────────────┬───────────────────────────────────┘
184
+
185
+
186
+ mData 对象
187
+ ```
188
+
189
+ ### 3.2 脚本分类处理
190
+
191
+ | code 属性 | 处理方式 | 存储位置 |
192
+ |-----------|----------|----------|
193
+ | 无 / `default` | 直接拼接 | `data.script` |
194
+ | `before` | 拼接后处理宏 | `data.before` |
195
+ | `global` | 拼接后处理宏 | `data.global` |
196
+ | `event` | 提取函数名,生成事件代码 | `data.event` |
197
+ | `listen` | 提取函数名,生成监听代码 | `data.listen` |
198
+ | `interface` | 提取函数名,生成接口代码 | `data.interface` |
199
+
200
+ ### 3.3 CSS 处理流程
201
+
202
+ ```
203
+ <css scope="#id:button" default-theme>
204
+ & {
205
+ background-color: #c6c6c6;
206
+ }
207
+ </css>
208
+
209
+
210
+ ┌──────────────────────────────────────────────────────────────┐
211
+ │ 1. scope 属性解析 │
212
+ │ → 确定作用域选择器 │
213
+ └──────────────────────────┬───────────────────────────────────┘
214
+
215
+
216
+ ┌──────────────────────────────────────────────────────────────┐
217
+ │ 2. 编译作用域选择器 │
218
+ │ → 生成唯一类名 .m-css-scope-abc123 │
219
+ └──────────────────────────┬───────────────────────────────────┘
220
+
221
+
222
+ ┌──────────────────────────────────────────────────────────────┐
223
+ │ 3. default-theme 处理 (可选) │
224
+ │ → 将 CSS 值转换为 CSS 变量 │
225
+ │ → 添加到 CSS_VAR 字符串 │
226
+ └──────────────────────────┬───────────────────────────────────┘
227
+
228
+
229
+ ┌──────────────────────────────────────────────────────────────┐
230
+ │ 4. 输出 │
231
+ │ CSS: .m-css-scope-abc123 { background-color: ... } │
232
+ │ VAR: --button-m-css-scope-abc123-background-color: ... │
233
+ └──────────────────────────────────────────────────────────────┘
234
+ ```
235
+
236
+ ---
237
+
238
+ ## 4. 项目运行流程
239
+
240
+ ### 4.1 Web 平台运行
241
+
242
+ ```
243
+ magic run
244
+
245
+
246
+ ┌──────────────────────────────────────────────────────────────┐
247
+ │ RunProject() │
248
+ └──────────────────────────┬───────────────────────────────────┘
249
+
250
+
251
+ ┌──────────────────────────────────────────────────────────────┐
252
+ │ 1. 加载 build.toml │
253
+ │ 2. examine_BuildConfig() 校验配置 │
254
+ │ 3. 根据 platform.target 分发 │
255
+ └──────────────────────────┬───────────────────────────────────┘
256
+
257
+
258
+ ┌──────────────────────────────────────────────────────────────┐
259
+ │ platform["web"](config) │
260
+ │ ┌────────────────────────────────────────────────────────┐ │
261
+ │ │ 判断运行模式: │ │
262
+ │ │ • browser: 启动浏览器 │ │
263
+ │ │ • server: 启动 HTTP 服务器 + WebSocket │ │
264
+ │ └────────────────────────────────────────────────────────┘ │
265
+ └──────────────────────────┬───────────────────────────────────┘
266
+
267
+
268
+ ┌──────────────────────────────────────────────────────────────┐
269
+ │ HTTP 服务器 + WebSocket 热更新 │
270
+ │ ┌────────────────────────────────────────────────────────┐ │
271
+ │ │ 1. http.createServer() 创建 HTTP 服务器 │ │
272
+ │ │ 2. ws.Server() 创建 WebSocket 服务器 │ │
273
+ │ │ 3. 处理静态文件请求 │ │
274
+ │ │ 4. 广播刷新消息 │ │
275
+ │ │ 5. 客户端自动刷新页面 │ │
276
+ │ └────────────────────────────────────────────────────────┘ │
277
+ └──────────────────────────────────────────────────────────────┘
278
+ ```
279
+
280
+ ### 4.2 热更新机制
281
+
282
+ ```
283
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
284
+ │ 客户端 │ │ 服务器 │ │ 文件系统 │
285
+ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
286
+ │ │ │
287
+ │ WebSocket 连接 │ │
288
+ │───────────────────────>│ │
289
+ │ │ │
290
+ │ │ 每 500ms 轮询检查 │
291
+ │ │───────────────────────>│
292
+ │ │ │
293
+ │ │ 文件变化检测 │
294
+ │ │<───────────────────────│
295
+ │ │ │
296
+ │ 发送刷新指令 │ │
297
+ │<───────────────────────│ │
298
+ │ │ │
299
+ │ location.reload() │ │
300
+ │ 页面刷新 │ │
301
+ │ │ │
302
+ ```
303
+
304
+ ---
305
+
306
+ ## 5. 模块导入流程
307
+
308
+ ### 5.1 导入解析
309
+
310
+ ```
311
+ <import root="magic-ui/ui">
312
+ <module:control>
313
+ <list-view/>
314
+ </module:control>
315
+ </import>
316
+
317
+
318
+ ┌──────────────────────────────────────────────────────────────┐
319
+ │ 解析 namespace │
320
+ │ "control" → namespace: "control" │
321
+ └──────────────────────────┬───────────────────────────────────┘
322
+
323
+
324
+ ┌──────────────────────────────────────────────────────────────┐
325
+ │ 解析模块路径 │
326
+ │ module:list-view → magic-ui/ui/control/list-view │
327
+ └──────────────────────────┬───────────────────────────────────┘
328
+
329
+
330
+ ┌──────────────────────────────────────────────────────────────┐
331
+ │ 生成导入映射 │
332
+ │ { │
333
+ │ "control": { │
334
+ │ "list-view": "magic-ui/ui/control/list-view" │
335
+ │ } │
336
+ │ } │
337
+ └──────────────────────────────────────────────────────────────┘
338
+ ```
339
+
340
+ ### 5.2 运行时加载
341
+
342
+ ```
343
+ magic.importM("list-view")
344
+
345
+
346
+ ┌──────────────────────────────────────────────────────────────┐
347
+ │ 1. 名称标准化 │
348
+ │ name = "list-view".replace(/[^a-zA-Z]/g, '').toLowerCase()│
349
+ │ → "listview" │
350
+ └──────────────────────────┬───────────────────────────────────┘
351
+
352
+
353
+ ┌──────────────────────────────────────────────────────────────┐
354
+ │ 2. 查找模块构造函数 │
355
+ │ window["__MAGIC__"]["M"]["listview"] │
356
+ └──────────────────────────┬───────────────────────────────────┘
357
+
358
+
359
+ ┌──────────────────────────────────────────────────────────────┐
360
+ │ 3. 实例化 │
361
+ │ new window["__MAGIC__"]["M"]["listview"](args, listen) │
362
+ └──────────────────────────┬───────────────────────────────────┘
363
+
364
+
365
+ 返回模块元素
366
+ ```
367
+
368
+ ---
369
+
370
+ ## 6. 事件系统流程
371
+
372
+ ### 6.1 事件定义与触发
373
+
374
+ ```
375
+ 【定义端】
376
+ <script code="event">
377
+ clickHandler = (event) => {
378
+ emit_event("click", { data: "test" });
379
+ }
380
+ </script>
381
+
382
+
383
+ 编译生成
384
+
385
+
386
+ this.__magic_event = {
387
+ clickHandler: function(event) {...}
388
+ };
389
+ this.__magic_template.bind_event = () => {
390
+ magic.dom.event(element, "click", this, "clickHandler");
391
+ };
392
+
393
+
394
+ emit_event = magic.emit.event(_listen);
395
+
396
+
397
+ emit_event("click", { data: "test" });
398
+ ```
399
+
400
+ ### 6.2 事件监听流程
401
+
402
+ ```
403
+ 【模板定义】
404
+ <child-component #listen:select="onSelect"/>
405
+
406
+ 【编译后】
407
+ magic.importM("child-component", {}, {
408
+ select: (data) => this.__magic_listen_onSelect(data)
409
+ });
410
+
411
+ 【监听函数】
412
+ <script code="listen">
413
+ onSelect = (data) => {
414
+ console.log("Selected:", data);
415
+ }
416
+ </script>
417
+
418
+ 【触发流程】
419
+ 子模块 emit_event("select", { value: "A" })
420
+
421
+
422
+ 调用 _listen["select"]({ value: "A" })
423
+
424
+
425
+ 执行 onSelect({ value: "A" })
426
+ ```
427
+
428
+ ---
429
+
430
+ ## 7. 响应式数据流
431
+
432
+ ### 7.1 UiData 创建
433
+
434
+ ```
435
+ const UiData = magic_define_ui_data({
436
+ text: "Hello",
437
+ count: 0
438
+ });
439
+
440
+
441
+ ┌──────────────────────────────────────────────────────────────┐
442
+ │ 编译时转换 │
443
+ └──────────────────────────┬───────────────────────────────────┘
444
+
445
+
446
+ const UiData = magic.createUiData({
447
+ text: "Hello",
448
+ count: 0
449
+ }, _args);
450
+
451
+
452
+ ┌──────────────────────────────────────────────────────────────┐
453
+ │ createUiData() 返回深拷贝代理 │
454
+ │ • 支持类型转换 │
455
+ │ • 支持嵌套对象 │
456
+ │ • 返回响应式代理 │
457
+ └──────────────────────────────────────────────────────────────┘
458
+ ```
459
+
460
+ ### 7.2 动态值绑定
461
+
462
+ ```
463
+ magic_dynamic_value_bind($textElement)
464
+
465
+
466
+ ┌──────────────────────────────────────────────────────────────┐
467
+ │ 编译时转换 │
468
+ └──────────────────────────┬───────────────────────────────────┘
469
+
470
+
471
+ magic.DynamicValueBind($textElement, UiData);
472
+
473
+
474
+ ┌──────────────────────────────────────────────────────────────┐
475
+ │ 运行时处理 │
476
+ │ 1. replaceMagicComments() 替换 ${} 为注释节点 │
477
+ │ 2. UiData.__DynamicValueBind() 绑定 │
478
+ │ 3. 当 UiData 属性变化时自动更新文本节点 │
479
+ └──────────────────────────────────────────────────────────────┘
480
+ ```
481
+
482
+ ---
483
+
484
+ ## 8. 编译错误处理流程
485
+
486
+ ### 8.1 配置错误
487
+
488
+ ```
489
+ examine_BuildConfig() 校验失败
490
+
491
+
492
+ ┌──────────────────────────────────────────────────────────────┐
493
+ │ ProjectBuildConfigContrast() │
494
+ │ 发现类型不匹配或范围错误 │
495
+ └──────────────────────────┬───────────────────────────────────┘
496
+
497
+
498
+ 抛出错误: "目标 [key = value] 类型应该为 type"
499
+ ```
500
+
501
+ ### 8.2 编译时错误
502
+
503
+ ```
504
+ step/5.js Babel 解析失败
505
+
506
+
507
+ ┌──────────────────────────────────────────────────────────────┐
508
+ │ 抛出错误信息 │
509
+ │ code: <错误码> │
510
+ │ 错误原因: <reasonCode> │
511
+ │ 行 <line>, 列 <column> │
512
+ └──────────────────────────────────────────────────────────────┘
513
+ ```
514
+
515
+ ---
516
+
517
+ ## 9. 构建产物结构
518
+
519
+ ### 9.1 Debug 模式
520
+
521
+ ```
522
+ build/
523
+ ├── index.html # 主页面
524
+ ├── magic/
525
+ │ ├── runtime.js # 运行时
526
+ │ ├── runtime.css # 运行时样式
527
+ │ ├── default-theme-var.css # 主题变量
528
+ │ ├── 模块1.js # 每个模块独立文件
529
+ │ ├── 模块1.css
530
+ │ ├── 模块2.js
531
+ │ └── 模块2.css
532
+ ├── 其他资源文件...
533
+ ```
534
+
535
+ ### 9.2 Release 模式
536
+
537
+ ```
538
+ build/
539
+ ├── index.html # 压缩后的主页面
540
+ ├── magic/
541
+ │ ├── runtime.js # 可能压缩
542
+ │ ├── runtime.css
543
+ │ ├── default-theme-var.css
544
+ │ ├── m.js # 合并的 JS(可能分块)
545
+ │ └── m-1.js # 超过 1MB 的分块
546
+ │ └── m-2.css # CSS 分块
547
+ ├── 其他资源文件...
548
+ ```