@vitarx/plugin-vite 1.0.4 → 1.0.6

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 (44) hide show
  1. package/dist/constants/index.d.ts +0 -9
  2. package/dist/constants/index.js +0 -9
  3. package/dist/hmr-client/index.d.ts +27 -1
  4. package/dist/hmr-client/index.js +108 -12
  5. package/dist/hmr-client/update.d.ts +11 -2
  6. package/dist/hmr-client/update.js +25 -59
  7. package/dist/hmr-client/weak-refs.d.ts +37 -0
  8. package/dist/hmr-client/weak-refs.js +41 -0
  9. package/dist/passes/directives/processDirectives.d.ts +1 -1
  10. package/dist/passes/directives/processDirectives.js +15 -10
  11. package/dist/passes/hmr/index.d.ts +1 -1
  12. package/dist/passes/hmr/index.js +1 -1
  13. package/dist/passes/hmr/inject-state.d.ts +16 -10
  14. package/dist/passes/hmr/inject-state.js +141 -135
  15. package/dist/passes/hmr/inject.d.ts +10 -0
  16. package/dist/passes/hmr/inject.js +47 -10
  17. package/dist/passes/imports/collectRefVariables.d.ts +1 -0
  18. package/dist/passes/imports/collectRefVariables.js +52 -19
  19. package/dist/passes/index.d.ts +1 -1
  20. package/dist/passes/index.js +1 -1
  21. package/dist/passes/jsx/processJSXFragment.js +18 -1
  22. package/dist/passes/props/attribute.d.ts +3 -0
  23. package/dist/passes/props/attribute.js +13 -3
  24. package/dist/transform.js +16 -5
  25. package/dist/types.d.ts +1 -1
  26. package/dist/utils/branch-factory.js +26 -6
  27. package/dist/utils/component-collect.d.ts +7 -0
  28. package/dist/utils/component-collect.js +12 -236
  29. package/dist/utils/default-export.d.ts +38 -0
  30. package/dist/utils/default-export.js +119 -0
  31. package/dist/utils/forward-export.d.ts +28 -0
  32. package/dist/utils/forward-export.js +76 -0
  33. package/dist/utils/function-extract.d.ts +45 -0
  34. package/dist/utils/function-extract.js +98 -0
  35. package/dist/utils/generate.d.ts +7 -0
  36. package/dist/utils/generate.js +20 -0
  37. package/dist/utils/index.d.ts +3 -2
  38. package/dist/utils/index.js +4 -2
  39. package/dist/utils/jsx-helpers.d.ts +1 -4
  40. package/dist/utils/jsx-helpers.js +2 -15
  41. package/dist/utils/vif-helpers.js +6 -3
  42. package/package.json +5 -4
  43. package/dist/hmr-client/utils.d.ts +0 -23
  44. package/dist/hmr-client/utils.js +0 -137
@@ -1,12 +1,3 @@
1
- /**
2
- * Vitarx 运行时 API 名称
3
- * 这些 API 需要从 vitarx 包导入
4
- */
5
- /**
6
- * UI 相关的 API 名称列表
7
- * 这些 API 用于创建视图,在 HMR 时需要识别
8
- */
9
- export declare const UI_API_NAMES: readonly ["createView", "branch", "dynamic", "expr", "accessor", "withDirectives"];
10
1
  /**
11
2
  * Ref 相关 API 名称
12
3
  * 用于识别 ref 变量
@@ -1,12 +1,3 @@
1
- /**
2
- * Vitarx 运行时 API 名称
3
- * 这些 API 需要从 vitarx 包导入
4
- */
5
- /**
6
- * UI 相关的 API 名称列表
7
- * 这些 API 用于创建视图,在 HMR 时需要识别
8
- */
9
- export const UI_API_NAMES = ['createView', 'branch', 'dynamic', 'expr', 'accessor', 'withDirectives'];
10
1
  /**
11
2
  * Ref 相关 API 名称
12
3
  * 用于识别 ref 变量
@@ -46,6 +46,17 @@ export default class HMRManager {
46
46
  * const state = __$VITARX_HMR$__.instance.memo(__$VITARX_HMR_VIEW_NODE$__, 'state') ?? ref(0)
47
47
  */
48
48
  memo(view: ComponentView, name: string): any;
