@lynx-js/react 0.109.2 → 0.110.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/package.json +1 -1
- package/refresh/.turbo/turbo-build.log +1 -1
- package/runtime/lib/backgroundSnapshot.d.ts +2 -1
- package/runtime/lib/backgroundSnapshot.js +65 -42
- package/runtime/lib/backgroundSnapshot.js.map +1 -1
- package/runtime/lib/hooks/react.js +3 -3
- package/runtime/lib/hooks/react.js.map +1 -1
- package/runtime/lib/lifecycle/destroy.js +1 -0
- package/runtime/lib/lifecycle/destroy.js.map +1 -1
- package/runtime/lib/lifecycle/event/delayEvents.js +3 -0
- package/runtime/lib/lifecycle/event/delayEvents.js.map +1 -1
- package/runtime/lib/lifecycle/event/delayLifecycleEvents.d.ts +3 -2
- package/runtime/lib/lifecycle/event/delayLifecycleEvents.js +1 -12
- package/runtime/lib/lifecycle/event/delayLifecycleEvents.js.map +1 -1
- package/runtime/lib/lifecycle/event/jsReady.d.ts +1 -1
- package/runtime/lib/lifecycle/event/jsReady.js +3 -2
- package/runtime/lib/lifecycle/event/jsReady.js.map +1 -1
- package/runtime/lib/lifecycle/patch/commit.d.ts +0 -2
- package/runtime/lib/lifecycle/patch/commit.js +8 -36
- package/runtime/lib/lifecycle/patch/commit.js.map +1 -1
- package/runtime/lib/lifecycle/patch/error.d.ts +8 -0
- package/runtime/lib/lifecycle/patch/error.js +47 -0
- package/runtime/lib/lifecycle/patch/error.js.map +1 -0
- package/runtime/lib/lifecycle/patch/isMainThreadHydrationFinished.js +3 -0
- package/runtime/lib/lifecycle/patch/isMainThreadHydrationFinished.js.map +1 -1
- package/runtime/lib/lifecycle/patch/snapshotPatch.d.ts +2 -2
- package/runtime/lib/lifecycle/patch/snapshotPatch.js.map +1 -1
- package/runtime/lib/lifecycle/patch/snapshotPatchApply.js +10 -10
- package/runtime/lib/lifecycle/patch/snapshotPatchApply.js.map +1 -1
- package/runtime/lib/lifecycle/patch/updateMainThread.d.ts +0 -1
- package/runtime/lib/lifecycle/patch/updateMainThread.js +6 -13
- package/runtime/lib/lifecycle/patch/updateMainThread.js.map +1 -1
- package/runtime/lib/lifecycle/ref/delay.d.ts +31 -0
- package/runtime/lib/lifecycle/ref/delay.js +80 -0
- package/runtime/lib/lifecycle/ref/delay.js.map +1 -0
- package/runtime/lib/lifecycle/reload.d.ts +1 -1
- package/runtime/lib/lifecycle/reload.js +7 -4
- package/runtime/lib/lifecycle/reload.js.map +1 -1
- package/runtime/lib/lifecycle/render.js +3 -2
- package/runtime/lib/lifecycle/render.js.map +1 -1
- package/runtime/lib/lifecycleConstant.d.ts +10 -7
- package/runtime/lib/lifecycleConstant.js +8 -8
- package/runtime/lib/lifecycleConstant.js.map +1 -1
- package/runtime/lib/list.d.ts +1 -1
- package/runtime/lib/list.js +9 -7
- package/runtime/lib/list.js.map +1 -1
- package/runtime/lib/lynx/calledByNative.js +8 -5
- package/runtime/lib/lynx/calledByNative.js.map +1 -1
- package/runtime/lib/lynx/component.js +7 -0
- package/runtime/lib/lynx/component.js.map +1 -1
- package/runtime/lib/lynx/dynamic-js.d.ts +5 -1
- package/runtime/lib/lynx/dynamic-js.js +1 -0
- package/runtime/lib/lynx/dynamic-js.js.map +1 -1
- package/runtime/lib/lynx/env.d.ts +1 -1
- package/runtime/lib/lynx/env.js +13 -13
- package/runtime/lib/lynx/env.js.map +1 -1
- package/runtime/lib/lynx/lazy-bundle.js +7 -5
- package/runtime/lib/lynx/lazy-bundle.js.map +1 -1
- package/runtime/lib/lynx/performance.js +1 -1
- package/runtime/lib/lynx/performance.js.map +1 -1
- package/runtime/lib/lynx/runWithForce.js +3 -0
- package/runtime/lib/lynx/runWithForce.js.map +1 -1
- package/runtime/lib/lynx/tt.js +12 -33
- package/runtime/lib/lynx/tt.js.map +1 -1
- package/runtime/lib/lynx-api.d.ts +1 -1
- package/runtime/lib/lynx.js +5 -6
- package/runtime/lib/lynx.js.map +1 -1
- package/runtime/lib/snapshot/ref.d.ts +14 -9
- package/runtime/lib/snapshot/ref.js +64 -73
- package/runtime/lib/snapshot/ref.js.map +1 -1
- package/runtime/lib/snapshot/spread.js +9 -8
- package/runtime/lib/snapshot/spread.js.map +1 -1
- package/runtime/lib/snapshot/workletRef.d.ts +3 -3
- package/runtime/lib/snapshot/workletRef.js +27 -8
- package/runtime/lib/snapshot/workletRef.js.map +1 -1
- package/runtime/lib/snapshot.d.ts +4 -4
- package/runtime/lib/snapshot.js +28 -13
- package/runtime/lib/snapshot.js.map +1 -1
- package/runtime/lib/snapshotInstanceHydrationMap.d.ts +9 -0
- package/runtime/lib/snapshotInstanceHydrationMap.js +16 -0
- package/runtime/lib/snapshotInstanceHydrationMap.js.map +1 -0
- package/runtime/lib/worklet/workletRef.js +1 -2
- package/runtime/lib/worklet/workletRef.js.map +1 -1
- package/runtime/src/backgroundSnapshot.ts +74 -47
- package/runtime/src/hooks/react.ts +3 -3
- package/runtime/src/lifecycle/destroy.ts +1 -0
- package/runtime/src/lifecycle/event/delayEvents.ts +3 -0
- package/runtime/src/lifecycle/event/delayLifecycleEvents.ts +7 -13
- package/runtime/src/lifecycle/event/jsReady.ts +4 -3
- package/runtime/src/lifecycle/patch/commit.ts +10 -41
- package/runtime/src/lifecycle/patch/error.ts +61 -0
- package/runtime/src/lifecycle/patch/isMainThreadHydrationFinished.ts +3 -0
- package/runtime/src/lifecycle/patch/snapshotPatch.ts +2 -2
- package/runtime/src/lifecycle/patch/snapshotPatchApply.ts +28 -28
- package/runtime/src/lifecycle/patch/updateMainThread.ts +7 -16
- package/runtime/src/lifecycle/ref/delay.ts +99 -0
- package/runtime/src/lifecycle/reload.ts +9 -6
- package/runtime/src/lifecycle/render.ts +3 -2
- package/runtime/src/lifecycleConstant.ts +11 -7
- package/runtime/src/list.ts +9 -7
- package/runtime/src/lynx/calledByNative.ts +14 -9
- package/runtime/src/lynx/component.ts +9 -0
- package/runtime/src/lynx/dynamic-js.ts +5 -1
- package/runtime/src/lynx/env.ts +17 -17
- package/runtime/src/lynx/lazy-bundle.ts +22 -14
- package/runtime/src/lynx/performance.ts +1 -1
- package/runtime/src/lynx/runWithForce.ts +9 -5
- package/runtime/src/lynx/tt.ts +19 -37
- package/runtime/src/lynx-api.ts +1 -1
- package/runtime/src/lynx.ts +6 -6
- package/runtime/src/snapshot/ref.ts +77 -87
- package/runtime/src/snapshot/spread.ts +8 -8
- package/runtime/src/snapshot/workletRef.ts +35 -9
- package/runtime/src/snapshot.ts +39 -20
- package/runtime/src/snapshotInstanceHydrationMap.ts +17 -0
- package/runtime/src/worklet/workletRef.ts +1 -2
- package/testing-library/dist/env/vitest.js +5 -3
- package/testing-library/dist/pure.js +4 -3
- package/transform/dist/wasm.cjs +1 -1
- package/worklet-runtime/dist/dev.js +1 -4
- package/worklet-runtime/dist/main.js +0 -3
- package/worklet-runtime/lib/bindings/observers.d.ts +14 -1
- package/worklet-runtime/lib/bindings/observers.js +7 -7
- package/worklet-runtime/lib/bindings/observers.js.map +1 -1
- package/worklet-runtime/lib/hydrate.js +0 -5
- package/worklet-runtime/lib/hydrate.js.map +1 -1
- package/runtime/lib/lifecycle/delayUnmount.d.ts +0 -8
- package/runtime/lib/lifecycle/delayUnmount.js +0 -65
- package/runtime/lib/lifecycle/delayUnmount.js.map +0 -1
- package/runtime/src/lifecycle/delayUnmount.ts +0 -77
|
@@ -1,3 +1,6 @@
|
|
|
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.
|
|
1
4
|
import { onHydrationFinished } from '@lynx-js/react/worklet-runtime/bindings';
|
|
2
5
|
|
|
3
6
|
export let isMainThreadHydrationFinished = false;
|
|
@@ -42,9 +42,9 @@ export const enum SnapshotOperation {
|
|
|
42
42
|
// fn: string,
|
|
43
43
|
// ]
|
|
44
44
|
|
|
45
|
-
export type SnapshotPatch =
|
|
45
|
+
export type SnapshotPatch = unknown[];
|
|
46
46
|
|
|
47
|
-
export let __globalSnapshotPatch:
|
|
47
|
+
export let __globalSnapshotPatch: SnapshotPatch | undefined;
|
|
48
48
|
|
|
49
49
|
export function takeGlobalSnapshotPatch(): SnapshotPatch | undefined {
|
|
50
50
|
if (__globalSnapshotPatch) {
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* order and with proper error handling.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { sendCtxNotFoundEventToBackground } from './error.js';
|
|
17
|
+
import type { SnapshotPatch } from './snapshotPatch.js';
|
|
18
|
+
import { SnapshotOperation } from './snapshotPatch.js';
|
|
16
19
|
import {
|
|
17
20
|
SnapshotInstance,
|
|
18
21
|
createSnapshot,
|
|
@@ -20,12 +23,7 @@ import {
|
|
|
20
23
|
snapshotInstanceManager,
|
|
21
24
|
snapshotManager,
|
|
22
25
|
} from '../../snapshot.js';
|
|
23
|
-
import type {
|
|
24
|
-
import { SnapshotOperation } from './snapshotPatch.js';
|
|
25
|
-
|
|
26
|
-
function reportCtxNotFound(): void {
|
|
27
|
-
lynx.reportError(new Error(`snapshotPatchApply failed: ctx not found`));
|
|
28
|
-
}
|
|
26
|
+
import type { DynamicPartType } from '../../snapshot.js';
|
|
29
27
|
|
|
30
28
|
/**
|
|
31
29
|
* Applies a patch of snapshot operations to the main thread.
|
|
@@ -37,68 +35,68 @@ export function snapshotPatchApply(snapshotPatch: SnapshotPatch): void {
|
|
|
37
35
|
for (let i = 0; i < length; ++i) {
|
|
38
36
|
switch (snapshotPatch[i]) {
|
|
39
37
|
case SnapshotOperation.CreateElement: {
|
|
40
|
-
const type = snapshotPatch[++i];
|
|
41
|
-
const id = snapshotPatch[++i];
|
|
38
|
+
const type = snapshotPatch[++i] as string;
|
|
39
|
+
const id = snapshotPatch[++i] as number;
|
|
42
40
|
new SnapshotInstance(type, id);
|
|
43
41
|
break;
|
|
44
42
|
}
|
|
45
43
|
case SnapshotOperation.InsertBefore: {
|
|
46
|
-
const parentId = snapshotPatch[++i];
|
|
47
|
-
const childId = snapshotPatch[++i];
|
|
48
|
-
const beforeId = snapshotPatch[++i];
|
|
44
|
+
const parentId = snapshotPatch[++i] as number;
|
|
45
|
+
const childId = snapshotPatch[++i] as number;
|
|
46
|
+
const beforeId = snapshotPatch[++i] as number | undefined;
|
|
49
47
|
const parent = snapshotInstanceManager.values.get(parentId);
|
|
50
48
|
const child = snapshotInstanceManager.values.get(childId);
|
|
51
|
-
const existingNode = snapshotInstanceManager.values.get(beforeId);
|
|
49
|
+
const existingNode = snapshotInstanceManager.values.get(beforeId!);
|
|
52
50
|
if (!parent || !child) {
|
|
53
|
-
|
|
51
|
+
sendCtxNotFoundEventToBackground(parent ? childId : parentId);
|
|
54
52
|
} else {
|
|
55
53
|
parent.insertBefore(child, existingNode);
|
|
56
54
|
}
|
|
57
55
|
break;
|
|
58
56
|
}
|
|
59
57
|
case SnapshotOperation.RemoveChild: {
|
|
60
|
-
const parentId = snapshotPatch[++i];
|
|
61
|
-
const childId = snapshotPatch[++i];
|
|
58
|
+
const parentId = snapshotPatch[++i] as number;
|
|
59
|
+
const childId = snapshotPatch[++i] as number;
|
|
62
60
|
const parent = snapshotInstanceManager.values.get(parentId);
|
|
63
61
|
const child = snapshotInstanceManager.values.get(childId);
|
|
64
62
|
if (!parent || !child) {
|
|
65
|
-
|
|
63
|
+
sendCtxNotFoundEventToBackground(parent ? childId : parentId);
|
|
66
64
|
} else {
|
|
67
65
|
parent.removeChild(child);
|
|
68
66
|
}
|
|
69
67
|
break;
|
|
70
68
|
}
|
|
71
69
|
case SnapshotOperation.SetAttribute: {
|
|
72
|
-
const id = snapshotPatch[++i];
|
|
73
|
-
const dynamicPartIndex = snapshotPatch[++i];
|
|
70
|
+
const id = snapshotPatch[++i] as number;
|
|
71
|
+
const dynamicPartIndex = snapshotPatch[++i] as number;
|
|
74
72
|
const value = snapshotPatch[++i];
|
|
75
73
|
const si = snapshotInstanceManager.values.get(id);
|
|
76
74
|
if (si) {
|
|
77
75
|
si.setAttribute(dynamicPartIndex, value);
|
|
78
76
|
} else {
|
|
79
|
-
|
|
77
|
+
sendCtxNotFoundEventToBackground(id);
|
|
80
78
|
}
|
|
81
79
|
break;
|
|
82
80
|
}
|
|
83
81
|
case SnapshotOperation.SetAttributes: {
|
|
84
|
-
const id = snapshotPatch[++i];
|
|
82
|
+
const id = snapshotPatch[++i] as number;
|
|
85
83
|
const values = snapshotPatch[++i];
|
|
86
84
|
const si = snapshotInstanceManager.values.get(id);
|
|
87
85
|
if (si) {
|
|
88
86
|
si.setAttribute('values', values);
|
|
89
87
|
} else {
|
|
90
|
-
|
|
88
|
+
sendCtxNotFoundEventToBackground(id);
|
|
91
89
|
}
|
|
92
90
|
break;
|
|
93
91
|
}
|
|
94
92
|
case SnapshotOperation.DEV_ONLY_AddSnapshot: {
|
|
95
93
|
if (__DEV__) {
|
|
96
|
-
const uniqID
|
|
97
|
-
const create
|
|
98
|
-
const update
|
|
99
|
-
const slot = snapshotPatch[++i];
|
|
100
|
-
const cssId
|
|
101
|
-
const entryName
|
|
94
|
+
const uniqID = snapshotPatch[++i] as string;
|
|
95
|
+
const create = snapshotPatch[++i] as string;
|
|
96
|
+
const update = snapshotPatch[++i] as string[];
|
|
97
|
+
const slot = snapshotPatch[++i] as [DynamicPartType, number][];
|
|
98
|
+
const cssId = (snapshotPatch[++i] ?? 0) as number;
|
|
99
|
+
const entryName = snapshotPatch[++i] as string | undefined;
|
|
102
100
|
|
|
103
101
|
if (!snapshotManager.values.has(entryUniqID(uniqID, entryName))) {
|
|
104
102
|
// HMR-related
|
|
@@ -106,10 +104,12 @@ export function snapshotPatchApply(snapshotPatch: SnapshotPatch): void {
|
|
|
106
104
|
createSnapshot(
|
|
107
105
|
uniqID,
|
|
108
106
|
evaluate<(ctx: SnapshotInstance) => FiberElement[]>(create),
|
|
107
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
109
108
|
update.map<(ctx: SnapshotInstance, index: number, oldValue: any) => void>(evaluate),
|
|
110
109
|
slot,
|
|
111
110
|
cssId,
|
|
112
111
|
entryName,
|
|
112
|
+
null,
|
|
113
113
|
);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -138,7 +138,7 @@ function evaluate<T>(code: string): T {
|
|
|
138
138
|
if (__DEV__) {
|
|
139
139
|
// We are using `eval` here to make the updated snapshot to access variables like `__webpack_require__`.
|
|
140
140
|
// See: https://github.com/lynx-family/lynx-stack/issues/983.
|
|
141
|
-
return eval(`(() => ${code})()`);
|
|
141
|
+
return eval(`(() => ${code})()`) as T;
|
|
142
142
|
}
|
|
143
143
|
throw new Error('unreachable: evaluate is not supported in production');
|
|
144
144
|
}
|
|
@@ -4,16 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import { updateWorkletRefInitValueChanges } from '@lynx-js/react/worklet-runtime/bindings';
|
|
6
6
|
|
|
7
|
-
import type { PatchList, PatchOptions } from './commit.js';
|
|
8
|
-
import { snapshotPatchApply } from './snapshotPatchApply.js';
|
|
9
7
|
import { LifecycleConstant } from '../../lifecycleConstant.js';
|
|
10
8
|
import { __pendingListUpdates } from '../../list.js';
|
|
11
|
-
import {
|
|
12
|
-
import { takeGlobalRefPatchMap } from '../../snapshot/ref.js';
|
|
9
|
+
import { PerformanceTimingKeys, markTiming, setPipeline } from '../../lynx/performance.js';
|
|
13
10
|
import { __page } from '../../snapshot.js';
|
|
14
|
-
import { isEmptyObject } from '../../utils.js';
|
|
15
11
|
import { getReloadVersion } from '../pass.js';
|
|
12
|
+
import type { PatchList, PatchOptions } from './commit.js';
|
|
16
13
|
import { setMainThreadHydrationFinished } from './isMainThreadHydrationFinished.js';
|
|
14
|
+
import { snapshotPatchApply } from './snapshotPatchApply.js';
|
|
15
|
+
import { applyRefQueue } from '../../snapshot/workletRef.js';
|
|
17
16
|
|
|
18
17
|
function updateMainThread(
|
|
19
18
|
{ data, patchOptions }: {
|
|
@@ -33,7 +32,7 @@ function updateMainThread(
|
|
|
33
32
|
markTiming(PerformanceTimingKeys.parseChangesEnd);
|
|
34
33
|
markTiming(PerformanceTimingKeys.patchChangesStart);
|
|
35
34
|
|
|
36
|
-
for (const { snapshotPatch, workletRefInitValuePatch
|
|
35
|
+
for (const { snapshotPatch, workletRefInitValuePatch } of patchList) {
|
|
37
36
|
updateWorkletRefInitValueChanges(workletRefInitValuePatch);
|
|
38
37
|
__pendingListUpdates.clear();
|
|
39
38
|
if (snapshotPatch) {
|
|
@@ -42,14 +41,13 @@ function updateMainThread(
|
|
|
42
41
|
__pendingListUpdates.flush();
|
|
43
42
|
// console.debug('********** Lepus updatePatch:');
|
|
44
43
|
// printSnapshotInstance(snapshotInstanceManager.values.get(-1)!);
|
|
45
|
-
|
|
46
|
-
commitMainThreadPatchUpdate(id);
|
|
47
44
|
}
|
|
48
45
|
markTiming(PerformanceTimingKeys.patchChangesEnd);
|
|
49
46
|
markTiming(PerformanceTimingKeys.mtsRenderEnd);
|
|
50
47
|
if (patchOptions.isHydration) {
|
|
51
48
|
setMainThreadHydrationFinished(true);
|
|
52
49
|
}
|
|
50
|
+
applyRefQueue();
|
|
53
51
|
if (patchOptions.pipelineOptions) {
|
|
54
52
|
flushOptions.pipelineOptions = patchOptions.pipelineOptions;
|
|
55
53
|
}
|
|
@@ -61,14 +59,7 @@ function injectUpdateMainThread(): void {
|
|
|
61
59
|
Object.assign(globalThis, { [LifecycleConstant.patchUpdate]: updateMainThread });
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
function commitMainThreadPatchUpdate(commitTaskId?: number): void {
|
|
65
|
-
const refPatch = takeGlobalRefPatchMap();
|
|
66
|
-
if (!isEmptyObject(refPatch)) {
|
|
67
|
-
__OnLifecycleEvent([LifecycleConstant.ref, { commitTaskId, refPatch: JSON.stringify(refPatch) }]);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
62
|
/**
|
|
72
63
|
* @internal
|
|
73
64
|
*/
|
|
74
|
-
export {
|
|
65
|
+
export { injectUpdateMainThread };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Copyright 2024 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 type { NodesRef, SelectorQuery } from '@lynx-js/types';
|
|
6
|
+
|
|
7
|
+
import { hydrationMap } from '../../snapshotInstanceHydrationMap.js';
|
|
8
|
+
|
|
9
|
+
type RefTask = (nodesRef: NodesRef) => SelectorQuery;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A flag to indicate whether UI operations should be delayed.
|
|
13
|
+
* When set to true, UI operations will be queued in the `delayedUiOps` array
|
|
14
|
+
* and executed later when `runDelayedUiOps` is called.
|
|
15
|
+
* This is used before hydration to ensure UI operations are batched
|
|
16
|
+
* and executed at the appropriate time.
|
|
17
|
+
*/
|
|
18
|
+
const shouldDelayUiOps = { value: true };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* An array of functions that will be executed later when `runDelayedUiOps` is called.
|
|
22
|
+
* These functions contain UI operations that need to be delayed.
|
|
23
|
+
*/
|
|
24
|
+
const delayedUiOps: (() => void)[] = [];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Runs a task either immediately or delays it based on the `shouldDelayUiOps` flag.
|
|
28
|
+
* @param task - The function to execute.
|
|
29
|
+
*/
|
|
30
|
+
function runOrDelay(task: () => void): void {
|
|
31
|
+
if (shouldDelayUiOps.value) {
|
|
32
|
+
delayedUiOps.push(task);
|
|
33
|
+
} else {
|
|
34
|
+
task();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Executes all delayed UI operations.
|
|
40
|
+
*/
|
|
41
|
+
function runDelayedUiOps(): void {
|
|
42
|
+
for (const task of delayedUiOps) {
|
|
43
|
+
task();
|
|
44
|
+
}
|
|
45
|
+
shouldDelayUiOps.value = false;
|
|
46
|
+
delayedUiOps.length = 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A proxy class designed for managing and executing reference-based tasks.
|
|
51
|
+
* It delays the execution of tasks until hydration is complete.
|
|
52
|
+
*/
|
|
53
|
+
class RefProxy {
|
|
54
|
+
private readonly refAttr: [snapshotInstanceId: number, expIndex: number];
|
|
55
|
+
private task: RefTask | undefined;
|
|
56
|
+
|
|
57
|
+
constructor(refAttr: [snapshotInstanceId: number, expIndex: number]) {
|
|
58
|
+
this.refAttr = refAttr;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private setTask<K extends keyof NodesRef>(
|
|
62
|
+
method: K,
|
|
63
|
+
args: Parameters<NodesRef[K]>,
|
|
64
|
+
): this {
|
|
65
|
+
this.task = (nodesRef) => {
|
|
66
|
+
return (nodesRef[method] as unknown as (...args: any[]) => SelectorQuery)(...args);
|
|
67
|
+
};
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
invoke(...args: Parameters<NodesRef['invoke']>): RefProxy {
|
|
72
|
+
return new RefProxy(this.refAttr).setTask('invoke', args);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
path(...args: Parameters<NodesRef['path']>): RefProxy {
|
|
76
|
+
return new RefProxy(this.refAttr).setTask('path', args);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fields(...args: Parameters<NodesRef['fields']>): RefProxy {
|
|
80
|
+
return new RefProxy(this.refAttr).setTask('fields', args);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
setNativeProps(...args: Parameters<NodesRef['setNativeProps']>): RefProxy {
|
|
84
|
+
return new RefProxy(this.refAttr).setTask('setNativeProps', args);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
exec(): void {
|
|
88
|
+
runOrDelay(() => {
|
|
89
|
+
const realRefId = hydrationMap.get(this.refAttr[0]) ?? this.refAttr[0];
|
|
90
|
+
const refSelector = `[react-ref-${realRefId}-${this.refAttr[1]}]`;
|
|
91
|
+
this.task!(lynx.createSelectorQuery().select(refSelector)).exec();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
export { RefProxy, runDelayedUiOps, shouldDelayUiOps };
|
|
@@ -13,25 +13,26 @@ import { hydrate } from '../hydrate.js';
|
|
|
13
13
|
import { LifecycleConstant } from '../lifecycleConstant.js';
|
|
14
14
|
import { __pendingListUpdates } from '../list.js';
|
|
15
15
|
import { __root, setRoot } from '../root.js';
|
|
16
|
+
import { destroyBackground } from './destroy.js';
|
|
17
|
+
import { applyRefQueue } from '../snapshot/workletRef.js';
|
|
16
18
|
import { SnapshotInstance, __page, snapshotInstanceManager } from '../snapshot.js';
|
|
17
|
-
import { takeGlobalRefPatchMap } from '../snapshot/ref.js';
|
|
18
19
|
import { isEmptyObject } from '../utils.js';
|
|
19
20
|
import { destroyWorklet } from '../worklet/destroy.js';
|
|
20
|
-
import { destroyBackground } from './destroy.js';
|
|
21
21
|
import { clearJSReadyEventIdSwap, isJSReady } from './event/jsReady.js';
|
|
22
22
|
import { increaseReloadVersion } from './pass.js';
|
|
23
|
+
import { setMainThreadHydrationFinished } from './patch/isMainThreadHydrationFinished.js';
|
|
23
24
|
import { deinitGlobalSnapshotPatch } from './patch/snapshotPatch.js';
|
|
25
|
+
import { shouldDelayUiOps } from './ref/delay.js';
|
|
24
26
|
import { renderMainThread } from './render.js';
|
|
25
|
-
import { setMainThreadHydrationFinished } from './patch/isMainThreadHydrationFinished.js';
|
|
26
27
|
|
|
27
|
-
function reloadMainThread(data:
|
|
28
|
+
function reloadMainThread(data: unknown, options: UpdatePageOption): void {
|
|
28
29
|
if (__PROFILE__) {
|
|
29
30
|
console.profile('reloadTemplate');
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
increaseReloadVersion();
|
|
33
34
|
|
|
34
|
-
if (typeof data == 'object' && !isEmptyObject(data)) {
|
|
35
|
+
if (typeof data == 'object' && !isEmptyObject(data as Record<string, unknown>)) {
|
|
35
36
|
Object.assign(lynx.__initData, data);
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -51,13 +52,13 @@ function reloadMainThread(data: any, options: UpdatePageOption): void {
|
|
|
51
52
|
|
|
52
53
|
// always call this before `__FlushElementTree`
|
|
53
54
|
__pendingListUpdates.flush();
|
|
55
|
+
applyRefQueue();
|
|
54
56
|
|
|
55
57
|
if (isJSReady) {
|
|
56
58
|
__OnLifecycleEvent([
|
|
57
59
|
LifecycleConstant.firstScreen, /* FIRST_SCREEN */
|
|
58
60
|
{
|
|
59
61
|
root: JSON.stringify(__root),
|
|
60
|
-
refPatch: JSON.stringify(takeGlobalRefPatchMap()),
|
|
61
62
|
},
|
|
62
63
|
]);
|
|
63
64
|
}
|
|
@@ -84,6 +85,8 @@ function reloadBackground(updateData: Record<string, any>): void {
|
|
|
84
85
|
// COW when modify `lynx.__initData` to make sure Provider & Consumer works
|
|
85
86
|
lynx.__initData = Object.assign({}, lynx.__initData, updateData);
|
|
86
87
|
|
|
88
|
+
shouldDelayUiOps.value = true;
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
87
90
|
render(__root.__jsx, __root as any);
|
|
88
91
|
|
|
89
92
|
if (__PROFILE__) {
|
|
@@ -18,6 +18,7 @@ function renderMainThread(): void {
|
|
|
18
18
|
process.env['NODE_ENV'] === 'test' && typeof __TESTING_FORCE_RENDER_TO_OPCODE__ !== 'undefined'
|
|
19
19
|
&& !__TESTING_FORCE_RENDER_TO_OPCODE__
|
|
20
20
|
) {
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
21
22
|
render(__root.__jsx, __root as any);
|
|
22
23
|
} else {
|
|
23
24
|
let opcodes;
|
|
@@ -25,8 +26,7 @@ function renderMainThread(): void {
|
|
|
25
26
|
if (__PROFILE__) {
|
|
26
27
|
console.profile('renderToString');
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
opcodes = renderToString(__root.__jsx);
|
|
29
|
+
opcodes = renderToString(__root.__jsx, undefined);
|
|
30
30
|
} catch (e) {
|
|
31
31
|
lynx.reportError(e as Error);
|
|
32
32
|
opcodes = [];
|
|
@@ -39,6 +39,7 @@ function renderMainThread(): void {
|
|
|
39
39
|
if (__PROFILE__) {
|
|
40
40
|
console.profile('renderOpcodesInto');
|
|
41
41
|
}
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
42
43
|
renderOpcodesInto(opcodes, __root as any);
|
|
43
44
|
if (__ENABLE_SSR__) {
|
|
44
45
|
__root.__opcodes = opcodes;
|
|
@@ -1,13 +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
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
export const enum LifecycleConstant {
|
|
5
|
+
firstScreen = 'rLynxFirstScreen',
|
|
6
|
+
updateFromRoot = 'updateFromRoot',
|
|
7
|
+
globalEventFromLepus = 'globalEventFromLepus',
|
|
8
|
+
jsReady = 'rLynxJSReady',
|
|
9
|
+
patchUpdate = 'rLynxChange',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface FirstScreenData {
|
|
13
|
+
root: string;
|
|
14
|
+
jsReadyEventIdSwap: Record<string | number, number>;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
export const enum NativeUpdateDataType {
|
package/runtime/src/list.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
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 {
|
|
6
|
-
import type
|
|
5
|
+
import { applyRefQueue } from './snapshot/workletRef.js';
|
|
6
|
+
import { type SnapshotInstance } from './snapshot.js';
|
|
7
7
|
|
|
8
8
|
export interface ListUpdateInfo {
|
|
9
9
|
flush(): void;
|
|
@@ -294,10 +294,9 @@ export function componentAtIndexFactory(
|
|
|
294
294
|
__FlushElementTree(root, { triggerLayout: true, operationID, elementID: sign, listID });
|
|
295
295
|
} else if (enableBatchRender && asyncFlush) {
|
|
296
296
|
__FlushElementTree(root, { asyncFlush: true });
|
|
297
|
-
} else {
|
|
298
|
-
// enableBatchRender == true && asyncFlush == false
|
|
299
|
-
// in this case, no need to invoke __FlushElementTree because in the end of componentAtIndexes(), the list will invoke __FlushElementTree.
|
|
300
297
|
}
|
|
298
|
+
// enableBatchRender == true && asyncFlush == false
|
|
299
|
+
// in this case, no need to invoke __FlushElementTree because in the end of componentAtIndexes(), the list will invoke __FlushElementTree.
|
|
301
300
|
return sign;
|
|
302
301
|
} else {
|
|
303
302
|
const newCtx = childCtx.takeElements();
|
|
@@ -311,7 +310,11 @@ export function componentAtIndexFactory(
|
|
|
311
310
|
recycleSignMap.delete(sign);
|
|
312
311
|
hydrate(oldCtx, childCtx);
|
|
313
312
|
oldCtx.unRenderElements();
|
|
313
|
+
if (!oldCtx.__id) {
|
|
314
|
+
oldCtx.tearDown();
|
|
315
|
+
}
|
|
314
316
|
const root = childCtx.__element_root!;
|
|
317
|
+
applyRefQueue();
|
|
315
318
|
if (!enableBatchRender) {
|
|
316
319
|
const flushOptions: FlushOptions = {
|
|
317
320
|
triggerLayout: true,
|
|
@@ -339,7 +342,6 @@ export function componentAtIndexFactory(
|
|
|
339
342
|
__FlushElementTree(root, flushOptions);
|
|
340
343
|
}
|
|
341
344
|
signMap.set(sign, childCtx);
|
|
342
|
-
commitMainThreadPatchUpdate(undefined);
|
|
343
345
|
return sign;
|
|
344
346
|
}
|
|
345
347
|
|
|
@@ -347,6 +349,7 @@ export function componentAtIndexFactory(
|
|
|
347
349
|
const root = childCtx.__element_root!;
|
|
348
350
|
__AppendElement(list, root);
|
|
349
351
|
const sign = __GetElementUniqueID(root);
|
|
352
|
+
applyRefQueue();
|
|
350
353
|
if (!enableBatchRender) {
|
|
351
354
|
__FlushElementTree(root, {
|
|
352
355
|
triggerLayout: true,
|
|
@@ -360,7 +363,6 @@ export function componentAtIndexFactory(
|
|
|
360
363
|
});
|
|
361
364
|
}
|
|
362
365
|
signMap.set(sign, childCtx);
|
|
363
|
-
commitMainThreadPatchUpdate(undefined);
|
|
364
366
|
return sign;
|
|
365
367
|
};
|
|
366
368
|
|
|
@@ -9,15 +9,16 @@ import { LifecycleConstant } from '../lifecycleConstant.js';
|
|
|
9
9
|
import { __pendingListUpdates } from '../list.js';
|
|
10
10
|
import { ssrHydrateByOpcodes } from '../opcodes.js';
|
|
11
11
|
import { __root, setRoot } from '../root.js';
|
|
12
|
-
import { takeGlobalRefPatchMap } from '../snapshot/ref.js';
|
|
13
12
|
import { SnapshotInstance, __page, setupPage } from '../snapshot.js';
|
|
14
13
|
import { isEmptyObject } from '../utils.js';
|
|
15
14
|
import { PerformanceTimingKeys, markTiming, setPipeline } from './performance.js';
|
|
15
|
+
import { applyRefQueue } from '../snapshot/workletRef.js';
|
|
16
16
|
|
|
17
17
|
function ssrEncode() {
|
|
18
18
|
const { __opcodes } = __root;
|
|
19
19
|
delete __root.__opcodes;
|
|
20
20
|
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
21
22
|
const oldToJSON = SnapshotInstance.prototype.toJSON;
|
|
22
23
|
SnapshotInstance.prototype.toJSON = function(this: SnapshotInstance): any {
|
|
23
24
|
return [
|
|
@@ -44,8 +45,13 @@ function ssrHydrate(info: string) {
|
|
|
44
45
|
setupPage(nativePage);
|
|
45
46
|
const refsMap = __GetTemplateParts(nativePage);
|
|
46
47
|
|
|
47
|
-
const { __opcodes, __root_values } = JSON.parse(info)
|
|
48
|
-
|
|
48
|
+
const { __opcodes, __root_values } = JSON.parse(info) as {
|
|
49
|
+
__opcodes: unknown[];
|
|
50
|
+
__root_values: unknown[] | undefined;
|
|
51
|
+
};
|
|
52
|
+
if (__root_values) {
|
|
53
|
+
__root.setAttribute('values', __root_values);
|
|
54
|
+
}
|
|
49
55
|
ssrHydrateByOpcodes(__opcodes, __root as SnapshotInstance, refsMap);
|
|
50
56
|
|
|
51
57
|
(__root as SnapshotInstance).__elements = [nativePage];
|
|
@@ -74,11 +80,11 @@ function injectCalledByNative(): void {
|
|
|
74
80
|
});
|
|
75
81
|
}
|
|
76
82
|
|
|
77
|
-
function renderPage(data:
|
|
83
|
+
function renderPage(data: Record<string, unknown> | undefined): void {
|
|
78
84
|
// reset `jsReady` state
|
|
79
85
|
resetJSReady();
|
|
80
86
|
|
|
81
|
-
lynx.__initData = data
|
|
87
|
+
lynx.__initData = data ?? {};
|
|
82
88
|
|
|
83
89
|
setupPage(__CreatePage('0', 0));
|
|
84
90
|
(__root as SnapshotInstance).ensureElements();
|
|
@@ -88,13 +94,14 @@ function renderPage(data: any): void {
|
|
|
88
94
|
// always call this before `__FlushElementTree`
|
|
89
95
|
// (There is an implicit `__FlushElementTree` in `renderPage`)
|
|
90
96
|
__pendingListUpdates.flush();
|
|
97
|
+
applyRefQueue();
|
|
91
98
|
|
|
92
99
|
if (__FIRST_SCREEN_SYNC_TIMING__ === 'immediately') {
|
|
93
100
|
jsReady();
|
|
94
101
|
}
|
|
95
102
|
}
|
|
96
103
|
|
|
97
|
-
function updatePage(data:
|
|
104
|
+
function updatePage(data: Record<string, unknown> | undefined, options?: UpdatePageOption): void {
|
|
98
105
|
if (options?.reloadTemplate) {
|
|
99
106
|
reloadMainThread(data, options);
|
|
100
107
|
return;
|
|
@@ -118,9 +125,6 @@ function updatePage(data: any, options?: UpdatePageOption): void {
|
|
|
118
125
|
markTiming(PerformanceTimingKeys.updateDiffVdomStart);
|
|
119
126
|
{
|
|
120
127
|
__pendingListUpdates.clear();
|
|
121
|
-
|
|
122
|
-
// ignore ref & unref before jsReady
|
|
123
|
-
takeGlobalRefPatchMap();
|
|
124
128
|
renderMainThread();
|
|
125
129
|
// As said by codename `jsReadyEventIdSwap`, this swap will only be used for event remap,
|
|
126
130
|
// because ref & unref cause by previous render will be ignored
|
|
@@ -132,6 +136,7 @@ function updatePage(data: any, options?: UpdatePageOption): void {
|
|
|
132
136
|
|
|
133
137
|
// always call this before `__FlushElementTree`
|
|
134
138
|
__pendingListUpdates.flush();
|
|
139
|
+
applyRefQueue();
|
|
135
140
|
}
|
|
136
141
|
markTiming(PerformanceTimingKeys.updateDiffVdomEnd);
|
|
137
142
|
}
|
|
@@ -1,6 +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
|
+
|
|
5
|
+
/* eslint-disable */
|
|
6
|
+
|
|
4
7
|
import { Component } from 'preact';
|
|
5
8
|
|
|
6
9
|
import { PerfSpecificKey, PerformanceTimingKeys, markTimingLegacy } from './performance.js';
|
|
@@ -20,11 +23,14 @@ if (__JS__) {
|
|
|
20
23
|
),
|
|
21
24
|
);
|
|
22
25
|
}
|
|
26
|
+
// @ts-expect-error hack lynx-kernel
|
|
23
27
|
return lynxCoreInject.tt._reactLynx.ReactComponent.prototype.getNodeRef
|
|
24
28
|
.call(
|
|
25
29
|
{
|
|
26
30
|
_type: '',
|
|
31
|
+
// @ts-expect-error hack lynx-kernel
|
|
27
32
|
_nativeApp: lynxCoreInject.tt._nativeApp,
|
|
33
|
+
// @ts-expect-error hack lynx-kernel
|
|
28
34
|
_uiModule: lynxCoreInject.tt._nativeApp.nativeModuleProxy.LynxUIMethodModule,
|
|
29
35
|
_reactAppInstance: lynxCoreInject.tt,
|
|
30
36
|
},
|
|
@@ -41,11 +47,14 @@ if (__JS__) {
|
|
|
41
47
|
),
|
|
42
48
|
);
|
|
43
49
|
}
|
|
50
|
+
// @ts-expect-error hack lynx-kernel
|
|
44
51
|
return lynxCoreInject.tt._reactLynx.ReactComponent.prototype
|
|
45
52
|
.getNodeRefFromRoot.call(
|
|
46
53
|
{
|
|
47
54
|
_type: '',
|
|
55
|
+
// @ts-expect-error hack lynx-kernel
|
|
48
56
|
_nativeApp: lynxCoreInject.tt._nativeApp,
|
|
57
|
+
// @ts-expect-error hack lynx-kernel
|
|
49
58
|
_uiModule: lynxCoreInject.tt._nativeApp.nativeModuleProxy.LynxUIMethodModule,
|
|
50
59
|
_reactAppInstance: lynxCoreInject.tt,
|
|
51
60
|
},
|
|
@@ -9,6 +9,7 @@ export function loadDynamicJS<T>(url: string): Promise<T> {
|
|
|
9
9
|
new Error(`A dynamic import (to "${url}") is leaked to Lepus bundle.`),
|
|
10
10
|
{ errorCode: 202 },
|
|
11
11
|
);
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
|
|
12
13
|
return Promise.reject();
|
|
13
14
|
}
|
|
14
15
|
return new Promise((resolve, reject) => {
|
|
@@ -22,7 +23,10 @@ export function loadDynamicJS<T>(url: string): Promise<T> {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export function __dynamicImport<T>(
|
|
26
|
+
export function __dynamicImport<T>(
|
|
27
|
+
url: string,
|
|
28
|
+
options?: { with?: { type?: 'component' | 'tsx' | 'jsx' } },
|
|
29
|
+
): Promise<T> {
|
|
26
30
|
const t = options?.with?.type;
|
|
27
31
|
if (t === 'component' || t === 'tsx' || t === 'jsx') {
|
|
28
32
|
return loadLazyBundle<any>(url);
|