diff --git a/.changeset/thirty-snakes-doubt.md b/.changeset/thirty-snakes-doubt.md
new file mode 100644
index 0000000000..853d812bb3
--- /dev/null
+++ b/.changeset/thirty-snakes-doubt.md
@@ -0,0 +1,3 @@
+---
+
+---
diff --git a/packages/react/runtime/__test__/clone.test.jsx b/packages/react/runtime/__test__/clone.test.jsx
index 2b74dd372a..0fc1a9ed3b 100644
--- a/packages/react/runtime/__test__/clone.test.jsx
+++ b/packages/react/runtime/__test__/clone.test.jsx
@@ -6,8 +6,7 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { elementTree } from './utils/nativeMethod';
-import { setupPage } from '../src/snapshot';
-import { BackgroundSnapshotInstance } from '../src/backgroundSnapshot';
+import { setupPage, BackgroundSnapshotInstance } from '../src/snapshot';
import { cloneElement, createRef } from '../src/index';
import { __root } from '../src/root';
import { globalEnvManager } from './utils/envManager';
diff --git a/packages/react/runtime/__test__/compat.test.jsx b/packages/react/runtime/__test__/compat.test.jsx
index 33c101fd3e..559d8c0964 100644
--- a/packages/react/runtime/__test__/compat.test.jsx
+++ b/packages/react/runtime/__test__/compat.test.jsx
@@ -1,7 +1,7 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { elementTree } from './utils/nativeMethod';
-import { backgroundSnapshotInstanceManager, setupPage, snapshotInstanceManager } from '../src/snapshot';
+import { setupPage, snapshotInstanceManager, backgroundSnapshotInstanceManager } from '../src/snapshot';
import { ComponentFromReactRuntime, wrapWithLynxComponent } from '../src/compat/lynxComponent';
import { setupDocument } from '../src/document';
import { Fragment, render } from 'preact';
@@ -38,7 +38,7 @@ describe('addComponentElement', () => {
}
}
- const jsx = wrapWithLynxComponent((__c) => {__c}, );
+ const jsx = wrapWithLynxComponent(__c => {__c}, );
scratch.ensureElements();
render(jsx, scratch);
@@ -53,7 +53,11 @@ describe('addComponentElement', () => {
`);
});
- let snapshot = (__c) => {__c};
+ let snapshot = __c => (
+
+ {__c}
+
+ );
it('should render a fake component element \'view\' - with some component attr', () => {
class C extends ComponentFromReactRuntime {
render() {
diff --git a/packages/react/runtime/__test__/compat/initData.test.jsx b/packages/react/runtime/__test__/compat/initData.test.jsx
index bdd76fdcec..d18f7699c1 100644
--- a/packages/react/runtime/__test__/compat/initData.test.jsx
+++ b/packages/react/runtime/__test__/compat/initData.test.jsx
@@ -1,9 +1,13 @@
import { Component, render } from 'preact';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { elementTree, waitSchedule } from '../utils/nativeMethod';
-import { BackgroundSnapshotInstance } from '../../src/backgroundSnapshot';
import { setupBackgroundDocument } from '../../src/document';
-import { backgroundSnapshotInstanceManager, setupPage, SnapshotInstance } from '../../src/snapshot';
+import {
+ setupPage,
+ SnapshotInstance,
+ BackgroundSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+} from '../../src/snapshot';
import { backgroundSnapshotInstanceToJSON } from '../utils/debug';
import { useState } from 'preact/compat';
import { useInitData, withInitDataInState } from '../../src/lynx-api';
@@ -49,7 +53,7 @@ describe('initData', () => {
render(, scratch);
_setD(1);
lynx.__initData = {
- 'key1': 'value1',
+ key1: 'value1',
};
lynx.getJSModule('GlobalEventEmitter').emit('onDataChanged');
_setD(2);
@@ -83,7 +87,7 @@ describe('withInitDataInState', () => {
const tt = lynxCoreInject.tt;
expect(app.state).toMatchInlineSnapshot(`{}`);
tt.updateCardData({
- 'key2': 'value2',
+ key2: 'value2',
});
expect(lynx.__initData).toMatchInlineSnapshot(`
{
@@ -111,7 +115,7 @@ describe('withInitDataInState', () => {
const tt = lynxCoreInject.tt;
expect(app.state).toMatchInlineSnapshot(`{}`);
tt.updateCardData({
- 'key3': 'value3',
+ key3: 'value3',
});
await waitSchedule();
// state is updated
@@ -121,7 +125,7 @@ describe('withInitDataInState', () => {
}
`);
app.setState({
- 'key3': null,
+ key3: null,
});
await waitSchedule();
expect(app.state).toMatchInlineSnapshot(`
diff --git a/packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx b/packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx
index 16e16130e5..8f94a51a07 100644
--- a/packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx
+++ b/packages/react/runtime/__test__/debug/backgroundSnapshot-profile.test.jsx
@@ -6,17 +6,18 @@
import { options, render } from 'preact';
import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
-import { BackgroundSnapshotInstance, hydrate } from '../../src/backgroundSnapshot';
import { setupDocument } from '../../src/document';
import { setupVNodeSourceHook } from '../../src/debug/vnodeSource';
import { SnapshotOperation, SnapshotOperationParams } from '../../src/lifecycle/patch/snapshotPatch';
import { DIFFED, DOM } from '../../src/renderToOpcodes/constants';
import { __root } from '../../src/root';
import {
- backgroundSnapshotInstanceManager,
setupPage,
SnapshotInstance,
snapshotInstanceManager,
+ BackgroundSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+ hydrate,
} from '../../src/snapshot';
import { elementTree } from '../utils/nativeMethod';
@@ -248,13 +249,11 @@ describe('backgroundSnapshot profile', () => {
);
expect(
- setAttributeCalls.some(([, option]) => (
+ setAttributeCalls.some(([, option]) =>
option?.args?.dynamicPartIndex === 'meta' && option?.args?.valueType === 'null'
- )),
- ).toBe(true);
- expect(
- insertBeforeCalls.some(([, option]) => option?.args?.targetId === ''),
+ ),
).toBe(true);
+ expect(insertBeforeCalls.some(([, option]) => option?.args?.targetId === '')).toBe(true);
});
it('should apply non-profile move branch with defined target id', () => {
@@ -265,11 +264,9 @@ describe('backgroundSnapshot profile', () => {
const patch = hydrate(before, after);
const operations = decodePatch(patch);
- const moveWithDefinedTarget = operations.find(({ op, args }) => (
- op === SnapshotOperation.InsertBefore
- && args[0] === before.id
- && args[2] !== undefined
- ));
+ const moveWithDefinedTarget = operations.find(
+ ({ op, args }) => op === SnapshotOperation.InsertBefore && args[0] === before.id && args[2] !== undefined,
+ );
expect(moveWithDefinedTarget).toBeDefined();
});
diff --git a/packages/react/runtime/__test__/debug/printSnapshot.test.jsx b/packages/react/runtime/__test__/debug/printSnapshot.test.jsx
index 5536c93c13..4ad36314a8 100644
--- a/packages/react/runtime/__test__/debug/printSnapshot.test.jsx
+++ b/packages/react/runtime/__test__/debug/printSnapshot.test.jsx
@@ -4,11 +4,14 @@
// LICENSE file in the root directory of this source tree.
*/
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
-import { backgroundSnapshotInstanceManager, snapshotInstanceManager } from '../../src/snapshot';
import { elementTree } from '../utils/nativeMethod';
-import { BackgroundSnapshotInstance } from '../../src/backgroundSnapshot';
+import {
+ BackgroundSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+ SnapshotInstance,
+ snapshotInstanceManager,
+} from '../../src/snapshot';
import { printSerializedSnapshotInstance, printSnapshotInstance } from '../../src/debug/printSnapshot';
-import { SnapshotInstance } from '../../src/snapshot';
const HOLE = null;
diff --git a/packages/react/runtime/__test__/element.test.jsx b/packages/react/runtime/__test__/element.test.jsx
index fff72a08fd..d8966f4e01 100644
--- a/packages/react/runtime/__test__/element.test.jsx
+++ b/packages/react/runtime/__test__/element.test.jsx
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it } from 'vitest';
-import { BackgroundSnapshotInstance } from '../src/backgroundSnapshot';
+import { BackgroundSnapshotInstance } from '../src/snapshot';
describe('BackgroundSnapshotInstance', () => {
let root, child1, child2, child3;
diff --git a/packages/react/runtime/__test__/hooks/useLynxGlobalEventListener.test.jsx b/packages/react/runtime/__test__/hooks/useLynxGlobalEventListener.test.jsx
index 5d538e7926..c52910f9bd 100644
--- a/packages/react/runtime/__test__/hooks/useLynxGlobalEventListener.test.jsx
+++ b/packages/react/runtime/__test__/hooks/useLynxGlobalEventListener.test.jsx
@@ -9,10 +9,14 @@ import { render } from 'preact';
import { useState } from 'preact/compat';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
-import { BackgroundSnapshotInstance } from '../../src/backgroundSnapshot';
import { setupBackgroundDocument } from '../../src/document';
import { useLynxGlobalEventListener } from '../../src/lynx-api';
-import { SnapshotInstance, backgroundSnapshotInstanceManager, setupPage } from '../../src/snapshot';
+import {
+ BackgroundSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+ SnapshotInstance,
+ setupPage,
+} from '../../src/snapshot';
import { backgroundSnapshotInstanceToJSON } from '../utils/debug.js';
import { elementTree } from '../utils/nativeMethod';
@@ -29,7 +33,7 @@ describe('useLynxGlobalEventListener', () => {
const lynx = {
...globalThis.lynx,
- getJSModule: (moduleName) => {
+ getJSModule: moduleName => {
if (moduleName === 'GlobalEventEmitter') {
return ee;
}
@@ -109,7 +113,7 @@ describe('useLynxGlobalEventListener', () => {
};
vi.stubGlobal('lynx', {
...globalThis.lynx,
- getJSModule: (moduleName) => {
+ getJSModule: moduleName => {
if (moduleName === 'GlobalEventEmitter') {
return fakeEE;
}
diff --git a/packages/react/runtime/__test__/hydrate.test.jsx b/packages/react/runtime/__test__/hydrate.test.jsx
index 0362746735..0f77fb1bff 100644
--- a/packages/react/runtime/__test__/hydrate.test.jsx
+++ b/packages/react/runtime/__test__/hydrate.test.jsx
@@ -1,7 +1,12 @@
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { elementTree } from './utils/nativeMethod';
-import { BackgroundSnapshotInstance, hydrate } from '../src/backgroundSnapshot';
-import { backgroundSnapshotInstanceManager, SnapshotInstance, snapshotInstanceManager } from '../src/snapshot';
+import {
+ SnapshotInstance,
+ snapshotInstanceManager,
+ backgroundSnapshotInstanceManager,
+ BackgroundSnapshotInstance,
+ hydrate,
+} from '../src/snapshot';
const HOLE = null;
@@ -244,7 +249,7 @@ describe('dual-runtime hydrate', () => {
aa.insertBefore(bb2);
// happens when first-screen render is failed
- expect(hydrate({ 'id': -1, 'type': 'root' }, aa)).toMatchInlineSnapshot(`
+ expect(hydrate({ id: -1, type: 'root' }, aa)).toMatchInlineSnapshot(`
[
0,
"__snapshot_a94a8_test_2",
diff --git a/packages/react/runtime/__test__/lifecycle.test.jsx b/packages/react/runtime/__test__/lifecycle.test.jsx
index e41460ef36..1de785014c 100644
--- a/packages/react/runtime/__test__/lifecycle.test.jsx
+++ b/packages/react/runtime/__test__/lifecycle.test.jsx
@@ -9,7 +9,7 @@ import { deinitGlobalSnapshotPatch, initGlobalSnapshotPatch } from '../src/lifec
import { LifecycleConstant } from '../src/lifecycleConstant';
import { CATCH_ERROR } from '../src/renderToOpcodes/constants';
import { __root } from '../src/root';
-import { backgroundSnapshotInstanceManager, setupPage } from '../src/snapshot';
+import { setupPage, backgroundSnapshotInstanceManager } from '../src/snapshot';
beforeAll(() => {
setupPage(__CreatePage('0', 0));
@@ -352,11 +352,7 @@ describe('componentWillUnmount', () => {
}
render() {
- return (
-
- {showB && }
-
- );
+ return {showB && };
}
}
@@ -397,11 +393,7 @@ describe('BackgroundSnapshotInstance remove', () => {
function Comp() {
const [show, setShow] = useState(1);
setShow_ = setShow;
- return (
-
- {show && 1}
-
- );
+ return {show && 1};
}
initGlobalSnapshotPatch();
@@ -409,8 +401,7 @@ describe('BackgroundSnapshotInstance remove', () => {
render(, __root);
await Promise.resolve().then(() => {});
vi.runAllTimers();
- expect([...backgroundSnapshotInstanceManager.values.keys()])
- .toMatchInlineSnapshot(`
+ expect([...backgroundSnapshotInstanceManager.values.keys()]).toMatchInlineSnapshot(`
[
1,
2,
@@ -424,8 +415,7 @@ describe('BackgroundSnapshotInstance remove', () => {
vi.runAllTimers();
mtCallbacks[0][2]();
- expect([...backgroundSnapshotInstanceManager.values.keys()])
- .toMatchInlineSnapshot(`
+ expect([...backgroundSnapshotInstanceManager.values.keys()]).toMatchInlineSnapshot(`
[
1,
2,
@@ -434,8 +424,7 @@ describe('BackgroundSnapshotInstance remove', () => {
`);
await Promise.resolve().then(() => {});
vi.runAllTimers();
- expect([...backgroundSnapshotInstanceManager.values.keys()])
- .toMatchInlineSnapshot(`
+ expect([...backgroundSnapshotInstanceManager.values.keys()]).toMatchInlineSnapshot(`
[
1,
2,
@@ -516,11 +505,13 @@ describe('useState', () => {
setShow_ = setShow;
- return show && (
-
-
-
-
+ return (
+ show && (
+
+
+
+
+ )
);
}
diff --git a/packages/react/runtime/__test__/lynx/suspense.test.jsx b/packages/react/runtime/__test__/lynx/suspense.test.jsx
index 0183156dc3..3d7d2d9619 100644
--- a/packages/react/runtime/__test__/lynx/suspense.test.jsx
+++ b/packages/react/runtime/__test__/lynx/suspense.test.jsx
@@ -11,13 +11,17 @@ import { replaceCommitHook } from '../../src/lifecycle/patch/commit';
import { injectUpdateMainThread } from '../../src/lifecycle/patch/updateMainThread';
import '../../src/lynx/component';
import { __root } from '../../src/root';
-import { setupPage, SnapshotInstance, snapshotInstanceManager } from '../../src/snapshot';
+import {
+ setupPage,
+ SnapshotInstance,
+ snapshotInstanceManager,
+ BackgroundSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+} from '../../src/snapshot';
import { globalEnvManager } from '../utils/envManager';
import { elementTree } from '../utils/nativeMethod';
-import { backgroundSnapshotInstanceManager } from '../../src/snapshot';
import { prettyFormatSnapshotPatch } from '../../src/debug/formatPatch';
import { createSuspender } from '../createSuspender';
-import { BackgroundSnapshotInstance } from '../../src/backgroundSnapshot';
beforeAll(() => {
setupPage(__CreatePage('0', 0));
diff --git a/packages/react/runtime/__test__/preact.test.jsx b/packages/react/runtime/__test__/preact.test.jsx
index 3450d9b9cf..f8641f9e83 100644
--- a/packages/react/runtime/__test__/preact.test.jsx
+++ b/packages/react/runtime/__test__/preact.test.jsx
@@ -2,7 +2,6 @@ import { cloneElement, Component, render } from 'preact';
import { Suspense, lazy } from 'preact/compat';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
-import { BackgroundSnapshotInstance, hydrate } from '../src/backgroundSnapshot';
import { setupBackgroundDocument, setupDocument } from '../src/document';
import { globalBackgroundSnapshotInstancesToRemove } from '../src/lifecycle/patch/commit';
import {
@@ -13,10 +12,12 @@ import {
import { runWithForce } from '../src/lynx/tt';
import {
SnapshotInstance,
- backgroundSnapshotInstanceManager,
setupPage,
snapshotInstanceManager,
traverseSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+ BackgroundSnapshotInstance,
+ hydrate,
} from '../src/snapshot';
import { backgroundSnapshotInstanceToJSON, snapshotInstanceToJSON } from './utils/debug.js';
import { globalEnvManager } from './utils/envManager';
@@ -253,16 +254,12 @@ describe('document', () => {
{result
? (
-
- {text ? text : 'Succ'}
-
+ {text ? text : 'Succ'}
)
: (
-
- {text ? text : 'Err'}
-
+ {text ? text : 'Err'}
)}
@@ -359,8 +356,7 @@ describe('document - background', () => {
`);
- expect([...backgroundSnapshotInstanceManager.values.keys()])
- .toMatchInlineSnapshot(`
+ expect([...backgroundSnapshotInstanceManager.values.keys()]).toMatchInlineSnapshot(`
[
1,
2,
@@ -388,8 +384,7 @@ describe('document - background', () => {
`);
- expect([...backgroundSnapshotInstanceManager.values.keys()])
- .toMatchInlineSnapshot(`
+ expect([...backgroundSnapshotInstanceManager.values.keys()]).toMatchInlineSnapshot(`
[
1,
2,
@@ -671,8 +666,7 @@ describe('document - dual-runtime', () => {
`);
delete BackgroundSnapshotInstance.prototype.toJSON;
- expect(hydrate(JSON.parse(JSON.stringify(root)), backgroundRoot))
- .toMatchInlineSnapshot(`
+ expect(hydrate(JSON.parse(JSON.stringify(root)), backgroundRoot)).toMatchInlineSnapshot(`
[
3,
-88,
@@ -778,7 +772,6 @@ describe('document - dual-runtime', () => {
`);
delete BackgroundSnapshotInstance.prototype.toJSON;
- expect(hydrate(JSON.parse(JSON.stringify(root)), backgroundRoot))
- .toMatchInlineSnapshot(`[]`);
+ expect(hydrate(JSON.parse(JSON.stringify(root)), backgroundRoot)).toMatchInlineSnapshot(`[]`);
});
});
diff --git a/packages/react/runtime/__test__/render.test.jsx b/packages/react/runtime/__test__/render.test.jsx
index 933ef9ccb2..0c3f993f58 100644
--- a/packages/react/runtime/__test__/render.test.jsx
+++ b/packages/react/runtime/__test__/render.test.jsx
@@ -12,7 +12,7 @@ import { __root } from '../src/root';
import { setupPage, SnapshotInstance, snapshotInstanceManager } from '../src/snapshot';
import { globalEnvManager } from './utils/envManager';
import { elementTree } from './utils/nativeMethod';
-import { backgroundSnapshotInstanceManager } from '../src/snapshot';
+import { backgroundSnapshotInstanceManager } from '../src/backgroundSnapshot';
import { prettyFormatSnapshotPatch } from '../src/debug/formatPatch';
import { root } from '../src/lynx-api';
diff --git a/packages/react/runtime/__test__/snapshot/event.test.jsx b/packages/react/runtime/__test__/snapshot/event.test.jsx
index 15462aacc5..2d0f9c3939 100644
--- a/packages/react/runtime/__test__/snapshot/event.test.jsx
+++ b/packages/react/runtime/__test__/snapshot/event.test.jsx
@@ -14,7 +14,7 @@ import { injectTt } from '../../src/lynx/tt';
import { root } from '../../src/lynx-api';
import { CHILDREN } from '../../src/renderToOpcodes/constants';
import { __root } from '../../src/root';
-import { backgroundSnapshotInstanceManager, setupPage } from '../../src/snapshot';
+import { setupPage, backgroundSnapshotInstanceManager } from '../../src/snapshot';
import { globalEnvManager } from '../utils/envManager';
import { elementTree } from '../utils/nativeMethod';
@@ -265,11 +265,7 @@ describe('eventUpdate', () => {
let handleTap1 = vi.fn();
let show = false;
function Comp() {
- return (
-
- {show ? 1 : null}
-
- );
+ return {show ? 1 : null};
}
// main thread render
@@ -677,7 +673,9 @@ describe('event in spread', () => {
return (
1
- 2
+
+ 2
+
);
}
@@ -894,11 +892,7 @@ describe('event in spread', () => {
let handleTap1 = vi.fn();
let spread1 = { bindtap: handleTap1 };
function Comp() {
- return (
-
- {show ? 1 : null}
-
- );
+ return {show ? 1 : null};
}
// main thread render
diff --git a/packages/react/runtime/__test__/snapshot/spread.test.jsx b/packages/react/runtime/__test__/snapshot/spread.test.jsx
index 82ca9234c7..c344e36dcc 100644
--- a/packages/react/runtime/__test__/snapshot/spread.test.jsx
+++ b/packages/react/runtime/__test__/snapshot/spread.test.jsx
@@ -6,11 +6,10 @@
import { render } from 'preact';
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
-import { hydrate } from '../../src/backgroundSnapshot';
import { useState } from '../../src/index';
import { initGlobalSnapshotPatch, takeGlobalSnapshotPatch } from '../../src/lifecycle/patch/snapshotPatch';
import { snapshotPatchApply } from '../../src/lifecycle/patch/snapshotPatchApply';
-import { backgroundSnapshotInstanceManager, setupPage, snapshotInstanceManager } from '../../src/snapshot';
+import { setupPage, snapshotInstanceManager, hydrate, backgroundSnapshotInstanceManager } from '../../src/snapshot';
import { globalEnvManager } from '../utils/envManager';
import { elementTree } from '../utils/nativeMethod';
@@ -56,7 +55,9 @@ describe('spreadUpdate', () => {
});
return (
- 1
+
+ 1
+
);
}
diff --git a/packages/react/runtime/__test__/snapshotPatch.test.jsx b/packages/react/runtime/__test__/snapshotPatch.test.jsx
index bff2e9df66..c225cbe258 100644
--- a/packages/react/runtime/__test__/snapshotPatch.test.jsx
+++ b/packages/react/runtime/__test__/snapshotPatch.test.jsx
@@ -3,7 +3,6 @@
// LICENSE file in the root directory of this source tree.
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
-import { BackgroundSnapshotInstance } from '../src/backgroundSnapshot';
import { globalEnvManager } from './utils/envManager';
import { elementTree } from './utils/nativeMethod';
import { registerWorkletOnBackground } from '../src/internal';
@@ -17,6 +16,7 @@ import {
} from '../src/lifecycle/patch/snapshotPatch';
import { snapshotPatchApply } from '../src/lifecycle/patch/snapshotPatchApply';
import {
+ BackgroundSnapshotInstance,
SnapshotInstance,
createSnapshot,
snapshotCreatorMap,
diff --git a/packages/react/runtime/__test__/utils/envManager.ts b/packages/react/runtime/__test__/utils/envManager.ts
index fc7bce407d..54212540e9 100644
--- a/packages/react/runtime/__test__/utils/envManager.ts
+++ b/packages/react/runtime/__test__/utils/envManager.ts
@@ -2,15 +2,18 @@
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
import { getJSModule } from './jsModule.js';
-import { BackgroundSnapshotInstance } from '../../src/backgroundSnapshot.js';
+import {
+ BackgroundSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+} from '../../src/snapshot/backgroundSnapshot.js';
import { setupBackgroundDocument, setupDocument } from '../../src/document.js';
import { deinitGlobalSnapshotPatch } from '../../src/lifecycle/patch/snapshotPatch.js';
import { shouldDelayUiOps } from '../../src/lifecycle/ref/delay.js';
import { clearListGlobal } from '../../src/list.js';
import { globalPipelineOptions, setPipeline } from '../../src/lynx/performance.js';
import { __root, setRoot } from '../../src/root.js';
-import { SnapshotInstance, backgroundSnapshotInstanceManager, snapshotInstanceManager } from '../../src/snapshot.js';
-import { hydrationMap } from '../../src/snapshotInstanceHydrationMap.js';
+import { SnapshotInstance, snapshotInstanceManager } from '../../src/snapshot/snapshot.js';
+import { hydrationMap } from '../../src/snapshot/snapshotInstanceHydrationMap.js';
import { clearWorkletRefLastIdForTesting } from '../../src/worklet/ref/workletRef.js';
export class EnvManager {
diff --git a/packages/react/runtime/src/alog/render.ts b/packages/react/runtime/src/alog/render.ts
index 3d14955c9a..07ee3d78ba 100644
--- a/packages/react/runtime/src/alog/render.ts
+++ b/packages/react/runtime/src/alog/render.ts
@@ -5,7 +5,7 @@ import { options } from 'preact';
import type { ComponentClass, VNode } from 'preact';
import { DIFFED, DOM } from '../renderToOpcodes/constants.js';
-import type { SnapshotInstance } from '../snapshot.js';
+import type { SnapshotInstance } from '../snapshot/snapshot.js';
import { getDisplayName } from '../utils.js';
export function initRenderAlog(): void {
diff --git a/packages/react/runtime/src/debug/printSnapshot.ts b/packages/react/runtime/src/debug/printSnapshot.ts
index fcaeecc31e..4bfb879e5c 100644
--- a/packages/react/runtime/src/debug/printSnapshot.ts
+++ b/packages/react/runtime/src/debug/printSnapshot.ts
@@ -1,10 +1,10 @@
// Copyright 2024 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import { BackgroundSnapshotInstance } from '../backgroundSnapshot.js';
-import { SnapshotInstance } from '../snapshot.js';
-import type { SerializedSnapshotInstance } from '../snapshot.js';
import { logDebug } from './debug.js';
+import { BackgroundSnapshotInstance } from '../snapshot/backgroundSnapshot.js';
+import { SnapshotInstance } from '../snapshot/snapshot.js';
+import type { SerializedSnapshotInstance } from '../snapshot/types.js';
export function printSnapshotInstance(
instance: BackgroundSnapshotInstance | SnapshotInstance,
diff --git a/packages/react/runtime/src/document.ts b/packages/react/runtime/src/document.ts
index a326180c05..50ff8678c0 100644
--- a/packages/react/runtime/src/document.ts
+++ b/packages/react/runtime/src/document.ts
@@ -1,8 +1,8 @@
// Copyright 2024 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import { BackgroundSnapshotInstance } from './backgroundSnapshot.js';
-import { SnapshotInstance } from './snapshot.js';
+import { BackgroundSnapshotInstance } from './snapshot/backgroundSnapshot.js';
+import { SnapshotInstance } from './snapshot/snapshot.js';
/**
* This module implements an Interface Adapter Pattern to integrate Preact's
diff --git a/packages/react/runtime/src/hydrate.ts b/packages/react/runtime/src/hydrate.ts
index 0aa2f7ed20..69b00fbfb0 100644
--- a/packages/react/runtime/src/hydrate.ts
+++ b/packages/react/runtime/src/hydrate.ts
@@ -8,7 +8,7 @@ import { __pendingListUpdates } from './pendingListUpdates.js';
import { DynamicPartType } from './snapshot/dynamicPartType.js';
import type { PlatformInfo } from './snapshot/platformInfo.js';
import { unref } from './snapshot/ref.js';
-import type { SnapshotInstance } from './snapshot.js';
+import type { SnapshotInstance } from './snapshot/snapshot.js';
import { isEmptyObject } from './utils.js';
const UNREACHABLE_ITEM_KEY_NOT_FOUND = 'UNREACHABLE_ITEM_KEY_NOT_FOUND';
diff --git a/packages/react/runtime/src/internal.ts b/packages/react/runtime/src/internal.ts
index c3213d2b3b..8aaaa9c863 100644
--- a/packages/react/runtime/src/internal.ts
+++ b/packages/react/runtime/src/internal.ts
@@ -7,14 +7,15 @@ import type { FC } from 'react';
import './lynx.js';
-import { BackgroundSnapshotInstance } from './backgroundSnapshot.js';
import { factory as factory2 } from './compat/componentIs.js';
import { useMemo } from './hooks/react.js';
import { loadLazyBundle } from './lynx/lazy-bundle.js';
import { __root } from './root.js';
+import { BackgroundSnapshotInstance } from './snapshot/backgroundSnapshot.js';
+import { __page, __pageId, createSnapshot, snapshotManager } from './snapshot/definition.js';
import { DynamicPartType } from './snapshot/dynamicPartType.js';
import { snapshotCreateList } from './snapshot/list.js';
-import { SnapshotInstance, __page, __pageId, createSnapshot, snapshotCreatorMap, snapshotManager } from './snapshot.js';
+import { SnapshotInstance, snapshotCreatorMap } from './snapshot/snapshot.js';
export { __page, __pageId, __root };
@@ -31,7 +32,7 @@ export const __DynamicPartSlot: DynamicPartType = DynamicPartType.Slot;
export const __DynamicPartMultiChildren: DynamicPartType = DynamicPartType.MultiChildren;
export const __DynamicPartChildren: DynamicPartType = DynamicPartType.Children;
export const __DynamicPartListChildren: DynamicPartType = DynamicPartType.ListChildren;
-export { __DynamicPartChildren_0 } from './snapshot.js';
+export { __DynamicPartChildren_0 } from './snapshot/dynamicPartType.js';
export { updateSpread } from './snapshot/spread.js';
export { updateEvent } from './snapshot/event.js';
diff --git a/packages/react/runtime/src/lifecycle/patch/commit.ts b/packages/react/runtime/src/lifecycle/patch/commit.ts
index 54e0783131..83a9e7d351 100644
--- a/packages/react/runtime/src/lifecycle/patch/commit.ts
+++ b/packages/react/runtime/src/lifecycle/patch/commit.ts
@@ -23,22 +23,26 @@ import { options } from 'preact';
import type { RunWorkletCtxData } from '@lynx-js/react/worklet-runtime/bindings';
+import {
+ globalBackgroundSnapshotInstancesToRemove,
+ setGlobalBackgroundSnapshotInstancesToRemove,
+} from './globalState.js';
+import { takeGlobalSnapshotPatch } from './snapshotPatch.js';
+import type { SnapshotPatch } from './snapshotPatch.js';
+import { profileEnd, profileStart } from '../../debug/profile.js';
import { LifecycleConstant } from '../../lifecycleConstant.js';
import { globalPipelineOptions, markTiming, markTimingLegacy, setPipeline } from '../../lynx/performance.js';
import { COMMIT } from '../../renderToOpcodes/constants.js';
+import { backgroundSnapshotInstanceManager } from '../../snapshot/backgroundSnapshot.js';
import { applyQueuedRefs } from '../../snapshot/ref.js';
-import { backgroundSnapshotInstanceManager } from '../../snapshot.js';
import { hook, isEmptyObject } from '../../utils.js';
-import { sendMTRefInitValueToMainThread } from '../../worklet/ref/updateInitValue.js';
-import { getReloadVersion } from '../pass.js';
-import type { SnapshotPatch } from './snapshotPatch.js';
-import { takeGlobalSnapshotPatch } from './snapshotPatch.js';
-import { profileEnd, profileStart } from '../../debug/profile.js';
import {
delayedRunOnMainThreadData,
takeDelayedRunOnMainThreadData,
} from '../../worklet/call/delayedRunOnMainThreadData.js';
+import { sendMTRefInitValueToMainThread } from '../../worklet/ref/updateInitValue.js';
import { isRendering } from '../isRendering.js';
+import { getReloadVersion } from '../pass.js';
let globalFlushOptions: FlushOptions = {};
@@ -51,8 +55,6 @@ function takeGlobalFlushOptions() {
const globalCommitTaskMap: Map void> = /*@__PURE__*/ new Map void>();
let nextCommitTaskId = 1;
-let globalBackgroundSnapshotInstancesToRemove: number[] = [];
-
/**
* A single patch operation.
*/
@@ -119,7 +121,7 @@ function replaceCommitHook(): void {
markTiming('diffVdomEnd');
const backgroundSnapshotInstancesToRemove = globalBackgroundSnapshotInstancesToRemove;
- globalBackgroundSnapshotInstancesToRemove = [];
+ setGlobalBackgroundSnapshotInstancesToRemove([]);
const commitTaskId = genCommitTaskId();
diff --git a/packages/react/runtime/src/lifecycle/patch/error.ts b/packages/react/runtime/src/lifecycle/patch/error.ts
index cd056789c1..e9ef22e767 100644
--- a/packages/react/runtime/src/lifecycle/patch/error.ts
+++ b/packages/react/runtime/src/lifecycle/patch/error.ts
@@ -2,7 +2,8 @@
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import { backgroundSnapshotInstanceManager, snapshotManager } from '../../snapshot.js';
+import { backgroundSnapshotInstanceManager } from '../../snapshot/backgroundSnapshot.js';
+import { snapshotManager } from '../../snapshot/definition.js';
export const ctxNotFoundType = 'Lynx.Error.CtxNotFound';
diff --git a/packages/react/runtime/src/lifecycle/patch/globalState.ts b/packages/react/runtime/src/lifecycle/patch/globalState.ts
new file mode 100644
index 0000000000..d0f66bd8e4
--- /dev/null
+++ b/packages/react/runtime/src/lifecycle/patch/globalState.ts
@@ -0,0 +1,16 @@
+// Copyright 2024 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+/**
+ * Global state shared across modules to avoid circular dependencies
+ */
+
+/**
+ * List of background snapshot instances to remove during commit phase
+ */
+export let globalBackgroundSnapshotInstancesToRemove: number[] = [];
+
+export function setGlobalBackgroundSnapshotInstancesToRemove(ids: number[]): void {
+ globalBackgroundSnapshotInstancesToRemove = ids;
+}
diff --git a/packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts b/packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts
index 7123364b07..62565c47cc 100644
--- a/packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts
+++ b/packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts
@@ -16,7 +16,7 @@
import { sendCtxNotFoundEventToBackground } from './error.js';
import type { SnapshotPatch } from './snapshotPatch.js';
import { SnapshotOperation } from './snapshotPatch.js';
-import { SnapshotInstance, snapshotCreatorMap, snapshotInstanceManager } from '../../snapshot.js';
+import { SnapshotInstance, snapshotCreatorMap, snapshotInstanceManager } from '../../snapshot/snapshot.js';
/**
* Applies a patch of snapshot operations to the main thread.
diff --git a/packages/react/runtime/src/lifecycle/patch/updateMainThread.ts b/packages/react/runtime/src/lifecycle/patch/updateMainThread.ts
index ce181f77a0..7807338232 100644
--- a/packages/react/runtime/src/lifecycle/patch/updateMainThread.ts
+++ b/packages/react/runtime/src/lifecycle/patch/updateMainThread.ts
@@ -12,8 +12,8 @@ import { prettyFormatSnapshotPatch } from '../../debug/formatPatch.js';
import { LifecycleConstant } from '../../lifecycleConstant.js';
import { markTiming, setPipeline } from '../../lynx/performance.js';
import { __pendingListUpdates } from '../../pendingListUpdates.js';
+import { __page } from '../../snapshot/definition.js';
import { applyRefQueue } from '../../snapshot/workletRef.js';
-import { __page } from '../../snapshot.js';
import { isMtsEnabled } from '../../worklet/functionality.js';
import { getReloadVersion } from '../pass.js';
diff --git a/packages/react/runtime/src/lifecycle/ref/delay.ts b/packages/react/runtime/src/lifecycle/ref/delay.ts
index bf953f0dc4..ee3d02bbc7 100644
--- a/packages/react/runtime/src/lifecycle/ref/delay.ts
+++ b/packages/react/runtime/src/lifecycle/ref/delay.ts
@@ -4,7 +4,7 @@
import type { NodesRef, SelectorQuery } from '@lynx-js/types';
-import { hydrationMap } from '../../snapshotInstanceHydrationMap.js';
+import { hydrationMap } from '../../snapshot/snapshotInstanceHydrationMap.js';
type FunctionPropertyNames = {
[K in keyof T]: T[K] extends (...args: unknown[]) => unknown ? K : never;
diff --git a/packages/react/runtime/src/lifecycle/reload.ts b/packages/react/runtime/src/lifecycle/reload.ts
index 2d97a20f97..c5c4c59141 100644
--- a/packages/react/runtime/src/lifecycle/reload.ts
+++ b/packages/react/runtime/src/lifecycle/reload.ts
@@ -14,8 +14,8 @@ import { LifecycleConstant } from '../lifecycleConstant.js';
import { __pendingListUpdates } from '../pendingListUpdates.js';
import { __root, setRoot } from '../root.js';
import { destroyBackground } from './destroy.js';
+import { SnapshotInstance, snapshotInstanceManager } from '../snapshot/snapshot.js';
import { applyRefQueue } from '../snapshot/workletRef.js';
-import { SnapshotInstance, __page, snapshotInstanceManager } from '../snapshot.js';
import { isEmptyObject } from '../utils.js';
import { clearJSReadyEventIdSwap, isJSReady } from './event/jsReady.js';
import { increaseReloadVersion } from './pass.js';
@@ -23,6 +23,7 @@ import { deinitGlobalSnapshotPatch } from './patch/snapshotPatch.js';
import { shouldDelayUiOps } from './ref/delay.js';
import { renderMainThread } from './render.js';
import { profileEnd, profileStart } from '../debug/profile.js';
+import { __page } from '../snapshot/definition.js';
function reloadMainThread(data: unknown, options: UpdatePageOption): void {
if (typeof __PROFILE__ !== 'undefined' && __PROFILE__) {
diff --git a/packages/react/runtime/src/lifecycle/render.ts b/packages/react/runtime/src/lifecycle/render.ts
index 111e9e0af7..153ea55d1d 100644
--- a/packages/react/runtime/src/lifecycle/render.ts
+++ b/packages/react/runtime/src/lifecycle/render.ts
@@ -12,7 +12,7 @@ import { profileEnd, profileStart } from '../debug/profile.js';
import { renderOpcodesInto } from '../opcodes.js';
import { render as renderToString } from '../renderToOpcodes/index.js';
import { __root } from '../root.js';
-import { SnapshotInstance } from '../snapshot.js';
+import { SnapshotInstance } from '../snapshot/snapshot.js';
function renderMainThread(): void {
let opcodes;
diff --git a/packages/react/runtime/src/list.ts b/packages/react/runtime/src/list.ts
index 1c32d70591..736303b2a8 100644
--- a/packages/react/runtime/src/list.ts
+++ b/packages/react/runtime/src/list.ts
@@ -2,8 +2,8 @@
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
import { LifecycleConstant } from './lifecycleConstant.js';
+import type { SnapshotInstance } from './snapshot/snapshot.js';
import { applyRefQueue } from './snapshot/workletRef.js';
-import type { SnapshotInstance } from './snapshot.js';
import { maybePromise } from './utils.js';
export const gSignMap: Record> = {};
diff --git a/packages/react/runtime/src/listUpdateInfo.ts b/packages/react/runtime/src/listUpdateInfo.ts
index bbf3a0ee64..6c8db2c1ad 100644
--- a/packages/react/runtime/src/listUpdateInfo.ts
+++ b/packages/react/runtime/src/listUpdateInfo.ts
@@ -5,7 +5,7 @@
import { profileEnd, profileStart } from './debug/profile.js';
import { hydrate } from './hydrate.js';
import { componentAtIndexFactory, enqueueComponentFactory } from './list.js';
-import type { SnapshotInstance } from './snapshot.js';
+import type { SnapshotInstance } from './snapshot/snapshot.js';
export interface ListUpdateInfo {
flush(): number | undefined;
diff --git a/packages/react/runtime/src/lynx/calledByNative.ts b/packages/react/runtime/src/lynx/calledByNative.ts
index 7d8e95f53f..cccd0bf927 100644
--- a/packages/react/runtime/src/lynx/calledByNative.ts
+++ b/packages/react/runtime/src/lynx/calledByNative.ts
@@ -10,8 +10,9 @@ import { ssrHydrateByOpcodes } from '../opcodes.js';
import { __pendingListUpdates } from '../pendingListUpdates.js';
import { __root, setRoot } from '../root.js';
import { markTiming, setPipeline } from './performance.js';
+import { __page, setupPage } from '../snapshot/definition.js';
+import { SnapshotInstance } from '../snapshot/snapshot.js';
import { applyRefQueue } from '../snapshot/workletRef.js';
-import { SnapshotInstance, __page, setupPage } from '../snapshot.js';
import { isEmptyObject } from '../utils.js';
function ssrEncode() {
diff --git a/packages/react/runtime/src/lynx/injectLepusMethods.ts b/packages/react/runtime/src/lynx/injectLepusMethods.ts
index 59fb5195db..5ef9b0d414 100644
--- a/packages/react/runtime/src/lynx/injectLepusMethods.ts
+++ b/packages/react/runtime/src/lynx/injectLepusMethods.ts
@@ -1,7 +1,7 @@
// Copyright 2024 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import { snapshotInstanceManager } from '../snapshot.js';
+import { snapshotInstanceManager } from '../snapshot/snapshot.js';
function injectLepusMethods(): void {
Object.assign(globalThis, {
diff --git a/packages/react/runtime/src/lynx/suspense.ts b/packages/react/runtime/src/lynx/suspense.ts
index 2414c8ef9a..b96abb058a 100644
--- a/packages/react/runtime/src/lynx/suspense.ts
+++ b/packages/react/runtime/src/lynx/suspense.ts
@@ -8,8 +8,8 @@ import { useRef } from 'preact/hooks';
import { createElement as createElementMainThread } from '@lynx-js/react/lepus';
-import type { BackgroundSnapshotInstance } from '../backgroundSnapshot.js';
import { globalBackgroundSnapshotInstancesToRemove } from '../lifecycle/patch/commit.js';
+import type { BackgroundSnapshotInstance } from '../snapshot/backgroundSnapshot.js';
export const Suspense: FunctionComponent<{ children: VNode | VNode[]; fallback: VNode }> = (
{ children, fallback },
diff --git a/packages/react/runtime/src/lynx/tt.ts b/packages/react/runtime/src/lynx/tt.ts
index 61166746ab..635dc0a664 100644
--- a/packages/react/runtime/src/lynx/tt.ts
+++ b/packages/react/runtime/src/lynx/tt.ts
@@ -6,7 +6,6 @@ import { process, render } from 'preact';
import { LifecycleConstant, NativeUpdateDataType } from '../lifecycleConstant.js';
import type { FirstScreenData } from '../lifecycleConstant.js';
import { PerformanceTimingFlags, PipelineOrigins, beginPipeline, markTiming } from './performance.js';
-import { BackgroundSnapshotInstance, hydrate } from '../backgroundSnapshot.js';
import { runWithForce } from './runWithForce.js';
import { printSnapshotInstanceToString } from '../debug/printSnapshot.js';
import { profileEnd, profileStart } from '../debug/profile.js';
@@ -21,8 +20,12 @@ import { runDelayedUiOps } from '../lifecycle/ref/delay.js';
import { reloadBackground } from '../lifecycle/reload.js';
import { CHILDREN } from '../renderToOpcodes/constants.js';
import { __root } from '../root.js';
-import { backgroundSnapshotInstanceManager } from '../snapshot.js';
-import type { SerializedSnapshotInstance } from '../snapshot.js';
+import {
+ BackgroundSnapshotInstance,
+ backgroundSnapshotInstanceManager,
+ hydrate,
+} from '../snapshot/backgroundSnapshot.js';
+import type { SerializedSnapshotInstance } from '../snapshot/types.js';
import {
delayedRunOnMainThreadData,
takeDelayedRunOnMainThreadData,
diff --git a/packages/react/runtime/src/opcodes.ts b/packages/react/runtime/src/opcodes.ts
index d1eed6b8af..352488e1f9 100644
--- a/packages/react/runtime/src/opcodes.ts
+++ b/packages/react/runtime/src/opcodes.ts
@@ -4,7 +4,7 @@
import { hydrate } from './hydrate.js';
import { componentAtIndexFactory, enqueueComponentFactory, gRecycleMap, gSignMap } from './list.js';
import { CHILDREN } from './renderToOpcodes/constants.js';
-import { SnapshotInstance } from './snapshot.js';
+import { SnapshotInstance } from './snapshot/snapshot.js';
const OpcodeBegin = 0;
const OpcodeEnd = 1;
diff --git a/packages/react/runtime/src/root.ts b/packages/react/runtime/src/root.ts
index a3f0f6b4ad..18c5f8cb74 100644
--- a/packages/react/runtime/src/root.ts
+++ b/packages/react/runtime/src/root.ts
@@ -1,8 +1,8 @@
// Copyright 2024 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import { BackgroundSnapshotInstance } from './backgroundSnapshot.js';
-import { SnapshotInstance } from './snapshot.js';
+import { BackgroundSnapshotInstance } from './snapshot/backgroundSnapshot.js';
+import { SnapshotInstance } from './snapshot/snapshot.js';
/**
* The internal ReactLynx's root.
diff --git a/packages/react/runtime/src/backgroundSnapshot.ts b/packages/react/runtime/src/snapshot/backgroundSnapshot.ts
similarity index 87%
rename from packages/react/runtime/src/backgroundSnapshot.ts
rename to packages/react/runtime/src/snapshot/backgroundSnapshot.ts
index cdeafefe09..1d9f4c3bff 100644
--- a/packages/react/runtime/src/backgroundSnapshot.ts
+++ b/packages/react/runtime/src/snapshot/backgroundSnapshot.ts
@@ -10,34 +10,99 @@
import type { Worklet } from '@lynx-js/react/worklet-runtime/bindings';
-import { profileEnd, profileStart } from './debug/profile.js';
-import { getSnapshotVNodeSource } from './debug/vnodeSource.js';
-import { processGestureBackground } from './gesture/processGestureBagkround.js';
-import type { GestureKind } from './gesture/types.js';
-import { diffArrayAction, diffArrayLepus } from './hydrate.js';
-import { globalBackgroundSnapshotInstancesToRemove } from './lifecycle/patch/commit.js';
-import type { SnapshotPatch } from './lifecycle/patch/snapshotPatch.js';
+import { profileEnd, profileStart } from '../debug/profile.js';
+import { clearSnapshotVNodeSource, getSnapshotVNodeSource, moveSnapshotVNodeSource } from '../debug/vnodeSource.js';
+import { processGestureBackground } from '../gesture/processGestureBagkround.js';
+import type { GestureKind } from '../gesture/types.js';
+import { diffArrayAction, diffArrayLepus } from '../hydrate.js';
+import { snapshotManager } from './definition.js';
+import type { Snapshot } from './definition.js';
+import { DynamicPartType } from './dynamicPartType.js';
+import { applyRef, clearQueuedRefs, queueRefAttrUpdate } from './ref.js';
+import type { Ref } from './ref.js';
+import { snapshotCreatorMap } from './snapshot.js';
+import { hydrationMap } from './snapshotInstanceHydrationMap.js';
+import { transformSpread } from './spread.js';
+import type { SerializedSnapshotInstance } from './types.js';
+import { traverseSnapshotInstance } from './utils.js';
+import { globalBackgroundSnapshotInstancesToRemove } from '../lifecycle/patch/globalState.js';
import {
SnapshotOperation,
__globalSnapshotPatch,
initGlobalSnapshotPatch,
takeGlobalSnapshotPatch,
-} from './lifecycle/patch/snapshotPatch.js';
-import { globalPipelineOptions } from './lynx/performance.js';
-import { DynamicPartType } from './snapshot/dynamicPartType.js';
-import { applyRef, clearQueuedRefs, queueRefAttrUpdate } from './snapshot/ref.js';
-import type { Ref } from './snapshot/ref.js';
-import { transformSpread } from './snapshot/spread.js';
-import type { SerializedSnapshotInstance, Snapshot } from './snapshot.js';
-import {
- backgroundSnapshotInstanceManager,
- snapshotCreatorMap,
- snapshotManager,
- traverseSnapshotInstance,
-} from './snapshot.js';
-import { hydrationMap } from './snapshotInstanceHydrationMap.js';
-import { isDirectOrDeepEqual } from './utils.js';
-import { onPostWorkletCtx } from './worklet/ctx.js';
+} from '../lifecycle/patch/snapshotPatch.js';
+import type { SnapshotPatch } from '../lifecycle/patch/snapshotPatch.js';
+import { globalPipelineOptions } from '../lynx/performance.js';
+import { isDirectOrDeepEqual } from '../utils.js';
+import { onPostWorkletCtx } from '../worklet/ctx.js';
+
+/**
+ * Background snapshot instance manager that manages all background snapshot instances.
+ */
+export const backgroundSnapshotInstanceManager: {
+ nextId: number;
+ values: Map;
+ clear(): void;
+ updateId(id: number, newId: number): void;
+ getValueBySign(str: string): unknown;
+} = {
+ nextId: 0,
+ values: /* @__PURE__ */ new Map(),
+ clear() {
+ // not resetting `nextId` to prevent id collision
+ this.values.clear();
+ if (__DEV__) {
+ clearSnapshotVNodeSource();
+ }
+ },
+ updateId(id: number, newId: number) {
+ const values = this.values;
+ const si = values.get(id)!;
+ // For PreactDevtools, on first hydration,
+ // PreactDevtools can get the real snapshot instance id in main-thread
+ if (__DEV__ && __BACKGROUND__) {
+ lynx.getJSModule('GlobalEventEmitter').emit('onBackgroundSnapshotInstanceUpdateId', [
+ {
+ backgroundSnapshotInstance: si,
+ oldId: id,
+ newId,
+ },
+ ]);
+ }
+ values.delete(id);
+ values.set(newId, si);
+ si.__id = newId;
+ if (__DEV__) {
+ moveSnapshotVNodeSource(id, newId);
+ }
+ },
+ getValueBySign(str: string): unknown {
+ const res = str?.split(':');
+ if (!res || (res.length != 2 && res.length != 3)) {
+ throw new Error('Invalid ctx format: ' + str);
+ }
+ const id = Number(res[0]);
+ const expIndex = Number(res[1]);
+ const ctx = this.values.get(id);
+ if (!ctx) {
+ return null;
+ }
+ const spreadKey = res[2];
+ if (res[1] === '__extraProps') {
+ if (spreadKey) {
+ return ctx.__extraProps![spreadKey];
+ }
+ throw new Error('unreachable');
+ } else {
+ if (spreadKey) {
+ return (ctx.__values![expIndex] as { [spreadKey]: unknown })[spreadKey];
+ } else {
+ return ctx.__values![expIndex];
+ }
+ }
+ },
+};
export class BackgroundSnapshotInstance {
constructor(public type: string) {
diff --git a/packages/react/runtime/src/snapshot/constants.ts b/packages/react/runtime/src/snapshot/constants.ts
new file mode 100644
index 0000000000..ca7037dec9
--- /dev/null
+++ b/packages/react/runtime/src/snapshot/constants.ts
@@ -0,0 +1,17 @@
+// Copyright 2024 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+/**
+ * Constants for snapshot system.
+ */
+
+/**
+ * Default entry name for snapshots.
+ */
+export const DEFAULT_ENTRY_NAME = '__Card__';
+
+/**
+ * Default CSS ID for snapshots.
+ */
+export const DEFAULT_CSS_ID = 0;
diff --git a/packages/react/runtime/src/snapshot/definition.ts b/packages/react/runtime/src/snapshot/definition.ts
new file mode 100644
index 0000000000..3eb560a6cf
--- /dev/null
+++ b/packages/react/runtime/src/snapshot/definition.ts
@@ -0,0 +1,147 @@
+// Copyright 2024 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+/**
+ * Snapshot manager that manages all snapshot definitions.
+ */
+import { DEFAULT_ENTRY_NAME } from './constants.js';
+import { DynamicPartType, __DynamicPartChildren_0 } from './dynamicPartType.js';
+import type { SnapshotInstance } from './snapshot.js';
+import { entryUniqID } from './utils.js';
+import { SnapshotOperation, __globalSnapshotPatch } from '../lifecycle/patch/snapshotPatch.js';
+
+export let __page: FiberElement;
+export let __pageId = 0;
+export function setupPage(page: FiberElement): void {
+ __page = page;
+ __pageId = __GetElementUniqueID(page);
+}
+
+export function clearPage(): void {
+ __page = undefined as unknown as FiberElement;
+ __pageId = 0;
+}
+
+/**
+ * A snapshot definition that contains all the information needed to create and update elements
+ * This is generated at compile time through static analysis of the JSX
+ */
+export interface Snapshot {
+ create: null | ((ctx: SnapshotInstance) => FiberElement[]);
+ update: null | ((ctx: SnapshotInstance, index: number, oldValue: any) => void)[];
+ slot: [DynamicPartType, number][];
+
+ isListHolder?: boolean;
+ cssId?: number | undefined;
+ entryName?: string | undefined;
+ refAndSpreadIndexes?: number[] | null;
+}
+
+/**
+ * Manager for snapshot definitions
+ */
+export const snapshotManager: {
+ values: Map;
+} = {
+ values: /* @__PURE__ */ new Map([
+ [
+ 'root',
+ {
+ create() {
+ /* v8 ignore start */
+ if (__JS__ && !__DEV__) {
+ return [];
+ }
+ /* v8 ignore stop */
+ return [__page!];
+ },
+ update: [],
+ slot: __DynamicPartChildren_0,
+ isListHolder: false,
+ cssId: 0,
+ },
+ ],
+ [
+ 'wrapper',
+ {
+ create() {
+ /* v8 ignore start */
+ if (__JS__ && !__DEV__) {
+ return [];
+ }
+ /* v8 ignore stop */
+ return [__CreateWrapperElement(__pageId)];
+ },
+ update: [],
+ slot: __DynamicPartChildren_0,
+ isListHolder: false,
+ },
+ ],
+ [
+ null as unknown as string,
+ {
+ create() {
+ /* v8 ignore start */
+ if (__JS__ && !__DEV__) {
+ return [];
+ }
+ /* v8 ignore stop */
+ return [__CreateRawText('')];
+ },
+ update: [
+ ctx => {
+ /* v8 ignore start */
+ if (__JS__ && !__DEV__) {
+ return;
+ }
+ /* v8 ignore stop */
+ if (ctx.__elements) {
+ __SetAttribute(ctx.__elements[0]!, 'text', ctx.__values![0]);
+ }
+ },
+ ],
+ slot: [],
+ isListHolder: false,
+ },
+ ],
+ ]),
+};
+
+/**
+ * Creates a new snapshot definition and adds it to the manager
+ */
+export function createSnapshot(
+ uniqID: string,
+ create: Snapshot['create'] | null,
+ update: Snapshot['update'] | null,
+ slot: Snapshot['slot'],
+ cssId: number | undefined,
+ entryName: string | undefined,
+ refAndSpreadIndexes: number[] | null,
+ isLazySnapshotSupported: boolean = false,
+): string {
+ if (!isLazySnapshotSupported) {
+ uniqID = entryUniqID(uniqID, entryName);
+ }
+ // For Lazy Bundle, their entryName is not DEFAULT_ENTRY_NAME.
+ // We need to set the entryName correctly for HMR
+ if (
+ __DEV__ && __JS__ && __globalSnapshotPatch && entryName && entryName !== DEFAULT_ENTRY_NAME
+ // `uniqID` will be `https://example.com/main.lynx.bundle:__snapshot_835da_eff1e_1` when loading a standalone lazy bundle after hydration.
+ && !uniqID.includes(':')
+ ) {
+ __globalSnapshotPatch.push(
+ SnapshotOperation.DEV_ONLY_SetSnapshotEntryName,
+ uniqID,
+ entryName,
+ );
+ }
+
+ const s: Snapshot = { create, update, slot, cssId, entryName, refAndSpreadIndexes };
+ snapshotManager.values.set(uniqID, s);
+ if (slot && slot[0] && slot[0][0] === DynamicPartType.ListChildren) {
+ s.isListHolder = true;
+ }
+ return uniqID;
+}
diff --git a/packages/react/runtime/src/snapshot/dynamicPartType.ts b/packages/react/runtime/src/snapshot/dynamicPartType.ts
index 58f4b5cb0d..dd4b296bd5 100644
--- a/packages/react/runtime/src/snapshot/dynamicPartType.ts
+++ b/packages/react/runtime/src/snapshot/dynamicPartType.ts
@@ -16,3 +16,8 @@ export const DynamicPartType = {
} as const;
export type DynamicPartType = (typeof DynamicPartType)[keyof typeof DynamicPartType];
+
+/**
+ * Default dynamic part for children
+ */
+export const __DynamicPartChildren_0: [DynamicPartType, number][] = [[DynamicPartType.Children, 0]];
diff --git a/packages/react/runtime/src/snapshot/event.ts b/packages/react/runtime/src/snapshot/event.ts
index 734c7ffd5a..6ffec1dee9 100644
--- a/packages/react/runtime/src/snapshot/event.ts
+++ b/packages/react/runtime/src/snapshot/event.ts
@@ -1,7 +1,7 @@
// Copyright 2024 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import { SnapshotInstance } from '../snapshot.js';
+import { SnapshotInstance } from '../snapshot/snapshot.js';
function updateEvent(
snapshot: SnapshotInstance,
diff --git a/packages/react/runtime/src/snapshot/gesture.ts b/packages/react/runtime/src/snapshot/gesture.ts
index 8f1307d7e1..b59cd9fe5b 100644
--- a/packages/react/runtime/src/snapshot/gesture.ts
+++ b/packages/react/runtime/src/snapshot/gesture.ts
@@ -4,7 +4,7 @@
import { processGesture } from '../gesture/processGesture.js';
import type { GestureKind } from '../gesture/types.js';
import { isMainThreadHydrating } from '../lifecycle/patch/isMainThreadHydrating.js';
-import { SnapshotInstance } from '../snapshot.js';
+import type { SnapshotInstance } from '../snapshot/snapshot.js';
export function updateGesture(
snapshot: SnapshotInstance,
diff --git a/packages/react/runtime/src/snapshot/index.ts b/packages/react/runtime/src/snapshot/index.ts
new file mode 100644
index 0000000000..4f40a0fa0d
--- /dev/null
+++ b/packages/react/runtime/src/snapshot/index.ts
@@ -0,0 +1,8 @@
+// Copyright 2026 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+export { BackgroundSnapshotInstance, backgroundSnapshotInstanceManager, hydrate } from './backgroundSnapshot.js';
+export { SnapshotInstance, snapshotInstanceManager, snapshotCreatorMap } from './snapshot.js';
+export { snapshotManager, createSnapshot, setupPage, __page, __pageId, clearPage } from './definition.js';
+export { traverseSnapshotInstance } from './utils.js';
diff --git a/packages/react/runtime/src/snapshot/list.ts b/packages/react/runtime/src/snapshot/list.ts
index 0c7de36886..972433e888 100644
--- a/packages/react/runtime/src/snapshot/list.ts
+++ b/packages/react/runtime/src/snapshot/list.ts
@@ -4,7 +4,7 @@
import { hydrate } from '../hydrate.js';
import { componentAtIndexFactory, enqueueComponentFactory, gRecycleMap, gSignMap } from '../list.js';
-import type { SnapshotInstance } from '../snapshot.js';
+import type { SnapshotInstance } from '../snapshot/snapshot.js';
const destroyLifetimeHandlerMap = new Map void>();
diff --git a/packages/react/runtime/src/snapshot/platformInfo.ts b/packages/react/runtime/src/snapshot/platformInfo.ts
index c7ff692fbb..4612033141 100644
--- a/packages/react/runtime/src/snapshot/platformInfo.ts
+++ b/packages/react/runtime/src/snapshot/platformInfo.ts
@@ -3,7 +3,7 @@
// LICENSE file in the root directory of this source tree.
import { ListUpdateInfoRecording } from '../listUpdateInfo.js';
import { __pendingListUpdates } from '../pendingListUpdates.js';
-import { SnapshotInstance } from '../snapshot.js';
+import type { SnapshotInstance } from '../snapshot/snapshot.js';
const platformInfoVirtualAttributes: Set = /* @__PURE__ */ new Set([
'reuse-identifier',
diff --git a/packages/react/runtime/src/snapshot/ref.ts b/packages/react/runtime/src/snapshot/ref.ts
index 4e3fc14520..b082b79616 100644
--- a/packages/react/runtime/src/snapshot/ref.ts
+++ b/packages/react/runtime/src/snapshot/ref.ts
@@ -3,9 +3,9 @@
// LICENSE file in the root directory of this source tree.
import type { Element, Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
-import type { SnapshotInstance } from '../snapshot.js';
import { workletUnRef } from './workletRef.js';
import { RefProxy } from '../lifecycle/ref/delay.js';
+import type { SnapshotInstance } from '../snapshot/snapshot.js';
const refsToClear: Ref[] = [];
const refsToApply: (Ref | [snapshotInstanceId: number, expIndex: number])[] = [];
diff --git a/packages/react/runtime/src/snapshot.ts b/packages/react/runtime/src/snapshot/snapshot.ts
similarity index 66%
rename from packages/react/runtime/src/snapshot.ts
rename to packages/react/runtime/src/snapshot/snapshot.ts
index 6dadcc6c87..be32ed7b1f 100644
--- a/packages/react/runtime/src/snapshot.ts
+++ b/packages/react/runtime/src/snapshot/snapshot.ts
@@ -3,125 +3,27 @@
// LICENSE file in the root directory of this source tree.
/**
- * Core snapshot system that implements a compiler-hinted virtual DOM.
+ * Main thread snapshot implementation that runs in the main thread.
*
- * Key components:
- * 1. {@link Snapshot}: Template definition generated at compile time
- * 2. {@link SnapshotInstance}: Runtime instance in the main thread
- * 3. {@link BackgroundSnapshotInstance}: Runtime instance in the background thread
- *
- * The system uses static analysis to identify dynamic parts and generate
- * optimized update instructions, avoiding full virtual DOM diffing.
+ * This is the mirror of background's {@link BackgroundSnapshotInstance}:
*/
import type { Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
-import type { BackgroundSnapshotInstance } from './backgroundSnapshot.js';
-import { clearSnapshotVNodeSource, moveSnapshotVNodeSource } from './debug/vnodeSource.js';
-import { SnapshotOperation, __globalSnapshotPatch } from './lifecycle/patch/snapshotPatch.js';
-import { ListUpdateInfoRecording } from './listUpdateInfo.js';
-import { __pendingListUpdates } from './pendingListUpdates.js';
-import { DynamicPartType } from './snapshot/dynamicPartType.js';
-import { snapshotDestroyList } from './snapshot/list.js';
-import type { PlatformInfo } from './snapshot/platformInfo.js';
-import { unref } from './snapshot/ref.js';
-import { isDirectOrDeepEqual } from './utils.js';
-
-/**
- * A snapshot definition that contains all the information needed to create and update elements
- * This is generated at compile time through static analysis of the JSX
- */
-export interface Snapshot {
- create: null | ((ctx: SnapshotInstance) => FiberElement[]);
- update: null | ((ctx: SnapshotInstance, index: number, oldValue: any) => void)[];
- slot: [DynamicPartType, number][];
-
- isListHolder?: boolean;
- cssId?: number | undefined;
- entryName?: string | undefined;
- refAndSpreadIndexes?: number[] | null;
-}
-
-export let __page: FiberElement;
-export let __pageId = 0;
-export function setupPage(page: FiberElement): void {
- __page = page;
- __pageId = __GetElementUniqueID(page);
-}
-
-export function clearPage(): void {
- __page = undefined as unknown as FiberElement;
- __pageId = 0;
-}
-
-export const __DynamicPartChildren_0: [DynamicPartType, number][] = [[DynamicPartType.Children, 0]];
-
-export const snapshotManager: {
- values: Map;
-} = {
- values: /* @__PURE__ */ new Map([
- [
- 'root',
- {
- create() {
- /* v8 ignore start */
- if (__JS__ && !__DEV__) {
- return [];
- }
- /* v8 ignore stop */
- return [__page!];
- },
- update: [],
- slot: __DynamicPartChildren_0,
- isListHolder: false,
- cssId: 0,
- },
- ],
- [
- 'wrapper',
- {
- create() {
- /* v8 ignore start */
- if (__JS__ && !__DEV__) {
- return [];
- }
- /* v8 ignore stop */
- return [__CreateWrapperElement(__pageId)];
- },
- update: [],
- slot: __DynamicPartChildren_0,
- isListHolder: false,
- },
- ],
- [
- null as unknown as string,
- {
- create() {
- /* v8 ignore start */
- if (__JS__ && !__DEV__) {
- return [];
- }
- /* v8 ignore stop */
- return [__CreateRawText('')];
- },
- update: [
- ctx => {
- /* v8 ignore start */
- if (__JS__ && !__DEV__) {
- return;
- }
- /* v8 ignore stop */
- if (ctx.__elements) {
- __SetAttribute(ctx.__elements[0]!, 'text', ctx.__values![0]);
- }
- },
- ],
- slot: [],
- isListHolder: false,
- },
- ],
- ]),
-};
+import { clearSnapshotVNodeSource } from '../debug/vnodeSource.js';
+import { SnapshotOperation, __globalSnapshotPatch } from '../lifecycle/patch/snapshotPatch.js';
+import { ListUpdateInfoRecording } from '../listUpdateInfo.js';
+import { __pendingListUpdates } from '../pendingListUpdates.js';
+import { DEFAULT_CSS_ID, DEFAULT_ENTRY_NAME } from './constants.js';
+import { snapshotManager } from './definition.js';
+import type { Snapshot } from './definition.js';
+import { DynamicPartType, __DynamicPartChildren_0 } from './dynamicPartType.js';
+import { snapshotDestroyList } from './list.js';
+import type { PlatformInfo } from './platformInfo.js';
+import { unref } from './ref.js';
+import type { SerializedSnapshotInstance } from './types.js';
+import { traverseSnapshotInstance } from './utils.js';
+import { isDirectOrDeepEqual } from '../utils.js';
export const snapshotInstanceManager: {
nextId: number;
@@ -165,135 +67,6 @@ if (__DEV__ && __JS__) {
});
}
-export const backgroundSnapshotInstanceManager: {
- nextId: number;
- values: Map;
- clear(): void;
- updateId(id: number, newId: number): void;
- getValueBySign(str: string): unknown;
-} = {
- nextId: 0,
- values: /* @__PURE__ */ new Map(),
- clear() {
- // not resetting `nextId` to prevent id collision
- this.values.clear();
- if (__DEV__) {
- clearSnapshotVNodeSource();
- }
- },
- updateId(id: number, newId: number) {
- const values = this.values;
- const si = values.get(id)!;
- // For PreactDevtools, on first hydration,
- // PreactDevtools can get the real snapshot instance id in main-thread
- if (__DEV__ && __BACKGROUND__) {
- lynx.getJSModule('GlobalEventEmitter').emit('onBackgroundSnapshotInstanceUpdateId', [
- {
- backgroundSnapshotInstance: si,
- oldId: id,
- newId,
- },
- ]);
- }
- values.delete(id);
- values.set(newId, si);
- si.__id = newId;
- if (__DEV__) {
- moveSnapshotVNodeSource(id, newId);
- }
- },
- getValueBySign(str: string): unknown {
- const res = str?.split(':');
- if (!res || (res.length != 2 && res.length != 3)) {
- throw new Error('Invalid ctx format: ' + str);
- }
- const id = Number(res[0]);
- const expIndex = Number(res[1]);
- const ctx = this.values.get(id);
- if (!ctx) {
- return null;
- }
- const spreadKey = res[2];
- if (res[1] === '__extraProps') {
- if (spreadKey) {
- return ctx.__extraProps![spreadKey];
- }
- throw new Error('unreachable');
- } else {
- if (spreadKey) {
- return (ctx.__values![expIndex] as { [spreadKey]: unknown })[spreadKey];
- } else {
- return ctx.__values![expIndex];
- }
- }
- },
-};
-
-export function entryUniqID(uniqID: string, entryName?: string): string {
- return entryName ? `${entryName}:${uniqID}` : uniqID;
-}
-
-export function createSnapshot(
- uniqID: string,
- create: Snapshot['create'] | null,
- update: Snapshot['update'] | null,
- slot: Snapshot['slot'],
- cssId: number | undefined,
- entryName: string | undefined,
- refAndSpreadIndexes: number[] | null,
- isLazySnapshotSupported: boolean = false,
-): string {
- if (!isLazySnapshotSupported) {
- uniqID = entryUniqID(uniqID, entryName);
- }
- // For Lazy Bundle, their entryName is not DEFAULT_ENTRY_NAME.
- // We need to set the entryName correctly for HMR
- if (
- __DEV__ && __JS__ && __globalSnapshotPatch && entryName && entryName !== DEFAULT_ENTRY_NAME
- // `uniqID` will be `https://example.com/main.lynx.bundle:__snapshot_835da_eff1e_1` when loading a standalone lazy bundle after hydration.
- && !uniqID.includes(':')
- ) {
- __globalSnapshotPatch.push(
- SnapshotOperation.DEV_ONLY_SetSnapshotEntryName,
- uniqID,
- entryName,
- );
- }
-
- const s: Snapshot = { create, update, slot, cssId, entryName, refAndSpreadIndexes };
- snapshotManager.values.set(uniqID, s);
- if (slot && slot[0] && slot[0][0] === DynamicPartType.ListChildren) {
- s.isListHolder = true;
- }
- return uniqID;
-}
-
-export interface WithChildren {
- childNodes: WithChildren[];
-}
-
-export function traverseSnapshotInstance(
- si: I,
- callback: (si: I) => void,
-): void {
- const c = si.childNodes;
- callback(si);
- for (const vv of c) {
- traverseSnapshotInstance(vv as I, callback);
- }
-}
-
-export interface SerializedSnapshotInstance {
- id: number;
- type: string;
- values?: any[] | undefined;
- extraProps?: Record | undefined;
- children?: SerializedSnapshotInstance[] | undefined;
-}
-
-const DEFAULT_ENTRY_NAME = '__Card__';
-const DEFAULT_CSS_ID = 0;
-
/**
* The runtime instance of a {@link Snapshot} on the main thread that manages
* the actual elements and handles updates to dynamic parts.
diff --git a/packages/react/runtime/src/snapshotInstanceHydrationMap.ts b/packages/react/runtime/src/snapshot/snapshotInstanceHydrationMap.ts
similarity index 100%
rename from packages/react/runtime/src/snapshotInstanceHydrationMap.ts
rename to packages/react/runtime/src/snapshot/snapshotInstanceHydrationMap.ts
diff --git a/packages/react/runtime/src/snapshot/spread.ts b/packages/react/runtime/src/snapshot/spread.ts
index c7f12d5c9f..14e8edb3fd 100644
--- a/packages/react/runtime/src/snapshot/spread.ts
+++ b/packages/react/runtime/src/snapshot/spread.ts
@@ -11,10 +11,10 @@
import type { Element, Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
-import type { BackgroundSnapshotInstance } from '../backgroundSnapshot.js';
+import type { BackgroundSnapshotInstance } from './backgroundSnapshot.js';
import { ListUpdateInfoRecording } from '../listUpdateInfo.js';
import { __pendingListUpdates } from '../pendingListUpdates.js';
-import { SnapshotInstance } from '../snapshot.js';
+import { SnapshotInstance } from '../snapshot/snapshot.js';
import { isDirectOrDeepEqual, isEmptyObject, pick } from '../utils.js';
import { updateEvent } from './event.js';
import { updateGesture } from './gesture.js';
diff --git a/packages/react/runtime/src/snapshot/types.ts b/packages/react/runtime/src/snapshot/types.ts
new file mode 100644
index 0000000000..4cae2d1dc8
--- /dev/null
+++ b/packages/react/runtime/src/snapshot/types.ts
@@ -0,0 +1,25 @@
+// Copyright 2024 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+/**
+ * Type definitions for snapshot system.
+ */
+
+/**
+ * Interface for objects that have child nodes.
+ */
+export interface WithChildren {
+ childNodes: WithChildren[];
+}
+
+/**
+ * Serialized snapshot instance for communication between threads.
+ */
+export interface SerializedSnapshotInstance {
+ id: number;
+ type: string;
+ values?: any[] | undefined;
+ extraProps?: Record | undefined;
+ children?: SerializedSnapshotInstance[] | undefined;
+}
diff --git a/packages/react/runtime/src/snapshot/utils.ts b/packages/react/runtime/src/snapshot/utils.ts
new file mode 100644
index 0000000000..eba5156353
--- /dev/null
+++ b/packages/react/runtime/src/snapshot/utils.ts
@@ -0,0 +1,30 @@
+// Copyright 2024 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+/**
+ * Utility functions for snapshot system.
+ */
+
+import type { WithChildren } from './types.js';
+
+/**
+ * Generates a unique ID for a snapshot entry by combining the entry name and unique ID.
+ */
+export function entryUniqID(uniqID: string, entryName?: string): string {
+ return entryName ? `${entryName}:${uniqID}` : uniqID;
+}
+
+/**
+ * Traverses a snapshot instance tree and calls the callback for each node.
+ */
+export function traverseSnapshotInstance(
+ si: I,
+ callback: (si: I) => void,
+): void {
+ const c = si.childNodes;
+ callback(si);
+ for (const vv of c) {
+ traverseSnapshotInstance(vv as I, callback);
+ }
+}
diff --git a/packages/react/runtime/src/snapshot/workletEvent.ts b/packages/react/runtime/src/snapshot/workletEvent.ts
index 8a04726384..88f8262198 100644
--- a/packages/react/runtime/src/snapshot/workletEvent.ts
+++ b/packages/react/runtime/src/snapshot/workletEvent.ts
@@ -6,7 +6,7 @@ import type { Worklet } from '@lynx-js/react/worklet-runtime/bindings';
import { describeInvalidValue } from '../debug/describeInvalidValue.js';
import { isMainThreadHydrating } from '../lifecycle/patch/isMainThreadHydrating.js';
-import { SnapshotInstance } from '../snapshot.js';
+import { SnapshotInstance } from '../snapshot/snapshot.js';
function formatEventAttribute(workletType: string, eventType: string, eventName: string): string {
const suffix = eventType.endsWith('Event') ? eventType.slice(0, -'Event'.length) : eventType;
diff --git a/packages/react/runtime/src/snapshot/workletRef.ts b/packages/react/runtime/src/snapshot/workletRef.ts
index 32953e6330..293806d5fb 100644
--- a/packages/react/runtime/src/snapshot/workletRef.ts
+++ b/packages/react/runtime/src/snapshot/workletRef.ts
@@ -6,7 +6,7 @@ import { onWorkletCtxUpdate, runWorkletCtx, updateWorkletRef as update } from '@
import type { Element, Worklet, WorkletRefImpl } from '@lynx-js/react/worklet-runtime/bindings';
import { isMainThreadHydrating } from '../lifecycle/patch/isMainThreadHydrating.js';
-import type { SnapshotInstance } from '../snapshot.js';
+import type { SnapshotInstance } from '../snapshot/snapshot.js';
let mtRefQueue: (WorkletRefImpl | Worklet | Element)[] = [];
diff --git a/packages/react/testing-library/src/__tests__/act.test.jsx b/packages/react/testing-library/src/__tests__/act.test.jsx
index cc1e04329f..fbd2970ccf 100644
--- a/packages/react/testing-library/src/__tests__/act.test.jsx
+++ b/packages/react/testing-library/src/__tests__/act.test.jsx
@@ -7,7 +7,7 @@ import { createRef } from 'preact';
import { Component } from 'preact';
import { expect } from 'vitest';
import { __globalSnapshotPatch } from '../../../runtime/lib/lifecycle/patch/snapshotPatch.js';
-import { snapshotInstanceManager } from '../../../runtime/lib/snapshot.js';
+import { snapshotInstanceManager } from '../../../runtime/lib/snapshot/index.js';
test('render calls useEffect immediately', async () => {
const cb = vi.fn();
diff --git a/packages/react/testing-library/src/__tests__/end-to-end.test.jsx b/packages/react/testing-library/src/__tests__/end-to-end.test.jsx
index 4a0f1aa25c..1308f62876 100644
--- a/packages/react/testing-library/src/__tests__/end-to-end.test.jsx
+++ b/packages/react/testing-library/src/__tests__/end-to-end.test.jsx
@@ -2,7 +2,7 @@ import '@testing-library/jest-dom';
import { Component } from 'preact';
import { expect } from 'vitest';
import { render, screen, waitForElementToBeRemoved } from '..';
-import { snapshotInstanceManager } from '../../../runtime/lib/snapshot.js';
+import { snapshotInstanceManager } from '../../../runtime/lib/snapshot/index.js';
const fetchAMessage = () =>
new Promise((resolve) => {
diff --git a/packages/react/testing-library/src/pure.jsx b/packages/react/testing-library/src/pure.jsx
index a8b6fbdcbb..4eaa962281 100644
--- a/packages/react/testing-library/src/pure.jsx
+++ b/packages/react/testing-library/src/pure.jsx
@@ -9,7 +9,7 @@ import { act } from 'preact/test-utils';
import { __root } from '@lynx-js/react/internal';
import { flushDelayedLifecycleEvents } from '../../runtime/lib/lynx/tt.js';
-import { clearPage } from '../../runtime/lib/snapshot.js';
+import { clearPage } from '../../runtime/lib/snapshot/index.js';
export function waitSchedule() {
return new Promise(resolve => {
diff --git a/packages/react/testing-library/src/vitest-global-setup.js b/packages/react/testing-library/src/vitest-global-setup.js
index 70e627e480..e3161d5afb 100644
--- a/packages/react/testing-library/src/vitest-global-setup.js
+++ b/packages/react/testing-library/src/vitest-global-setup.js
@@ -1,7 +1,6 @@
import { options } from 'preact';
import { expect } from 'vitest';
-import { BackgroundSnapshotInstance } from '../../runtime/lib/backgroundSnapshot.js';
import { clearCommitTaskId, replaceCommitHook } from '../../runtime/lib/lifecycle/patch/commit.js';
import { deinitGlobalSnapshotPatch } from '../../runtime/lib/lifecycle/patch/snapshotPatch.js';
import { injectUpdateMainThread } from '../../runtime/lib/lifecycle/patch/updateMainThread.js';
@@ -13,9 +12,10 @@ import { addCtxNotFoundEventListener } from '../../runtime/lib/lifecycle/patch/e
import { setRoot } from '../../runtime/lib/root.js';
import {
SnapshotInstance,
+ BackgroundSnapshotInstance,
backgroundSnapshotInstanceManager,
snapshotInstanceManager,
-} from '../../runtime/lib/snapshot.js';
+} from '../../runtime/lib/snapshot/index.js';
import { destroyWorklet } from '../../runtime/lib/worklet/destroy.js';
import { initApiEnv } from '../../worklet-runtime/lib/api/lynxApi.js';
import { initEventListeners } from '../../worklet-runtime/lib/listeners.js';