49
+ /**
50
+ * 无条件恢复状态(不做 Ref/reactive 门禁)
51
+ *
52
+ * 供解构声明的隐藏变量使用:composable 返回的控制器是普通对象
53
+ * (内含 Ref 与函数),memo 的响应式门禁会将其拒收导致恢复永远
54
+ * 落空。仅限转换器为解构声明生成的代码调用。
55
+ *
56
+ * @param {ComponentView} view - 组件视图
57
+ * @param {string} name - 变量名称
58
+ */
59
+ memoRaw(view: ComponentView, name: string): any;
49
60
  /**
50
61
  * 注册节点
51
62
  *
@@ -59,10 +70,25 @@ export default class HMRManager {
59
70
  * @param component - 组件构造函数
60
71
  */
61
72
  getId(component: Component): string;
73
+ /**
74
+ * 登记视图状态 getter
75
+ *
76
+ * 由转换器注入的代码在组件函数每次执行时调用,登记当前作用域的
77
+ * 惰性状态读取器(同一视图重复登记覆盖旧的)。读取动作延迟到
78
+ * 热更新快照时发生,正常挂载/重挂载不会产生任何状态残留。
79
+ *
80
+ * @param {ComponentView} view - 组件视图
81
+ * @param {Record<string, () => any>} getters - 变量名到读取器的映射
82
+ */
83
+ trackState(view: ComponentView, getters: Record<string, () => any>): void;
62
84
  /**
63
85
  * 模块更新
64
86
  *
65
87
  * @param newModule - 新模块对象
88
+ * @returns 模块导出中是否包含至少一个已绑定 HMR id 的组件。
89
+ * 供导入转发模块的 accept 回调判断兜底:转发目标若不含
90
+ * 可识别组件(如换成未转换模块的组件),调用方应
91
+ * invalidate 触发整页刷新,避免界面静默 stale。
66
92
  */
67
- update(newModule: ModuleNamespace): void;
93
+ update(newModule: ModuleNamespace): boolean;
68
94
  }
@@ -3,10 +3,11 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _HMRManager_idMapToView, _HMRManager_idMapToComponent;
6
+ var _HMRManager_instances, _HMRManager_idMapToView, _HMRManager_idMapToComponent, _HMRManager_viewStateGetters, _HMRManager_snapshotState;
7
7
  import { isComponent, isReactive, isRef } from 'vitarx';
8
8
  import { HMR } from '../constants/index.js';
9
9
  import { processUpdate } from './update.js';
10
+ import { collectLiveViews, registerViewRef } from './weak-refs.js';
10
11
  /**
11
12
  * HMR管理器
12
13
  *
@@ -14,10 +15,18 @@ import { processUpdate } from './update.js';
14
15
  */
