@sigx/lynx-runtime 0.4.0 → 0.4.1
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/dist/animated/animated-value.d.ts +2 -2
- package/dist/animated/animated-value.js +15 -0
- package/dist/animated/shared-value.d.ts +1 -1
- package/dist/animated/shared-value.js +94 -0
- package/dist/animated/use-animated-style.d.ts +3 -3
- package/dist/animated/use-animated-style.js +53 -0
- package/dist/animated-bridge.js +71 -0
- package/dist/bg-bridge.js +63 -0
- package/dist/event-registry.js +75 -0
- package/dist/flush.d.ts +1 -1
- package/dist/flush.js +8 -0
- package/dist/hmr.js +119 -39
- package/dist/index.d.ts +24 -22
- package/dist/index.js +37 -849
- package/dist/jsx.d.ts +29 -3
- package/dist/jsx.js +19 -0
- package/dist/main-thread-ref.js +134 -0
- package/dist/model-processor.js +76 -0
- package/dist/mt-hmr-bridge.js +125 -53
- package/dist/native/gesture-detector.d.ts +1 -1
- package/dist/native/gesture-detector.js +340 -0
- package/dist/native/index.d.ts +2 -2
- package/dist/native/index.js +1 -0
- package/dist/nodeOps.d.ts +1 -1
- package/dist/nodeOps.js +319 -0
- package/dist/op-queue.js +213 -0
- package/dist/render.d.ts +1 -1
- package/dist/render.js +125 -0
- package/dist/run-on-background.d.ts +1 -1
- package/dist/run-on-background.js +201 -0
- package/dist/shadow-element.js +91 -0
- package/dist/threading.d.ts +1 -1
- package/dist/threading.js +124 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +10 -0
- package/dist/use-element-layout.d.ts +72 -0
- package/dist/use-element-layout.js +40 -0
- package/package.json +10 -8
- package/dist/hmr.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mt-hmr-bridge.js.map +0 -1
package/dist/jsx.d.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* the imports — see lynx-runtime README for details.
|
|
18
18
|
*/
|
|
19
19
|
import type { Model } from '@sigx/runtime-core';
|
|
20
|
-
import type { MainThreadRef } from './main-thread-ref';
|
|
20
|
+
import type { MainThreadRef } from './main-thread-ref.js';
|
|
21
21
|
export type LynxEventHandler<E = any> = (event: E) => void;
|
|
22
22
|
export declare namespace MainThread {
|
|
23
23
|
/** Element handle available in main-thread event handlers via MainThreadRef.current. */
|
|
@@ -97,12 +97,21 @@ export interface LynxCommonAttributes {
|
|
|
97
97
|
catchtouchend?: LynxEventHandler;
|
|
98
98
|
bindtouchcancel?: LynxEventHandler;
|
|
99
99
|
catchtouchcancel?: LynxEventHandler;
|
|
100
|
+
/**
|
|
101
|
+
* Fires when this element's measured layout (frame, padding, border)
|
|
102
|
+
* changes. Lynx 3.7+. Works on any element; for `<text>` specifically
|
|
103
|
+
* see also the text-only `bindlayout` event which carries extra
|
|
104
|
+
* baseline/line metrics.
|
|
105
|
+
*/
|
|
106
|
+
bindlayoutchange?: LynxEventHandler;
|
|
107
|
+
catchlayoutchange?: LynxEventHandler;
|
|
100
108
|
onTap?: LynxEventHandler;
|
|
101
109
|
onLongpress?: LynxEventHandler;
|
|
102
110
|
onTouchstart?: LynxEventHandler;
|
|
103
111
|
onTouchmove?: LynxEventHandler;
|
|
104
112
|
onTouchend?: LynxEventHandler;
|
|
105
113
|
onTouchcancel?: LynxEventHandler;
|
|
114
|
+
onLayoutchange?: LynxEventHandler;
|
|
106
115
|
/** Bind a MainThreadRef to this element for synchronous MT access. */
|
|
107
116
|
'main-thread:ref'?: MainThreadRef<MainThread.Element | null>;
|
|
108
117
|
'main-thread-bindtap'?: LynxEventHandler;
|
|
@@ -129,8 +138,25 @@ export interface TextAttributes extends LynxCommonAttributes {
|
|
|
129
138
|
'number-of-lines'?: number;
|
|
130
139
|
/** Text overflow mode */
|
|
131
140
|
'text-overflow'?: 'clip' | 'ellipsis';
|
|
132
|
-
/**
|
|
133
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Enable native text selection (long-press to select, system context
|
|
143
|
+
* menu for copy/share). Lynx 3.7+.
|
|
144
|
+
*/
|
|
145
|
+
'text-selection'?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Suppress the system context menu after selection so the app can
|
|
148
|
+
* render its own. Only takes effect when `text-selection` is enabled.
|
|
149
|
+
* Lynx 3.7+.
|
|
150
|
+
*/
|
|
151
|
+
'custom-text-selection'?: boolean;
|
|
152
|
+
/** Fires when the selection range changes (selection start/end). */
|
|
153
|
+
bindselectionchange?: LynxEventHandler;
|
|
154
|
+
/** Fires when text layout is computed (frame/baseline/line metrics). */
|
|
155
|
+
bindlayout?: LynxEventHandler;
|
|
156
|
+
/** Convenience alias for `bindselectionchange`. */
|
|
157
|
+
onSelectionchange?: LynxEventHandler;
|
|
158
|
+
/** Convenience alias for `bindlayout`. */
|
|
159
|
+
onLayout?: LynxEventHandler;
|
|
134
160
|
}
|
|
135
161
|
export interface ImageAttributes extends LynxCommonAttributes {
|
|
136
162
|
/** Image source URI */
|
package/dist/jsx.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lynx JSX intrinsic element type definitions for SignalX.
|
|
3
|
+
*
|
|
4
|
+
* Importing this file (which happens automatically when you import
|
|
5
|
+
* `@sigx/lynx-runtime`) globally augments `JSX.IntrinsicElements` so
|
|
6
|
+
* that <view>, <text>, <image>, <scroll-view>, <list>, <list-item>,
|
|
7
|
+
* <input>, <textarea>, <page>, <svg>, <filter-image> are recognised
|
|
8
|
+
* with their proper attribute types.
|
|
9
|
+
*
|
|
10
|
+
* Same pattern as packages/runtime-dom/src/jsx.tsx (DOM elements) and
|
|
11
|
+
* packages/runtime-terminal/src/index.ts (<box>/<text>/<br>).
|
|
12
|
+
*
|
|
13
|
+
* Hybrid web+lynx codebases that import both @sigx/runtime-dom and
|
|
14
|
+
* @sigx/lynx-runtime will hit a TypeScript merge error on <input>
|
|
15
|
+
* because runtime-dom declares it via InputHTMLAttributes and we
|
|
16
|
+
* declare it via InputAttributes. Pick one platform per app or alias
|
|
17
|
+
* the imports — see lynx-runtime README for details.
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MainThreadRef — a ref whose `.current` value lives on the Main Thread.
|
|
3
|
+
*
|
|
4
|
+
* On the Background Thread, `.current` is always the initial value (typically
|
|
5
|
+
* `null`). On the Main Thread, `.current` is set to the real Lynx element
|
|
6
|
+
* handle when the ref is bound via `main-thread:ref={ref}`.
|
|
7
|
+
*
|
|
8
|
+
* This is the sigx equivalent of react-lynx's `useMainThreadRef()` and
|
|
9
|
+
* vue-lynx's `useMainThreadRef()`. It enables zero-latency style updates
|
|
10
|
+
* and animations by giving main-thread event handlers synchronous access
|
|
11
|
+
* to native elements.
|
|
12
|
+
*
|
|
13
|
+
* Architecture:
|
|
14
|
+
* BG: useMainThreadRef(init) → MainThreadRef { wvid, current: init }
|
|
15
|
+
* → pushOp(INIT_MT_REF, wvid, init)
|
|
16
|
+
* BG: patchProp('main-thread:ref', ref) → pushOp(SET_MT_REF, elId, wvid)
|
|
17
|
+
* MT: INIT_MT_REF → workletRefs.set(wvid, { current: init })
|
|
18
|
+
* MT: SET_MT_REF → workletRefs.get(wvid).current = elements.get(elId)
|
|
19
|
+
*/
|
|
20
|
+
import { onUnmounted } from '@sigx/runtime-core';
|
|
21
|
+
import { OP, pushOp, scheduleFlush } from './op-queue.js';
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Worklet variable ID generator
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
let nextWvid = 1;
|
|
26
|
+
export function resetWvidCounter() {
|
|
27
|
+
nextWvid = 1;
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// MainThreadRef class
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* A ref whose `.current` property is managed on the Main Thread.
|
|
34
|
+
*
|
|
35
|
+
* On the BG thread, `.current` returns the `initValue` and is read-only
|
|
36
|
+
* (setting it has no effect — the real value lives on MT).
|
|
37
|
+
*
|
|
38
|
+
* In main-thread event handlers and `runOnMainThread` callbacks, `.current`
|
|
39
|
+
* is the real Lynx element handle with methods like `setStyleProperties()`,
|
|
40
|
+
* `getComputedStyleProperty()`, and `animate()`.
|
|
41
|
+
*/
|
|
42
|
+
export class MainThreadRef {
|
|
43
|
+
/**
|
|
44
|
+
* Worklet variable ID — uniquely identifies this ref across threads.
|
|
45
|
+
* Underscored to match the field name `transformWorklet` walks for
|
|
46
|
+
* in @lynx-js/react/worklet-runtime when expanding `_c` captures.
|
|
47
|
+
*/
|
|
48
|
+
_wvid;
|
|
49
|
+
/**
|
|
50
|
+
* Initial value snapshot — sent to MT in INIT_MT_REF and used by
|
|
51
|
+
* the worklet-runtime to seed the firstScreen ref map.
|
|
52
|
+
*/
|
|
53
|
+
_initValue;
|
|
54
|
+
/**
|
|
55
|
+
* On BG: the init value (read-only snapshot).
|
|
56
|
+
* On MT: the real element handle (set by SET_MT_REF op).
|
|
57
|
+
*/
|
|
58
|
+
current;
|
|
59
|
+
constructor(initValue) {
|
|
60
|
+
this._wvid = nextWvid++;
|
|
61
|
+
this._initValue = initValue;
|
|
62
|
+
this.current = initValue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Walk a captured `_c` map and serialize MainThreadRef instances to plain
|
|
67
|
+
* `{ _wvid, _initValue }` objects so they survive the JSON round-trip across
|
|
68
|
+
* the BG→MT bridge. Upstream's worklet-runtime walks `_c` looking for `_wvid`
|
|
69
|
+
* to recognize ref captures and resolve them via
|
|
70
|
+
* `lynxWorkletImpl._refImpl._workletRefMap`.
|
|
71
|
+
*
|
|
72
|
+
* Used by both the SET_WORKLET_EVENT path (`nodeOps.patchProp`) and the
|
|
73
|
+
* SET_GESTURE_DETECTOR path (`native/gesture-detector.ts`).
|
|
74
|
+
*/
|
|
75
|
+
export function sanitizeCaptured(captured) {
|
|
76
|
+
const out = {};
|
|
77
|
+
for (const k in captured) {
|
|
78
|
+
const v = captured[k];
|
|
79
|
+
if (v instanceof MainThreadRef) {
|
|
80
|
+
out[k] = { _wvid: v._wvid, _initValue: v._initValue };
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
out[k] = v;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// useMainThreadRef composable
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
/**
|
|
92
|
+
* Create a ref that provides synchronous access to a native element on the
|
|
93
|
+
* Main Thread. Bind it to an element via `main-thread:ref={ref}`.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```tsx
|
|
97
|
+
* const elRef = useMainThreadRef<MainThread.Element>(null);
|
|
98
|
+
*
|
|
99
|
+
* function handleScroll(e: ScrollEvent) {
|
|
100
|
+
* 'main thread';
|
|
101
|
+
* const offset = e.detail.scrollTop;
|
|
102
|
+
* elRef.current?.setStyleProperties({
|
|
103
|
+
* transform: `translateY(${-offset}px)`,
|
|
104
|
+
* });
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* return (
|
|
108
|
+
* <scroll-view
|
|
109
|
+
* main-thread-bindscroll={handleScroll}
|
|
110
|
+
* >
|
|
111
|
+
* <view main-thread:ref={elRef}>
|
|
112
|
+
* <text>Sticky header</text>
|
|
113
|
+
* </view>
|
|
114
|
+
* </scroll-view>
|
|
115
|
+
* );
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export function useMainThreadRef(initValue) {
|
|
119
|
+
const ref = new MainThreadRef(initValue);
|
|
120
|
+
// Tell the MT to create a worklet ref holder with this ID and initial value.
|
|
121
|
+
pushOp(OP.INIT_MT_REF, ref._wvid, initValue);
|
|
122
|
+
scheduleFlush();
|
|
123
|
+
// Release the holder when the owning component unmounts. Without this, the
|
|
124
|
+
// MT-side `_workletRefMap` grows monotonically across mount/unmount cycles
|
|
125
|
+
// (router-driven apps with frequent navigation hit this fastest).
|
|
126
|
+
// `onUnmounted` no-ops if called outside a component setup; callers that
|
|
127
|
+
// construct refs ad-hoc (e.g. tests) just won't get a release op, which is
|
|
128
|
+
// the same as today's behaviour.
|
|
129
|
+
onUnmounted(() => {
|
|
130
|
+
pushOp(OP.RELEASE_MT_REF, ref._wvid);
|
|
131
|
+
scheduleFlush();
|
|
132
|
+
});
|
|
133
|
+
return ref;
|
|
134
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-specific model processor for Lynx form elements.
|
|
3
|
+
*
|
|
4
|
+
* Wires sigx's `model={() => state.field}` two-way binding directive to
|
|
5
|
+
* Lynx's <input> and <textarea> elements. The processor runs at JSX
|
|
6
|
+
* creation time (called from runtime-core/jsx-runtime.ts when an
|
|
7
|
+
* intrinsic element has a `model` prop) and rewrites the props to:
|
|
8
|
+
*
|
|
9
|
+
* 1. Set the initial `value` from the bound state
|
|
10
|
+
* 2. Install a `bindinput` handler that pushes the new value back into state
|
|
11
|
+
*
|
|
12
|
+
* Lynx differs from DOM in two important ways:
|
|
13
|
+
*
|
|
14
|
+
* - Lynx <input> fires `bindinput` with `event.detail.value` containing
|
|
15
|
+
* the new text. There is no DOM-style `target.value` property — the
|
|
16
|
+
* value lives on the event detail object.
|
|
17
|
+
* - Lynx Go (and most current Lynx hosts) have no native checkbox or
|
|
18
|
+
* radio elements. We only handle text-style <input> and <textarea>
|
|
19
|
+
* here. Adding checkbox/radio later is straightforward — mirror the
|
|
20
|
+
* branches in packages/runtime-dom/src/model-processor.ts.
|
|
21
|
+
*
|
|
22
|
+
* Mirrors packages/runtime-dom/src/model-processor.ts.
|
|
23
|
+
*/
|
|
24
|
+
import { setPlatformModelProcessor } from '@sigx/runtime-core/internals';
|
|
25
|
+
setPlatformModelProcessor((type, props, [stateObj, key], _originalProps) => {
|
|
26
|
+
// Helper to set value — uses onUpdate handler if available (for props
|
|
27
|
+
// model forwarding through component boundaries).
|
|
28
|
+
const setValue = (v) => {
|
|
29
|
+
const updateHandler = stateObj[`onUpdate:${key}`];
|
|
30
|
+
if (typeof updateHandler === 'function') {
|
|
31
|
+
updateHandler(v);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
stateObj[key] = v;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
// Text <input>
|
|
38
|
+
if (type === 'input') {
|
|
39
|
+
props.value = stateObj[key] ?? '';
|
|
40
|
+
const existingBindInput = props.bindinput;
|
|
41
|
+
props.bindinput = (e) => {
|
|
42
|
+
const v = e?.detail?.value ?? '';
|
|
43
|
+
setValue(v);
|
|
44
|
+
if (existingBindInput)
|
|
45
|
+
existingBindInput(e);
|
|
46
|
+
};
|
|
47
|
+
const existingHandler = props['onUpdate:modelValue'];
|
|
48
|
+
props['onUpdate:modelValue'] = (v) => {
|
|
49
|
+
setValue(v);
|
|
50
|
+
if (existingHandler)
|
|
51
|
+
existingHandler(v);
|
|
52
|
+
};
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
// <textarea>
|
|
56
|
+
if (type === 'textarea') {
|
|
57
|
+
props.value = stateObj[key] ?? '';
|
|
58
|
+
const existingBindInput = props.bindinput;
|
|
59
|
+
props.bindinput = (e) => {
|
|
60
|
+
const v = e?.detail?.value ?? '';
|
|
61
|
+
setValue(v);
|
|
62
|
+
if (existingBindInput)
|
|
63
|
+
existingBindInput(e);
|
|
64
|
+
};
|
|
65
|
+
const existingHandler = props['onUpdate:modelValue'];
|
|
66
|
+
props['onUpdate:modelValue'] = (v) => {
|
|
67
|
+
setValue(v);
|
|
68
|
+
if (existingHandler)
|
|
69
|
+
existingHandler(v);
|
|
70
|
+
};
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
// Not handled — fall back to the generic modelValue/onUpdate:modelValue
|
|
74
|
+
// pair so component-level model forwarding still works.
|
|
75
|
+
return false;
|
|
76
|
+
});
|
package/dist/mt-hmr-bridge.js
CHANGED
|
@@ -1,58 +1,130 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BG → MT hot-update bridge.
|
|
4
|
+
*
|
|
5
|
+
* The MT bundle has rspack's HMR runtime in code (because `module.hot.accept`
|
|
6
|
+
* is referenced) but no transport feeding it updates. After a save, BG's HMR
|
|
7
|
+
* client patches App.tsx and re-renders, generating worklet placeholders with
|
|
8
|
+
* new content-hash `_wkltId`s. MT's `_workletMap` still holds the old IDs, so
|
|
9
|
+
* the lookup fails (`bind of undefined`) when the user taps.
|
|
10
|
+
*
|
|
11
|
+
* This bridge closes the gap. We hook the same `webpackHotUpdate` event the
|
|
12
|
+
* rspack HMR client subscribes to. On every cycle:
|
|
13
|
+
* 1. Fetch the matching `main__main-thread.<hash>.hot-update.js` over the
|
|
14
|
+
* dev server URL (`__webpack_require__.p`).
|
|
15
|
+
* 2. Extract every `registerWorkletInternal(...)` call from the response.
|
|
16
|
+
* 3. Forward the concatenated calls to MT via
|
|
17
|
+
* `callLepusMethod('sigxApplyMtHotUpdate', { code }, ...)`.
|
|
18
|
+
* The MT handler `eval`s them in the existing realm, registering the new IDs
|
|
19
|
+
* into the live `_workletMap` before the user taps a freshly re-rendered
|
|
20
|
+
* button.
|
|
21
|
+
*
|
|
22
|
+
* Loaded only in dev mode — wired into the BG entry by `lynx-plugin`'s
|
|
23
|
+
* `applyEntry` when `enabledHMR` is true.
|
|
24
|
+
*/
|
|
25
|
+
function findRspackEmitter() {
|
|
26
|
+
const cache = __webpack_require__?.c;
|
|
27
|
+
if (!cache)
|
|
28
|
+
return undefined;
|
|
29
|
+
for (const id in cache) {
|
|
30
|
+
if (!id.includes('@rspack') || !id.endsWith('emitter.js'))
|
|
31
|
+
continue;
|
|
32
|
+
const exp = cache[id]?.exports;
|
|
33
|
+
if (exp
|
|
34
|
+
&& typeof exp.on === 'function'
|
|
35
|
+
&& typeof exp.emit === 'function') {
|
|
36
|
+
return exp;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
9
40
|
}
|
|
41
|
+
// Defer subscription via a microtask: the entry chain prepends this bridge
|
|
42
|
+
// before `@rspack/core/hot/dev-server`, so at module-eval time the emitter
|
|
43
|
+
// isn't in the webpack cache yet. By the next microtask, dev-server has run
|
|
44
|
+
// its top-level code and the emitter module is cached.
|
|
10
45
|
Promise.resolve().then(() => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
46
|
+
const emitter = findRspackEmitter();
|
|
47
|
+
if (!emitter) {
|
|
48
|
+
console.log('[sigx-mt-hmr-bridge] rspack emitter not found — bridge inactive');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
emitter.on('webpackHotUpdate', () => {
|
|
52
|
+
fetchAndForward();
|
|
53
|
+
});
|
|
19
54
|
});
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
55
|
+
function fetchAndForward() {
|
|
56
|
+
// The `webpackHotUpdate` event payload is the *new* hash, but hot-update
|
|
57
|
+
// chunks are named with the *previous* hash (the "delta-from" hash). Use
|
|
58
|
+
// `__webpack_require__.hu` — same helper rspack's own loader uses — which
|
|
59
|
+
// reads `__webpack_require__.h()` to build the URL with the right hash.
|
|
60
|
+
const publicPath = __webpack_require__?.p ?? '';
|
|
61
|
+
const hu = __webpack_require__?.hu;
|
|
62
|
+
if (typeof hu !== 'function')
|
|
63
|
+
return;
|
|
64
|
+
const url = publicPath + hu('main__main-thread');
|
|
65
|
+
// Lynx's BG runtime doesn't have a working `fetch` for arbitrary URLs in
|
|
66
|
+
// many hosts; rspack's own HMR loader uses `lynx.requireModuleAsync` (see
|
|
67
|
+
// `loadUpdateChunk` in the BG bundle). It returns the parsed hot-update
|
|
68
|
+
// shape `{ modules, runtime }` — each `modules[id]` is the compiled JS
|
|
69
|
+
// factory function. We extract registerWorkletInternal calls from
|
|
70
|
+
// `factory.toString()` so we don't have to actually evaluate the factory
|
|
71
|
+
// (which would import worklet-runtime / install-hybrid into BG's webpack
|
|
72
|
+
// module graph, with unwanted side effects).
|
|
73
|
+
const requireModuleAsync = lynx?.requireModuleAsync;
|
|
74
|
+
if (typeof requireModuleAsync !== 'function')
|
|
75
|
+
return;
|
|
76
|
+
requireModuleAsync(url, (err, update) => {
|
|
77
|
+
if (err) {
|
|
78
|
+
console.log('[sigx-mt-hmr-bridge] requireModuleAsync failed:', String(err));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
let combined = '';
|
|
82
|
+
for (const id in update.modules) {
|
|
83
|
+
const factory = update.modules[id];
|
|
84
|
+
if (typeof factory === 'function')
|
|
85
|
+
combined += factory.toString() + '\n';
|
|
86
|
+
}
|
|
87
|
+
const code = extractRegistrations(combined);
|
|
88
|
+
if (!code)
|
|
89
|
+
return;
|
|
90
|
+
const app = lynx?.getNativeApp?.();
|
|
91
|
+
if (!app || typeof app.callLepusMethod !== 'function')
|
|
92
|
+
return;
|
|
93
|
+
app.callLepusMethod('sigxApplyMtHotUpdate', { code }, () => { });
|
|
94
|
+
});
|
|
39
95
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Extract `registerWorkletInternal(...)` calls from a hot-update body.
|
|
98
|
+
*
|
|
99
|
+
* Mirrors `lynx-plugin/src/loaders/worklet-utils.ts:extractRegistrations`
|
|
100
|
+
* (duplicated here to avoid a runtime → build-time dep). Bracket-depth count
|
|
101
|
+
* handles nested braces in the function body.
|
|
102
|
+
*/
|
|
103
|
+
function extractRegistrations(source) {
|
|
104
|
+
const out = [];
|
|
105
|
+
const marker = 'registerWorkletInternal(';
|
|
106
|
+
let from = 0;
|
|
107
|
+
while (true) {
|
|
108
|
+
const idx = source.indexOf(marker, from);
|
|
109
|
+
if (idx === -1)
|
|
110
|
+
break;
|
|
111
|
+
let depth = 0;
|
|
112
|
+
let i = idx + marker.length - 1; // points at the opening '('
|
|
113
|
+
for (; i < source.length; i++) {
|
|
114
|
+
const ch = source[i];
|
|
115
|
+
if (ch === '(')
|
|
116
|
+
depth++;
|
|
117
|
+
else if (ch === ')') {
|
|
118
|
+
depth--;
|
|
119
|
+
if (depth === 0)
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
let end = i + 1;
|
|
124
|
+
if (end < source.length && source[end] === ';')
|
|
125
|
+
end++;
|
|
126
|
+
out.push(source.slice(idx, end));
|
|
127
|
+
from = end;
|
|
128
|
+
}
|
|
129
|
+
return out.join('\n');
|
|
55
130
|
}
|
|
56
|
-
//#endregion
|
|
57
|
-
|
|
58
|
-
//# sourceMappingURL=mt-hmr-bridge.js.map
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* SET_MT_REF op (pushed during the first JSX render) is applied before
|
|
17
17
|
* the SET_GESTURE_DETECTOR op tries to resolve the workletRefMap entry.
|
|
18
18
|
*/
|
|
19
|
-
import { MainThreadRef } from '../main-thread-ref';
|
|
19
|
+
import { MainThreadRef } from '../main-thread-ref.js';
|
|
20
20
|
export declare const GestureType: {
|
|
21
21
|
readonly COMPOSED: -1;
|
|
22
22
|
readonly PAN: 0;
|