@lynx-js/react 0.105.1 → 0.106.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 (109) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/package.json +2 -2
  3. package/refresh/.turbo/turbo-build.log +1 -1
  4. package/refresh/package.json +1 -1
  5. package/runtime/lib/backgroundSnapshot.d.ts +1 -1
  6. package/runtime/lib/backgroundSnapshot.js +2 -2
  7. package/runtime/lib/backgroundSnapshot.js.map +1 -1
  8. package/runtime/lib/compat/initData.js +0 -2
  9. package/runtime/lib/compat/initData.js.map +1 -1
  10. package/runtime/lib/gesture/processGesture.js +3 -0
  11. package/runtime/lib/gesture/processGesture.js.map +1 -1
  12. package/runtime/lib/gesture/types.d.ts +2 -0
  13. package/runtime/lib/internal.d.ts +2 -1
  14. package/runtime/lib/internal.js +3 -2
  15. package/runtime/lib/internal.js.map +1 -1
  16. package/runtime/lib/lifecycle/destroy.js +3 -3
  17. package/runtime/lib/lifecycle/destroy.js.map +1 -1
  18. package/runtime/lib/lifecycle/{patchUpdate.d.ts → patch/commit.d.ts} +8 -6
  19. package/runtime/lib/lifecycle/patch/commit.js +167 -0
  20. package/runtime/lib/lifecycle/patch/commit.js.map +1 -0
  21. package/runtime/lib/lifecycle/patch/snapshotPatch.js.map +1 -0
  22. package/runtime/lib/{snapshotPatchApply.js → lifecycle/patch/snapshotPatchApply.js} +1 -4
  23. package/runtime/lib/lifecycle/patch/snapshotPatchApply.js.map +1 -0
  24. package/runtime/lib/lifecycle/patch/updateMainThread.d.ts +3 -0
  25. package/runtime/lib/lifecycle/patch/updateMainThread.js +56 -0
  26. package/runtime/lib/lifecycle/patch/updateMainThread.js.map +1 -0
  27. package/runtime/lib/lifecycle/reload.js +3 -4
  28. package/runtime/lib/lifecycle/reload.js.map +1 -1
  29. package/runtime/lib/lifecycle/render.d.ts +3 -1
  30. package/runtime/lib/lifecycle/render.js +9 -2
  31. package/runtime/lib/lifecycle/render.js.map +1 -1
  32. package/runtime/lib/list.d.ts +3 -0
  33. package/runtime/lib/list.js +11 -3
  34. package/runtime/lib/list.js.map +1 -1
  35. package/runtime/lib/lynx/calledByNative.js +40 -5
  36. package/runtime/lib/lynx/calledByNative.js.map +1 -1
  37. package/runtime/lib/lynx/component.js +3 -3
  38. package/runtime/lib/lynx/component.js.map +1 -1
  39. package/runtime/lib/lynx/dynamic-js.js +0 -1
  40. package/runtime/lib/lynx/dynamic-js.js.map +1 -1
  41. package/runtime/lib/lynx/env.js +1 -2
  42. package/runtime/lib/lynx/env.js.map +1 -1
  43. package/runtime/lib/lynx/lazy-bundle.js.map +1 -1
  44. package/runtime/lib/lynx/performance.js +1 -1
  45. package/runtime/lib/lynx/performance.js.map +1 -1
  46. package/runtime/lib/lynx/tt.d.ts +1 -0
  47. package/runtime/lib/lynx/tt.js +48 -7
  48. package/runtime/lib/lynx/tt.js.map +1 -1
  49. package/runtime/lib/lynx-api.d.ts +1 -1
  50. package/runtime/lib/lynx-api.js +2 -2
  51. package/runtime/lib/lynx-api.js.map +1 -1
  52. package/runtime/lib/lynx.d.ts +0 -1
  53. package/runtime/lib/lynx.js +4 -46
  54. package/runtime/lib/lynx.js.map +1 -1
  55. package/runtime/lib/opcodes.d.ts +6 -0
  56. package/runtime/lib/opcodes.js +70 -0
  57. package/runtime/lib/opcodes.js.map +1 -1
  58. package/runtime/lib/root.d.ts +1 -0
  59. package/runtime/lib/root.js.map +1 -1
  60. package/runtime/lib/snapshot/ref.d.ts +2 -2
  61. package/runtime/lib/snapshot/ref.js +6 -7
  62. package/runtime/lib/snapshot/ref.js.map +1 -1
  63. package/runtime/lib/snapshot.js +1 -1
  64. package/runtime/lib/snapshot.js.map +1 -1
  65. package/runtime/lib/worklet/functionCall.js.map +1 -1
  66. package/runtime/lib/worklet/hmr.js +1 -1
  67. package/runtime/lib/worklet/hmr.js.map +1 -1
  68. package/runtime/lib/worklet/runOnBackground.js.map +1 -1
  69. package/runtime/lib/worklet/workletRef.js +1 -1
  70. package/runtime/lib/worklet/workletRef.js.map +1 -1
  71. package/runtime/src/backgroundSnapshot.ts +3 -3
  72. package/runtime/src/compat/initData.ts +5 -6
  73. package/runtime/src/gesture/processGesture.ts +4 -0
  74. package/runtime/src/gesture/types.ts +2 -0
  75. package/runtime/src/internal.ts +4 -2
  76. package/runtime/src/lifecycle/destroy.ts +3 -4
  77. package/runtime/src/lifecycle/{patchUpdate.ts → patch/commit.ts} +94 -100
  78. package/runtime/src/{snapshotPatchApply.ts → lifecycle/patch/snapshotPatchApply.ts} +2 -2
  79. package/runtime/src/lifecycle/patch/updateMainThread.ts +71 -0
  80. package/runtime/src/lifecycle/reload.ts +3 -5
  81. package/runtime/src/lifecycle/render.ts +12 -3
  82. package/runtime/src/list.ts +12 -3
  83. package/runtime/src/lynx/calledByNative.ts +47 -4
  84. package/runtime/src/lynx/component.ts +3 -3
  85. package/runtime/src/lynx/dynamic-js.ts +2 -3
  86. package/runtime/src/lynx/env.ts +2 -2
  87. package/runtime/src/lynx/lazy-bundle.ts +1 -1
  88. package/runtime/src/lynx/performance.ts +3 -2
  89. package/runtime/src/lynx/tt.ts +58 -9
  90. package/runtime/src/lynx-api.ts +3 -3
  91. package/runtime/src/lynx.ts +5 -55
  92. package/runtime/src/opcodes.ts +90 -0
  93. package/runtime/src/root.ts +1 -1
  94. package/runtime/src/snapshot/ref.ts +6 -9
  95. package/runtime/src/snapshot.ts +1 -1
  96. package/runtime/src/worklet/functionCall.ts +1 -1
  97. package/runtime/src/worklet/hmr.ts +1 -1
  98. package/runtime/src/worklet/runOnBackground.ts +4 -4
  99. package/runtime/src/worklet/workletRef.ts +1 -1
  100. package/transform/dist/wasm.cjs +1 -1
  101. package/types/react.docs.d.ts +1 -1
  102. package/runtime/lib/lifecycle/patchUpdate.js +0 -179
  103. package/runtime/lib/lifecycle/patchUpdate.js.map +0 -1
  104. package/runtime/lib/snapshotPatch.js.map +0 -1
  105. package/runtime/lib/snapshotPatchApply.js.map +0 -1
  106. /package/runtime/lib/{snapshotPatch.d.ts → lifecycle/patch/snapshotPatch.d.ts} +0 -0
  107. /package/runtime/lib/{snapshotPatch.js → lifecycle/patch/snapshotPatch.js} +0 -0
  108. /package/runtime/lib/{snapshotPatchApply.d.ts → lifecycle/patch/snapshotPatchApply.d.ts} +0 -0
  109. /package/runtime/src/{snapshotPatch.ts → lifecycle/patch/snapshotPatch.ts} +0 -0