15
16
  class HMRManager {
16
17
  constructor() {
18
+ _HMRManager_instances.add(this);
17
19
  /**
18
20
  * id模块映射到组件虚拟节点集合
19
21
  *
20
- * 模块id -> 组件虚拟节点
22
+ * 模块id -> 组件虚拟节点(WeakRef 弱引用)
23
+ *
24
+ * 为什么用 WeakRef:register 在组件每次执行时都会调用,若用强引用,
25
+ * 已销毁的视图(弹窗关闭、路由切换)会被本 Map 永久钉住造成内存泄漏。
26
+ * WeakRef 借助 GC 可达性天然区分「Freeze 停用」与「真销毁」——
27
+ * Freeze 缓存持有视图强引用,停用中的视图不会被回收,热更新照常处理;
28
+ * 真销毁的视图无引用可回收,deref() 返回空,遍历时剪枝。
29
+ * 剪枝时机为 register/update 遍历(dev 下高频),泄漏上限极小。
21
30
  */
22
31
  _HMRManager_idMapToView.set(this, new Map()
23
32
  /**
@@ -28,6 +37,20 @@ class HMRManager {
28
37
  * id映射到组件构造函数
29
38
  */
30
39
  _HMRManager_idMapToComponent.set(this, new Map()
40
+ /**
41
+ * 视图状态 getter 登记表
42
+ *
43
+ * 组件函数每次执行时通过 trackState 登记当前作用域状态的惰性读取器,
44
+ * 热更新时读取一次生成快照;视图销毁/重挂载不会保留,避免旧状态泄漏。
45
+ */
46
+ );
47
+ /**
48
+ * 视图状态 getter 登记表
49
+ *
50
+ * 组件函数每次执行时通过 trackState 登记当前作用域状态的惰性读取器,
51
+ * 热更新时读取一次生成快照;视图销毁/重挂载不会保留,避免旧状态泄漏。
52
+ */
53
+ _HMRManager_viewStateGetters.set(this, new WeakMap()
31
54
  /**
32
55
  * 获取单实例
33
56
  */
@@ -81,6 +104,21 @@ class HMRManager {
81
104
  return undefined;
82
105
  return state;
83
106
  }
107
+ /**
108
+ * 无条件恢复状态(不做 Ref/reactive 门禁)
109
+ *
110
+ * 供解构声明的隐藏变量使用:composable 返回的控制器是普通对象
111
+ * (内含 Ref 与函数),memo 的响应式门禁会将其拒收导致恢复永远
112
+ * 落空。仅限转换器为解构声明生成的代码调用。
113
+ *
114
+ * @param {ComponentView} view - 组件视图
115
+ * @param {string} name - 变量名称
116
+ */
117
+ memoRaw(view, name) {
118
+ if (!view)
119
+ return undefined;
120
+ return view[HMR.state]?.[name];
121
+ }
84
122
  /**
85
123
  * 注册节点
86
124
  *
@@ -92,11 +130,12 @@ class HMRManager {
92
130
  return;
93
131
  component ?? (component = view.component);
94
132
  const id = this.getId(component);
95
- if (__classPrivateFieldGet(this, _HMRManager_idMapToView, "f").has(id)) {
96
- __classPrivateFieldGet(this, _HMRManager_idMapToView, "f").get(id).add(view);
133
+ const refs = __classPrivateFieldGet(this, _HMRManager_idMapToView, "f").get(id);
134
+ if (refs) {
135
+ registerViewRef(refs, view);
97
136
  }
98
137
  else {
99
- __classPrivateFieldGet(this, _HMRManager_idMapToView, "f").set(id, new Set([view]));
138
+ __classPrivateFieldGet(this, _HMRManager_idMapToView, "f").set(id, new Set([new WeakRef(view)]));
100
139
  }
101
140
  }
102
141
  /**
@@ -107,14 +146,33 @@ class HMRManager {
107
146
  getId(component) {
108
147
  return Reflect.get(component, HMR.id);
109
148
  }
149
+ /**
150
+ * 登记视图状态 getter
151
+ *
152
+ * 由转换器注入的代码在组件函数每次执行时调用,登记当前作用域的
153
+ * 惰性状态读取器(同一视图重复登记覆盖旧的)。读取动作延迟到
154
+ * 热更新快照时发生,正常挂载/重挂载不会产生任何状态残留。
155
+ *
156
+ * @param {ComponentView} view - 组件视图
157
+ * @param {Record<string, () => any>} getters - 变量名到读取器的映射
158
+ */
159
+ trackState(view, getters) {
160
+ if (!view)
161
+ return;
162
+ __classPrivateFieldGet(this, _HMRManager_viewStateGetters, "f").set(view, getters);
163
+ }
110
164
  /**
111
165
  * 模块更新
112
166
  *
113
167
  * @param newModule - 新模块对象
168
+ * @returns 模块导出中是否包含至少一个已绑定 HMR id 的组件。
169
+ * 供导入转发模块的 accept 回调判断兜底:转发目标若不含
170
+ * 可识别组件(如换成未转换模块的组件),调用方应
171
+ * invalidate 触发整页刷新,避免界面静默 stale。
114
172
  */
115
173
  update(newModule) {
116
174
  if (!newModule)
117
- return;
175
+ return false;
118
176
  try {
119
177
  const components = [];
120
178
  const updatedView = new Set();
@@ -135,23 +193,39 @@ class HMRManager {
135
193
  for (const component of components) {
136
194
  const id = this.getId(component);
137
195
  // 模块活跃的虚拟节点集合
138
- const views = __classPrivateFieldGet(this, _HMRManager_idMapToView, "f").get(id);
139
- if (!views)
196
+ const refs = __classPrivateFieldGet(this, _HMRManager_idMapToView, "f").get(id);
197
+ if (!refs)
198
+ continue;
199
+ // 收集存活视图(死引用已剪枝),遍历使其更新
200
+ const views = collectLiveViews(refs);
201
+ // 集合清空则移除 Map 条目,避免空壳残留长期积累
202
+ if (refs.size === 0) {
203
+ __classPrivateFieldGet(this, _HMRManager_idMapToView, "f").delete(id);
140
204
  continue;
141
- // 遍历关联的所有视图,使其更新
205
+ }
142
206
  for (const view of views) {
143
207
  // 跳过已更新过的视图,避免同一次更新中同一个视图被更新多次
144
208
  if (updatedView.has(view))
145
209
  continue;
146
210
  // 仅在视图是活跃状态,且已挂载时才更新
147
211
  if (view.isActive && view.isMounted) {
148
- // 处理视图更新
149
- processUpdate(view, this.resolveComponent(view.component));
212
+ // 重执行前快照当前状态,使组件函数重执行时 memo 命中、保留状态
213
+ __classPrivateFieldGet(this, _HMRManager_instances, "m", _HMRManager_snapshotState).call(this, view);
214
+ try {
215
+ // 处理视图更新
216
+ processUpdate(view, this.resolveComponent(view.component));
217
+ }
218
+ finally {
219
+ // 快照仅服务于本次热更新,用完即清——
220
+ // 保证后续正常的「卸载→重挂载」拿到全新状态,与生产行为一致
221
+ delete view[HMR.state];
222
+ }
150
223
  // 标记视图已更新
151
224
  updatedView.add(view);
152
225
  }
153
226
  }
154
227
  }
228
+ return components.length > 0;
155
229
  }
156
230
  catch (e) {
157
231
  if (import.meta.hot) {
@@ -161,7 +235,29 @@ class HMRManager {
161
235
  throw e;
162
236
  }
163
237
  }
238
+ return false;
164
239
  }
165
240
  }
166
- _HMRManager_idMapToView = new WeakMap(), _HMRManager_idMapToComponent = new WeakMap();
241
+ _HMRManager_idMapToView = new WeakMap(), _HMRManager_idMapToComponent = new WeakMap(), _HMRManager_viewStateGetters = new WeakMap(), _HMRManager_instances = new WeakSet(), _HMRManager_snapshotState = function _HMRManager_snapshotState(view) {
242
+ const getters = __classPrivateFieldGet(this, _HMRManager_viewStateGetters, "f").get(view);
243
+ if (!getters)
244
+ return;
245
+ const snapshot = {};
246
+ for (const name in getters) {
247
+ try {
248
+ // 注意:getters 是 getter 属性对象——读取属性即执行 getter 并返回值,
249
+ // 不能再加调用括号(否则会把返回值当函数调用,全部抛 TypeError)
250
+ const value = getters[name];
251
+ // 防御:函数值(旧编译产物仍可能登记函数变量)不进入快照,
252
+ // 绝不调用组件内的业务函数
253
+ if (typeof value === 'function')
254
+ continue;
255
+ snapshot[name] = value;
256
+ }
257
+ catch {
258
+ // 单个变量读取失败(如暂时性死区)不影响其余状态恢复
259
+ }
260
+ }
261
+ view[HMR.state] = snapshot;
262
+ };
167
263
  export default HMRManager;
@@ -1,7 +1,16 @@
1
+ /**
2
+ * HMR 组件更新:统一「卸载 → 重建 → 挂载」语义
3
+ *
4
+ * 任何代码变更(含纯 UI/注释)都走完整重挂载:dispose 触发旧实例的
5
+ * onDispose/onScopeDispose 清理副作用,init 重执行组件函数(状态经
6
+ * memo/快照协议保留),mount 触发 onMounted——dev 与生产的生命周期
7
+ * 语义完全一致,不区分 logic/非 logic 分叉,不存在钩子滞留或孤儿监听。
8
+ * @module hmr-client/update
9
+ */
1
10
  import { Component, ComponentView } from 'vitarx';
2
11
  /**
3
- * 处理组件更新函数
12
+ * 处理组件更新:卸载旧实例 → 重建(重执行组件函数,状态经快照恢复)→ 挂载
4
13
  * @param view - 组件视图对象,包含当前组件的实例和节点信息
5
- * @param newComponent - 新的组件定义,用于替换现有组件
14
+ * @param newComponent - 新的组件定义
6
15
  */
7
16
  export declare function processUpdate(view: ComponentView, newComponent: Component): void;
@@ -1,72 +1,38 @@
1
- import { createCommentView, EffectScope, getRenderer, runComponent } from 'vitarx';
2
- import { diffComponentChange } from './utils.js';
3
1
  /**
4
- * 处理组件更新函数
2
+ * HMR 组件更新:统一「卸载 → 重建 → 挂载」语义
3
+ *
4
+ * 任何代码变更(含纯 UI/注释)都走完整重挂载:dispose 触发旧实例的
5
+ * onDispose/onScopeDispose 清理副作用,init 重执行组件函数(状态经
6
+ * memo/快照协议保留),mount 触发 onMounted——dev 与生产的生命周期
7
+ * 语义完全一致,不区分 logic/非 logic 分叉,不存在钩子滞留或孤儿监听。
8
+ * @module hmr-client/update
9
+ */
10
+ import { getRenderer } from 'vitarx';
11
+ /**
12
+ * 处理组件更新:卸载旧实例 → 重建(重执行组件函数,状态经快照恢复)→ 挂载
5
13
  * @param view - 组件视图对象,包含当前组件的实例和节点信息
6
- * @param newComponent - 新的组件定义,用于替换现有组件
14
+ * @param newComponent - 新的组件定义
7
15
  */
8
16
  export function processUpdate(view, newComponent) {
9
- // 获取渲染器实例
17
+ // 获取渲染器实例,创建占位注释节点并插入到旧元素位置,
18
+ // 作为新旧子树替换的锚点
10
19
  const renderer = getRenderer();
11
- // 创建一个占位符注释节点
12
20
  const placeholder = renderer.createComment('');
13
- // 获取旧组件的DOM元素
14
- const oldElement = view.node;
15
- // 将占位符插入到旧元素的位置
16
- renderer.insert(placeholder, oldElement);
17
- // 获取组件实例
18
- const instance = view.instance;
19
- // 比较新旧组件的差异,检查逻辑是否有变化
20
- const { logic } = diffComponentChange(view.component.toString(), newComponent.toString());
21
- // 更新视图中的组件引用
21
+ renderer.insert(placeholder, view.node);
22
+ // 更新视图中的组件引用为最新模块导出
22
23
  Object.defineProperty(view, 'component', {
23
24
  value: newComponent,
24
25
  writable: true,
25
26
  enumerable: true,
26
27
  configurable: true
27
28
  });
28
- // 如果逻辑有变化,则完全重新挂载组件
29
- if (logic) {
30
- const ctx = view.ctx;
31
- view.dispose();
32
- view.init(ctx);
33
- view.mount(placeholder, 'replace');
34
- return;
35
- }
36
- // 销毁旧作用域
37
- instance.scope.dispose();
38
- // 重新创建新的作用域
39
- const scope = new EffectScope({
40
- name: view.name,
41
- errorHandler: (error, source) => {
42
- instance.reportError(error, `effect:${source}`);
43
- }
44
- });
45
- Object.defineProperty(instance, 'scope', {
46
- value: scope,
47
- writable: true,
48
- enumerable: true,
49
- configurable: true
50
- });
51
- // 销毁旧的子树
52
- instance.subView.dispose();
53
- // 创建新的子树
54
- let subView;
55
- try {
56
- subView = runComponent(instance, () => newComponent(view.props));
57
- }
58
- catch (e) {
59
- instance.reportError(e, 'component:run');
60
- subView = createCommentView(`Component<${view.name}>:failed`);
61
- }
62
- Object.defineProperty(instance, 'subView', {
63
- value: instance['normalizeView'](subView),
64
- writable: true,
65
- enumerable: true,
66
- configurable: true
67
- });
68
- // 初始化新的子树
69
- instance.subView.init(instance.subViewContext);
70
- // 挂载新的子树
71
- instance.subView.mount(placeholder, 'replace');
29
+ // 完整重挂载:dispose(清理旧副作用,触发 onDispose/onScopeDispose)
30
+ // → init(重执行组件函数,memo 命中快照保留状态)
31
+ // → mount(触发 onMounted,重新注册副作用)
32
+ // 注意:ctx 必须在 dispose 之前捕获——dispose 会拆除 provide 链,
33
+ // 之后读取 ctx 会导致重执行时 inject(如 useRouter)解析失败
34
+ const ctx = view.ctx;
35
+ view.dispose();
36
+ view.init(ctx);
37
+ view.mount(placeholder, 'replace');
72
38
  }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * HMR 视图弱引用集合工具
3
+ *
4
+ * #idMapToView 借助 WeakRef 让已销毁视图可被 GC 回收,避免被管理器
5
+ * 永久强引用造成内存泄漏。GC 可达性天然区分「Freeze 停用」与
6
+ * 「真销毁」——Freeze 缓存持有视图强引用,停用中的视图不会被回收,
7
+ * 热更新照常处理;真销毁的视图无引用可回收,deref() 返回空,遍历时剪枝。
8
+ *
9
+ * 剪枝/去重逻辑抽为纯函数并接受 WeakRefLike 结构类型,便于以伪引用
10
+ * 做确定性单元测试(真实 WeakRef 的 deref 时点依赖 GC,无法确定性断言)。
11
+ * @module hmr-client/weak-refs
12
+ */
13
+ import type { ComponentView } from 'vitarx';
14
+ /**
15
+ * WeakRef 结构类型
16
+ *
17
+ * 真实 WeakRef 天然满足此结构;测试可注入自定义伪引用。
18
+ */
19
+ export interface WeakRefLike<T extends object> {
20
+ deref(): T | undefined;
21
+ }
22
+ /**
23
+ * 向引用集合登记视图:剪枝死引用 + 按 deref 比对去重
24
+ *
25
+ * WeakRef 身份 ≠ 视图身份,同一视图多次登记(组件每次执行都会
26
+ * register)必须按解引用结果比对,否则集合会被同视图的多个
27
+ * WeakRef 无限撑大。
28
+ * @param refs - 视图弱引用集合(原地修改)
29
+ * @param view - 待登记的视图
30
+ */
31
+ export declare function registerViewRef(refs: Set<WeakRefLike<ComponentView>>, view: ComponentView): void;
32
+ /**
33
+ * 收集集合中仍存活(未被 GC)的视图,并原地剪枝死引用
34
+ * @param refs - 视图弱引用集合(原地修改)
35
+ * @returns 存活视图数组
36
+ */
37
+ export declare function collectLiveViews(refs: Set<WeakRefLike<ComponentView>>): ComponentView[];
@@ -0,0 +1,41 @@
1
+ /**
2
+ * 向引用集合登记视图:剪枝死引用 + 按 deref 比对去重
3
+ *
4
+ * WeakRef 身份 ≠ 视图身份,同一视图多次登记(组件每次执行都会
5
+ * register)必须按解引用结果比对,否则集合会被同视图的多个
6
+ * WeakRef 无限撑大。
7
+ * @param refs - 视图弱引用集合(原地修改)
8
+ * @param view - 待登记的视图
9
+ */
10
+ export function registerViewRef(refs, view) {
11
+ let exists = false;
12
+ for (const ref of refs) {
13
+ const cached = ref.deref();
14
+ if (!cached) {
15
+ refs.delete(ref);
16
+ }
17
+ else if (cached === view) {
18
+ exists = true;
19
+ }
20
+ }
21
+ if (!exists)
22
+ refs.add(new WeakRef(view));
23
+ }
24
+ /**
25
+ * 收集集合中仍存活(未被 GC)的视图,并原地剪枝死引用
26
+ * @param refs - 视图弱引用集合(原地修改)
27
+ * @returns 存活视图数组
28
+ */
29
+ export function collectLiveViews(refs) {
30
+ const live = [];
31
+ for (const ref of refs) {
32
+ const view = ref.deref();
33
+ if (view) {
34
+ live.push(view);
35
+ }
36
+ else {
37
+ refs.delete(ref);
38
+ }
39
+ }
40
+ return live;
41
+ }
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import * as t from '@babel/types';
7
7
  import { TransformContext } from '../../context.js';
8
- import type { DirectiveInfo } from '../../passes/props/types.js';
8
+ import type { DirectiveInfo } from '../props/types.js';
9
9
  /**
10
10
  * 处理指令
11
11
  * 将指令转换为 withDirectives 调用
@@ -52,16 +52,21 @@ ctx // 转换上下文,包含别名、导入等信息
52
52
  const properties = []; // 定义对象属性数组,可以是属性或方法
53
53
  // 添加 value 属性
54
54
  if (isIdentifier(value)) {
55
- // 如果值是一个标识符
56
- markImport(ctx, 'unref'); // 标记需要导入unref函数
57
- const unrefAlias = getAlias(ctx.vitarxAliases, 'unref'); // 获取unref函数的别名
58
- properties.push(
59
- // 添加一个getter方法作为属性
60
- t.objectMethod('get', // 方法类型为getter
61
- t.identifier('value'), // 属性名为value
62
- [], // 无参数
63
- t.blockStatement([t.returnStatement(t.callExpression(t.identifier(unrefAlias), [value]))]) // 返回unref(value)
64
- ));
55
+ // 三态决策:已知 ref → .value,已知非 ref → 原样,未知 → unref()
56
+ if (ctx.refVariables.has(value.name)) {
57
+ // 已知 ref:直接使用 .value
58
+ properties.push(t.objectMethod('get', t.identifier('value'), [], t.blockStatement([t.returnStatement(t.memberExpression(value, t.identifier('value')))])));
59
+ }
60
+ else if (ctx.nonRefVariables.has(value.name)) {
61
+ // 已知非 ref(函数等):原样返回,无需 unref
62
+ properties.push(t.objectMethod('get', t.identifier('value'), [], t.blockStatement([t.returnStatement(value)])));
63
+ }
64
+ else {
65
+ // 未知标识符:使用 unref() 解包(非 ref 原样返回)
66
+ markImport(ctx, 'unref');
67
+ const unrefAlias = getAlias(ctx.vitarxAliases, 'unref');
68
+ properties.push(t.objectMethod('get', t.identifier('value'), [], t.blockStatement([t.returnStatement(t.callExpression(t.identifier(unrefAlias), [value]))])));
69
+ }
65
70
  }
66
71
  else {
67
72
  // 如果值不是标识符
@@ -2,4 +2,4 @@
2
2
  * HMR 注入模块入口
3
3
  * @module passes/hmr
4
4
  */
5
- export { injectHMRSupport } from './inject.js';
5
+ export { injectHMRSupport, injectHMRAcceptOnly } from './inject.js';
@@ -2,4 +2,4 @@
2
2
  * HMR 注入模块入口
3
3
  * @module passes/hmr
4
4
  */
5
- export { injectHMRSupport } from './inject.js';
5
+ export { injectHMRSupport, injectHMRAcceptOnly } from './inject.js';
@@ -20,15 +20,21 @@ export declare function createHMRRegistrationStatements(variableNames: string[])
20
20
  */
21
21
  export declare function createWrappedComponentHMRStatements(componentName: string): t.Statement[];
22
22
  /**
23
- * 从函数体中收集局部变量名
24
- * 递归遍历函数体中的所有变量声明,用于状态恢复
23
+ * 为函数体注入状态恢复代码并收集需要登记(trackState)的变量名
24
+ *
25
+ * 处理规则:
26
+ * - 标识符声明(非函数初始值):初始值包装为 memo(view, '变量名') ?? 原始初始值
27
+ * - useModel 调用:豁免(桥接状态每次重建,见 isUseModelCall)
28
+ * - 解构声明(如 `const { a } = useFoo()`):拆分为隐藏变量整包 memo +
29
+ * 原声明解构隐藏变量——composable 返回的状态对象得以跨重执行保留,
30
+ * 其内部创建的响应式状态与已挂载的副作用保持一致
31
+ * - 函数类型初始值 / 无初始值:不注入
32
+ * - for 循环头部声明:循环局部绑定,不注入(仅递归循环体)
33
+ *
34
+ * 单趟完成注入与收集,返回按执行顺序排列的登记名列表(标识符名 +
35
+ * 隐藏变量名),供 trackState 生成 getter。隐藏变量采用用户标识符不可能
36
+ * 命中的 `__$VITARX_D<N>$__` 命名,按组件函数内确定性计数。
25
37
  * @param functionBody - 函数体语句块
26
- * @returns 变量名数组
38
+ * @returns 需要状态登记的变量名数组
27
39
  */
28
- export declare function collectLocalVariableNames(functionBody: t.BlockStatement): string[];
29
- /**
30
- * 为函数体内的变量声明注入状态恢复代码
31
- * 遍历函数体中的所有变量声明语句
32
- * @param functionBody - 函数体语句块
33
- */
34
- export declare function injectStatePreservation(functionBody: t.BlockStatement): void;
40
+ export declare function injectStatePreservation(functionBody: t.BlockStatement): string[];