@@ -1,31 +1,27 @@
1
1
  // Copyright 2024 The Lynx Authors. All rights reserved.
2
2
  // Licensed under the Apache License Version 2.0 that can be found in the
3
3
  // LICENSE file in the root directory of this source tree.
4
- import { options } from 'preact';
5
4
  import type { VNode } from 'preact';
5
+ import { options } from 'preact';
6
6
  import type { Component } from 'preact/compat';
7
7
 
8
- import { clearDelayedWorklets, updateWorkletRefInitValueChanges } from '@lynx-js/react/worklet-runtime/bindings';
9
-
10
- import { LifecycleConstant } from '../lifecycleConstant.js';
11
- import { __pendingListUpdates } from '../list.js';
12
- import { runDelayedUnmounts, takeDelayedUnmounts } from './delayUnmount.js';
13
- import { getReloadVersion } from './pass.js';
8
+ import type { SnapshotPatch } from './snapshotPatch.js';
9
+ import { takeGlobalSnapshotPatch } from './snapshotPatch.js';
10
+ import { LifecycleConstant } from '../../lifecycleConstant.js';
14
11
  import {
15
12
  PerformanceTimingKeys,
16
13
  globalPipelineOptions,
17
14
  markTiming,
18
15
  markTimingLegacy,
19
16
  setPipeline,
20
- } from '../lynx/performance.js';
21
- import { CATCH_ERROR, COMMIT, RENDER_CALLBACKS, VNODE } from '../renderToOpcodes/constants.js';
22
- import { takeGlobalRefPatchMap, updateBackgroundRefs } from '../snapshot/ref.js';
23
- import { __page, backgroundSnapshotInstanceManager } from '../snapshot.js';
24
- import { takeGlobalSnapshotPatch } from '../snapshotPatch.js';
25
- import type { SnapshotPatch } from '../snapshotPatch.js';
26
- import { snapshotPatchApply } from '../snapshotPatchApply.js';
27
- import { isEmptyObject } from '../utils.js';
28
- import { takeWorkletRefInitValuePatch } from '../worklet/workletRefPool.js';
17
+ } from '../../lynx/performance.js';
18
+ import { CATCH_ERROR, COMMIT, RENDER_CALLBACKS, VNODE } from '../../renderToOpcodes/constants.js';
19
+ import { updateBackgroundRefs } from '../../snapshot/ref.js';
20
+ import { backgroundSnapshotInstanceManager } from '../../snapshot.js';
21
+ import { isEmptyObject } from '../../utils.js';
22
+ import { takeWorkletRefInitValuePatch } from '../../worklet/workletRefPool.js';
23
+ import { runDelayedUnmounts, takeDelayedUnmounts } from '../delayUnmount.js';
24
+ import { getReloadVersion } from '../pass.js';
29
25
 
30
26
  let globalFlushOptions: FlushOptions = {};
31
27
 
@@ -34,77 +30,56 @@ let nextCommitTaskId = 1;
34
30
 
35
31
  let globalBackgroundSnapshotInstancesToRemove: number[] = [];
36
32
 
33
+ let patchesToCommit: Patch[] = [];
34
+
37
35
  interface Patch {
36
+ id: number;
38
37
  snapshotPatch?: SnapshotPatch;
39
38
  workletRefInitValuePatch?: [id: number, value: unknown][];
39
+ }
40
+
41
+ interface PatchList {
42
+ patchList: Patch[];
40
43
  flushOptions?: FlushOptions;
41
44
  }
42
45
 
43
46
  interface PatchOptions {
44
- commitTaskId: number;
45
47
  pipelineOptions?: PipelineOptions;
46
- reloadVersion?: number;
48
+ reloadVersion: number;
47
49
  isHydration?: boolean;
48
50
  }
49
51
 
50
- function injectUpdatePatch(): void {
51
- function updatePatch(
52
- { data, patchOptions }: {
53
- data: string;
54
- patchOptions: PatchOptions;
52
+ function replaceCommitHook(): void {
53
+ // use our own `options.debounceRendering` to insert a timing flag before render
54
+ type DebounceRendering = (f: () => void) => void;
55
+ const injectDebounceRendering = (debounceRendering: DebounceRendering): DebounceRendering => {
56
+ return (f: () => void) => {
57
+ debounceRendering(() => {
58
+ f();
59
+ void commitToMainThread();
60
+ });
61
+ };
62
+ };
63
+ const defaultDebounceRendering = options.debounceRendering?.bind(options)
64
+ ?? (Promise.prototype.then.bind(Promise.resolve()) as DebounceRendering);
65
+ let _debounceRendering = injectDebounceRendering(defaultDebounceRendering);
66
+ Object.defineProperty(options, 'debounceRendering', {
67
+ get() {
68
+ return _debounceRendering;
55
69
  },
56
- ): void {
57
- if ((patchOptions.reloadVersion ?? 0) < getReloadVersion()) {
58
- return;
59
- }
60
-
61
- setPipeline(patchOptions.pipelineOptions);
62
- markTiming(PerformanceTimingKeys.parse_changes_start);
63
- let { snapshotPatch, workletRefInitValuePatch, flushOptions } = JSON.parse(data) as Patch;
64
- markTiming(PerformanceTimingKeys.parse_changes_end);
65
-
66
- markTiming(PerformanceTimingKeys.patch_changes_start);
67
- updateWorkletRefInitValueChanges(workletRefInitValuePatch);
68
- __pendingListUpdates.clear();
69
- if (snapshotPatch) {
70
- snapshotPatchApply(snapshotPatch);
71
- }
72
- __pendingListUpdates.flush();
73
- // console.debug('********** Lepus updatePatch:');
74
- // printSnapshotInstance(snapshotInstanceManager.values.get(-1)!);
75
-
76
- commitMainThreadPatchUpdate(patchOptions.commitTaskId);
77
- if (patchOptions.isHydration) {
78
- clearDelayedWorklets();
79
- }
80
- markTiming(PerformanceTimingKeys.patch_changes_end);
81
- flushOptions ||= {};
82
- if (patchOptions.pipelineOptions) {
83
- flushOptions.pipelineOptions = patchOptions.pipelineOptions;
84
- }
85
- // TODO: triggerDataUpdated?
86
- __FlushElementTree(__page, flushOptions);
87
- }
88
-
89
- Object.assign(globalThis, { [LifecycleConstant.patchUpdate]: updatePatch });
90
- }
70
+ set(debounceRendering: DebounceRendering) {
71
+ _debounceRendering = injectDebounceRendering(debounceRendering);
72
+ },
73
+ });
91
74
 
92
- function replaceCommitHook(): void {
93
75
  const oldCommit = options[COMMIT];
94
- options[COMMIT] = async (vnode: VNode, commitQueue: any[]) => {
76
+ const commit = async (vnode: VNode, commitQueue: any[]) => {
95
77
  if (__LEPUS__) {
96
78
  // for testing only
97
79
  commitQueue.length = 0;
98
80
  return;
99
81
  }
100
-
101
- markTimingLegacy(PerformanceTimingKeys.update_diff_vdom_end);
102
- markTiming(PerformanceTimingKeys.diff_vdom_end);
103
- markTiming(PerformanceTimingKeys.pack_changes_start);
104
- if (__PROFILE__) {
105
- console.profile('commitChanges');
106
- }
107
- const renderCallbacks = commitQueue.map(component => {
82
+ const renderCallbacks = commitQueue.map((component: Component<any>) => {
108
83
  const ret = {
109
84
  component,
110
85
  [RENDER_CALLBACKS]: component[RENDER_CALLBACKS],
@@ -130,7 +105,7 @@ function replaceCommitHook(): void {
130
105
  cb.call(wrapper.component);
131
106
  });
132
107
  } catch (e) {
133
- options[CATCH_ERROR](e, wrapper[VNODE]);
108
+ options[CATCH_ERROR](e, wrapper[VNODE]!);
134
109
  }
135
110
  });
136
111
  if (backgroundSnapshotInstancesToRemove.length) {
@@ -143,50 +118,75 @@ function replaceCommitHook(): void {
143
118
  });
144
119
 
145
120
  const snapshotPatch = takeGlobalSnapshotPatch();
146
- const flushOptions = globalFlushOptions;
147
121
  const workletRefInitValuePatch = takeWorkletRefInitValuePatch();
148
- globalFlushOptions = {};
149
122
  if (!snapshotPatch && workletRefInitValuePatch.length === 0) {
150
123
  // before hydration, skip patch
151
- if (__PROFILE__) {
152
- console.profileEnd();
153
- }
154
124
  return;
155
125
  }
156
126
 
157
- const patch: Patch = {};
127
+ const patch: Patch = {
128
+ id: commitTaskId,
129
+ };
158
130
  // TODO: check all fields in `flushOptions` from runtime3
159
131
  if (snapshotPatch?.length) {
160
132
  patch.snapshotPatch = snapshotPatch;
161
133
  }
162
- if (!isEmptyObject(flushOptions)) {
163
- patch.flushOptions = flushOptions;
164
- }
165
134
  if (workletRefInitValuePatch.length) {
166
135
  patch.workletRefInitValuePatch = workletRefInitValuePatch;
167
136
  }
168
- await commitPatchUpdate(patch, { commitTaskId });
169
137
 
170
- const commitTask = globalCommitTaskMap.get(commitTaskId);
138
+ patchesToCommit.push(patch);
139
+ };
140
+ options[COMMIT] = commit as ((...args: Parameters<typeof commit>) => void);
141
+ }
142
+
143
+ async function commitToMainThread(): Promise<void> {
144
+ if (patchesToCommit.length === 0) {
145
+ return;
146
+ }
147
+
148
+ markTimingLegacy(PerformanceTimingKeys.update_diff_vdom_end);
149
+ markTiming(PerformanceTimingKeys.diff_vdom_end);
150
+
151
+ const flushOptions = globalFlushOptions;
152
+ globalFlushOptions = {};
153
+
154
+ const patchList: PatchList = {
155
+ patchList: patchesToCommit,
156
+ };
157
+ patchesToCommit = [];
158
+
159
+ if (!isEmptyObject(flushOptions)) {
160
+ patchList.flushOptions = flushOptions;
161
+ }
162
+
163
+ await commitPatchUpdate(patchList, {});
164
+
165
+ for (const patch of patchList.patchList) {
166
+ const commitTask = globalCommitTaskMap.get(patch.id);
171
167
  if (commitTask) {
172
168
  commitTask();
173
- globalCommitTaskMap.delete(commitTaskId);
169
+ globalCommitTaskMap.delete(patch.id);
174
170
  }
175
- };
171
+ }
176
172
  }
177
173
 
178
- function commitPatchUpdate(data: Patch, patchOptions: PatchOptions): Promise<void> {
174
+ function commitPatchUpdate(patchList: PatchList, patchOptions: Omit<PatchOptions, 'reloadVersion'>): Promise<void> {
179
175
  return new Promise(resolve => {
180
176
  // console.debug('********** JS update:');
181
177
  // printSnapshotInstance(
182
178
  // (backgroundSnapshotInstanceManager.values.get(1) || backgroundSnapshotInstanceManager.values.get(-1))!,
183
179
  // );
184
- // console.debug('commitPatchUpdate: ', JSON.stringify(data));
180
+ // console.debug('commitPatchUpdate: ', JSON.stringify(patchList));
181
+ if (__PROFILE__) {
182
+ console.profile('commitChanges');
183
+ }
184
+ markTiming(PerformanceTimingKeys.pack_changes_start);
185
185
  const obj: {
186
186
  data: string;
187
187
  patchOptions: PatchOptions;
188
188
  } = {
189
- data: JSON.stringify(data),
189
+ data: JSON.stringify(patchList),
190
190
  patchOptions: {
191
191
  ...patchOptions,
192
192
  reloadVersion: getReloadVersion(),
@@ -197,20 +197,13 @@ function commitPatchUpdate(data: Patch, patchOptions: PatchOptions): Promise<voi
197
197
  obj.patchOptions.pipelineOptions = globalPipelineOptions;
198
198
  setPipeline(undefined);
199
199
  }
200
+ lynx.getNativeApp().callLepusMethod(LifecycleConstant.patchUpdate, obj, resolve);
200
201
  if (__PROFILE__) {
201
202
  console.profileEnd();
202
203
  }
203
- lynx.getNativeApp().callLepusMethod(LifecycleConstant.patchUpdate, obj, resolve);
204
204
  });
205
205
  }
206
206
 
207
- function commitMainThreadPatchUpdate(commitTaskId?: number): void {
208
- const refPatch = takeGlobalRefPatchMap();
209
- if (!isEmptyObject(refPatch)) {
210
- __OnLifecycleEvent([LifecycleConstant.ref, { commitTaskId, refPatch: JSON.stringify(refPatch) }]);
211
- }
212
- }
213
-
214
207
  function genCommitTaskId(): number {
215
208
  return nextCommitTaskId++;
216
209
  }
@@ -219,7 +212,7 @@ function replaceRequestAnimationFrame(): void {
219
212
  // to make afterPaintEffects run faster
220
213
  const resolvedPromise = Promise.resolve();
221
214
  options.requestAnimationFrame = (cb: () => void) => {
222
- resolvedPromise.then(cb);
215
+ void resolvedPromise.then(cb);
223
216
  };
224
217
  }
225
218
 
@@ -227,14 +220,15 @@ function replaceRequestAnimationFrame(): void {
227
220
  * @internal
228
221
  */
229
222
  export {
230
- injectUpdatePatch,
231
223
  commitPatchUpdate,
232
- replaceCommitHook,
224
+ commitToMainThread,
233
225
  genCommitTaskId,
234
- commitMainThreadPatchUpdate,
235
- replaceRequestAnimationFrame,
236
- globalFlushOptions,
237
- globalCommitTaskMap,
238
226
  globalBackgroundSnapshotInstancesToRemove,
227
+ globalCommitTaskMap,
228
+ globalFlushOptions,
239
229
  nextCommitTaskId,
230
+ replaceCommitHook,
231
+ replaceRequestAnimationFrame,
232
+ type PatchOptions,
233
+ type PatchList,
240
234
  };
@@ -1,9 +1,9 @@
1
1
  // Copyright 2024 The Lynx Authors. All rights reserved.
2
2
  // Licensed under the Apache License Version 2.0 that can be found in the
3
3
  // LICENSE file in the root directory of this source tree.
4
- import { createSnapshot, SnapshotInstance, snapshotInstanceManager, snapshotManager } from './snapshot.js';
5
4
  import type { SnapshotPatch } from './snapshotPatch.js';
6
5
  import { SnapshotOperation } from './snapshotPatch.js';
6
+ import { SnapshotInstance, createSnapshot, snapshotInstanceManager, snapshotManager } from '../../snapshot.js';
7
7
 
8
8
  function reportCtxNotFound(): void {
9
9
  lynx.reportError(new Error(`snapshotPatchApply failed: ctx not found`));
@@ -25,7 +25,7 @@ export function snapshotPatchApply(snapshotPatch: SnapshotPatch): void {
25
25
  const beforeId = snapshotPatch[++i];
26
26
  const parent = snapshotInstanceManager.values.get(parentId);
27
27
  const child = snapshotInstanceManager.values.get(childId);
28
- const existingNode = snapshotInstanceManager.values.get(beforeId!);
28
+ const existingNode = snapshotInstanceManager.values.get(beforeId);
29
29
  if (!parent || !child) {
30
30
  reportCtxNotFound();
31
31
  } else {
@@ -0,0 +1,71 @@
1
+ // Copyright 2025 The Lynx Authors. All rights reserved.
2
+ // Licensed under the Apache License Version 2.0 that can be found in the
3
+ // LICENSE file in the root directory of this source tree.
4
+
5
+ import { clearDelayedWorklets, updateWorkletRefInitValueChanges } from '@lynx-js/react/worklet-runtime/bindings';
6
+
7
+ import type { PatchList, PatchOptions } from './commit.js';
8
+ import { snapshotPatchApply } from './snapshotPatchApply.js';
9
+ import { LifecycleConstant } from '../../lifecycleConstant.js';
10
+ import { __pendingListUpdates } from '../../list.js';
11
+ import { PerformanceTimingKeys, markTiming, setPipeline } from '../../lynx/performance.js';
12
+ import { takeGlobalRefPatchMap } from '../../snapshot/ref.js';
13
+ import { __page } from '../../snapshot.js';
14
+ import { isEmptyObject } from '../../utils.js';
15
+ import { getReloadVersion } from '../pass.js';
16
+
17
+ function updateMainThread(
18
+ { data, patchOptions }: {
19
+ data: string;
20
+ patchOptions: PatchOptions;
21
+ },
22
+ ): void {
23
+ if ((patchOptions.reloadVersion) < getReloadVersion()) {
24
+ return;
25
+ }
26
+
27
+ setPipeline(patchOptions.pipelineOptions);
28
+ markTiming(PerformanceTimingKeys.parse_changes_start);
29
+ const { patchList, flushOptions = {} } = JSON.parse(data) as PatchList;
30
+
31
+ markTiming(PerformanceTimingKeys.parse_changes_end);
32
+ markTiming(PerformanceTimingKeys.patch_changes_start);
33
+
34
+ for (const { snapshotPatch, workletRefInitValuePatch, id } of patchList) {
35
+ updateWorkletRefInitValueChanges(workletRefInitValuePatch);
36
+ __pendingListUpdates.clear();
37
+ if (snapshotPatch) {
38
+ snapshotPatchApply(snapshotPatch);
39
+ }
40
+ __pendingListUpdates.flush();
41
+ // console.debug('********** Lepus updatePatch:');
42
+ // printSnapshotInstance(snapshotInstanceManager.values.get(-1)!);
43
+
44
+ commitMainThreadPatchUpdate(id);
45
+ }
46
+ markTiming(PerformanceTimingKeys.patch_changes_end);
47
+ if (patchOptions.isHydration) {
48
+ clearDelayedWorklets();
49
+ }
50
+ if (patchOptions.pipelineOptions) {
51
+ flushOptions.pipelineOptions = patchOptions.pipelineOptions;
52
+ }
53
+ // TODO: triggerDataUpdated?
54
+ __FlushElementTree(__page, flushOptions);
55
+ }
56
+
57
+ function injectUpdateMainThread(): void {
58
+ Object.assign(globalThis, { [LifecycleConstant.patchUpdate]: updateMainThread });
59
+ }
60
+
61
+ function commitMainThreadPatchUpdate(commitTaskId?: number): void {
62
+ const refPatch = takeGlobalRefPatchMap();
63
+ if (!isEmptyObject(refPatch)) {
64
+ __OnLifecycleEvent([LifecycleConstant.ref, { commitTaskId, refPatch: JSON.stringify(refPatch) }]);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * @internal
70
+ */
71
+ export { commitMainThreadPatchUpdate, injectUpdateMainThread };
@@ -1,19 +1,17 @@
1
1
  // Copyright 2024 The Lynx Authors. All rights reserved.
2
2
  // Licensed under the Apache License Version 2.0 that can be found in the
3
3
  // LICENSE file in the root directory of this source tree.
4
- import { render } from 'preact';
5
-
6
4
  import { __root, setRoot } from '../root.js';
7
5
  import { SnapshotInstance, __page, snapshotInstanceManager } from '../snapshot.js';
8
6
  import { isEmptyObject } from '../utils.js';
9
7
  import { destroyBackground } from './destroy.js';
10
8
  import { increaseReloadVersion } from './pass.js';
11
- import { renderMainThread } from './render.js';
9
+ import { renderBackground, renderMainThread } from './render.js';
12
10
  import { hydrate } from '../hydrate.js';
13
11
  import { LifecycleConstant } from '../lifecycleConstant.js';
14
12
  import { __pendingListUpdates } from '../list.js';
15
13
  import { takeGlobalRefPatchMap } from '../snapshot/ref.js';
16
- import { deinitGlobalSnapshotPatch } from '../snapshotPatch.js';
14
+ import { deinitGlobalSnapshotPatch } from './patch/snapshotPatch.js';
17
15
  import { destroyWorklet } from '../worklet/destroy.js';
18
16
 
19
17
  function reloadMainThread(data: any, options: UpdatePageOption): void {
@@ -71,7 +69,7 @@ function reloadBackground(updateData: Record<string, any>): void {
71
69
  // COW when modify `lynx.__initData` to make sure Provider & Consumer works
72
70
  lynx.__initData = Object.assign({}, lynx.__initData, updateData);
73
71
 
74
- render(__root.__jsx, __root as any);
72
+ renderBackground(__root.__jsx, __root as any);
75
73
 
76
74
  if (__PROFILE__) {
77
75
  console.profileEnd();
@@ -2,11 +2,12 @@
2
2
  // Licensed under the Apache License Version 2.0 that can be found in the
3
3
  // LICENSE file in the root directory of this source tree.
4
4
  import { render } from 'preact';
5
+ import type { ComponentChild, ContainerNode } from 'preact';
5
6
 
6
7
  import { renderOpcodesInto } from '../opcodes.js';
7
8
  import { render as renderToString } from '../renderToOpcodes/index.js';
8
9
  import { __root } from '../root.js';
9
- // @ts-ignore
10
+ import { commitToMainThread } from './patch/commit.js';
10
11
 
11
12
  function renderMainThread(): void {
12
13
  /* v8 ignore start */
@@ -24,7 +25,7 @@ function renderMainThread(): void {
24
25
  // @ts-ignore
25
26
  opcodes = renderToString(__root.__jsx);
26
27
  } catch (e) {
27
- lynx.reportError(e);
28
+ lynx.reportError(e as Error);
28
29
  opcodes = [];
29
30
  } finally {
30
31
  if (__PROFILE__) {
@@ -36,6 +37,9 @@ function renderMainThread(): void {
36
37
  console.profile('renderOpcodesInto');
37
38
  }
38
39
  renderOpcodesInto(opcodes, __root as any);
40
+ if (__ENABLE_SSR__) {
41
+ __root.__opcodes = opcodes;
42
+ }
39
43
  if (__PROFILE__) {
40
44
  console.profileEnd();
41
45
  }
@@ -43,4 +47,9 @@ function renderMainThread(): void {
43
47
  /* v8 ignore stop */
44
48
  }
45
49
 
46
- export { renderMainThread };
50
+ function renderBackground(vnode: ComponentChild, parent: ContainerNode): void {
51
+ render(vnode, parent);
52
+ void commitToMainThread();
53
+ }
54
+
55
+ export { renderMainThread, renderBackground };
@@ -2,7 +2,7 @@
2
2
  // Licensed under the Apache License Version 2.0 that can be found in the
3
3
  // LICENSE file in the root directory of this source tree.
4
4
  import { hydrate } from './hydrate.js';
5
- import { commitMainThreadPatchUpdate } from './lifecycle/patchUpdate.js';
5
+ import { commitMainThreadPatchUpdate } from './lifecycle/patch/updateMainThread.js';
6
6
  import type { SnapshotInstance } from './snapshot.js';
7
7
 
8
8
  export interface ListUpdateInfo {
@@ -223,8 +223,17 @@ export const __pendingListUpdates = {
223
223
  },
224
224
  };
225
225
 
226
- const gSignMap: Record<number, Map<number, SnapshotInstance>> = {};
227
- const gRecycleMap: Record<number, Map<string, Map<number, SnapshotInstance>>> = {};
226
+ export const gSignMap: Record<number, Map<number, SnapshotInstance>> = {};
227
+ export const gRecycleMap: Record<number, Map<string, Map<number, SnapshotInstance>>> = {};
228
+
229
+ export function clearListGlobal(): void {
230
+ for (const key in gSignMap) {
231
+ delete gSignMap[key];
232
+ }
233
+ for (const key in gRecycleMap) {
234
+ delete gRecycleMap[key];
235
+ }
236
+ }
228
237
 
229
238
  export function componentAtIndexFactory(ctx: SnapshotInstance[]): ComponentAtIndexCallback {
230
239
  const componentAtIndex = (
@@ -13,8 +13,51 @@ import { renderMainThread } from '../lifecycle/render.js';
13
13
  import { hydrate } from '../hydrate.js';
14
14
  import { markTiming, PerformanceTimingKeys, setPipeline } from './performance.js';
15
15
  import { __pendingListUpdates } from '../list.js';
16
+ import { ssrHydrateByOpcodes } from '../opcodes.js';
17
+
18
+ function ssrEncode() {
19
+ const { __opcodes } = __root;
20
+ delete __root.__opcodes;
21
+
22
+ const oldToJSON = SnapshotInstance.prototype.toJSON;
23
+ SnapshotInstance.prototype.toJSON = function(this: SnapshotInstance): any {
24
+ return [
25
+ this.type,
26
+ this.__id,
27
+ this.__elements,
28
+ ];
29
+ };
30
+
31
+ try {
32
+ return JSON.stringify({ __opcodes, __root_values: __root.__values });
33
+ } finally {
34
+ SnapshotInstance.prototype.toJSON = oldToJSON;
35
+ }
36
+ }
37
+
38
+ function ssrHydrate(info: string) {
39
+ const nativePage = __GetPageElement();
40
+ if (!nativePage) {
41
+ throw new Error('SSR Hydration Failed! Please check if the SSR content loaded successfully!');
42
+ }
43
+
44
+ const refsMap = __GetTemplateParts(nativePage);
45
+
46
+ const { __opcodes, __root_values } = JSON.parse(info);
47
+ __root_values && __root.setAttribute('values', __root_values);
48
+ ssrHydrateByOpcodes(__opcodes, __root as SnapshotInstance, refsMap);
49
+
50
+ (__root as SnapshotInstance).__elements = [nativePage];
51
+ (__root as SnapshotInstance).__element_root = nativePage;
52
+ }
16
53
 
17
54
  function injectCalledByNative(): void {
55
+ if (process.env['NODE_ENV'] !== 'test') {
56
+ if (__FIRST_SCREEN_SYNC_TIMING__ !== 'jsReady' && __ENABLE_SSR__) {
57
+ throw new Error('`firstScreenSyncTiming` must be `jsReady` when SSR is enabled');
58
+ }
59
+ }
60
+
18
61
  const calledByNative: LynxCallByNative = {
19
62
  renderPage,
20
63
  updatePage,
@@ -23,9 +66,13 @@ function injectCalledByNative(): void {
23
66
  return null;
24
67
  },
25
68
  removeComponents: function(): void {},
69
+ ...(__ENABLE_SSR__ ? { ssrEncode, ssrHydrate } : {}),
26
70
  };
27
71
 
28
72
  Object.assign(globalThis, calledByNative);
73
+ Object.assign(globalThis, {
74
+ [LifecycleConstant.jsReady]: jsReady,
75
+ });
29
76
  }
30
77
 
31
78
  function renderPage(data: any): void {
@@ -46,10 +93,6 @@ function renderPage(data: any): void {
46
93
 
47
94
  if (__FIRST_SCREEN_SYNC_TIMING__ === 'immediately') {
48
95
  jsReady();
49
- } else {
50
- Object.assign(globalThis, {
51
- [LifecycleConstant.jsReady]: jsReady,
52
- });
53
96
  }
54
97
  }
55
98
 
@@ -4,7 +4,7 @@
4
4
  import { Component } from 'preact';
5
5
 
6
6
  import { PerfSpecificKey, PerformanceTimingKeys, markTimingLegacy } from './performance.js';
7
- import { globalFlushOptions } from '../lifecycle/patchUpdate.js';
7
+ import { globalFlushOptions } from '../lifecycle/patch/commit.js';
8
8
  import { NEXT_STATE } from '../renderToOpcodes/constants.js';
9
9
 
10
10
  if (__JS__) {
@@ -91,7 +91,7 @@ if (__JS__) {
91
91
 
92
92
  __Component.prototype.GlobalEventEmitter = lynxCoreInject.tt.GlobalEventEmitter;
93
93
 
94
- __Component.prototype.createSelectorQuery = function(...args: any[]) {
94
+ __Component.prototype.createSelectorQuery = function() {
95
95
  if (!__DISABLE_CREATE_SELECTOR_QUERY_INCOMPATIBLE_WARNING__) {
96
96
  lynx.reportError(
97
97
  new Error(
@@ -99,7 +99,7 @@ if (__JS__) {
99
99
  ),
100
100
  );
101
101
  }
102
- return lynx.createSelectorQuery(...args);
102
+ return lynx.createSelectorQuery();
103
103
  };
104
104
 
105
105
  const oldSetState = __Component.prototype.setState;
@@ -12,12 +12,11 @@ export function loadDynamicJS<T>(url: string): Promise<T> {
12
12
  return Promise.reject();
13
13
  }
14
14
  return new Promise((resolve, reject) => {
15
- // @ts-ignore
16
- lynx.requireModuleAsync(url, (err, data) => {
15
+ lynx.requireModuleAsync<T>(url, (err, data) => {
17
16
  if (err) {
18
17
  reject(err);
19
18
  } else {
20
- resolve(data);
19
+ resolve(data as T);
21
20
  }
22
21
  });
23
22
  });
@@ -94,8 +94,8 @@ export function setupLynxEnv(): void {
94
94
  }
95
95
  }
96
96
 
97
- if (processorName) {
98
- } else {
97
+ if (processorName) {}
98
+ else {
99
99
  hasDefaultDataProcessorExecuted = true;
100
100
  }
101
101
 
@@ -96,7 +96,7 @@ export function loadLazyBundle<
96
96
  if (typeof lynx.QueryComponent === 'function') {
97
97
  lynx.QueryComponent(source, callback);
98
98
  } else {
99
- lynx.getNativeLynx().QueryComponent(source, callback);
99
+ lynx.getNativeLynx().QueryComponent!(source, callback);
100
100
  }
101
101
  });
102
102
  }
@@ -3,8 +3,9 @@
3
3
  // LICENSE file in the root directory of this source tree.
4
4
  import { options } from 'preact';
5
5
  import type { VNode } from 'preact';
6
+
6
7
  import { DIFF } from '../renderToOpcodes/constants.js';
7
- import { __globalSnapshotPatch } from '../snapshotPatch.js';
8
+ import { __globalSnapshotPatch } from '../lifecycle/patch/snapshotPatch.js';
8
9
 
9
10
  enum PerformanceTimingKeys {
10
11
  update_set_state_trigger,
@@ -61,7 +62,7 @@ function markTimingLegacy(key: PerformanceTimingKeys, timingFlag_?: string): voi
61
62
  break;
62
63
  }
63
64
  }
64
- lynx.getNativeApp().markTiming?.(timingFlag, PerformanceTimingKeys[key]);
65
+ lynx.getNativeApp().markTiming?.(timingFlag!, PerformanceTimingKeys[key]);
65
66
  }
66
67
 
67
68
  function beginPipeline(needTimestamps: boolean, timingFlag?: string): void {