@sigx/lynx-plugin
v0.2.7
Published
Rspack/Rspeedy plugin for SignalX Lynx dual-thread rendering
Readme
@sigx/lynx-plugin
Rspack/Rspeedy plugin for SignalX on Lynx. Splits a single user app into the two bundles Lynx requires (background JS + main-thread Lepus) and runs the SWC worklet transform that powers 'main thread'-marked event handlers.
Installation
npm install -D @sigx/lynx-plugin// rspeedy.config.ts (or rspack.config.ts)
import { defineConfig } from '@lynx-js/rspeedy';
import { sigxLynxPlugin } from '@sigx/lynx-plugin';
export default defineConfig({
plugins: [sigxLynxPlugin()],
});What it does
Two-bundle split. Lynx ships JS to two contexts on the device:
- The background bundle — your sigx components, signals, effects, fetch logic.
- The main-thread bundle — only the worklet handlers extracted from your source, plus the runtime bootstrap.
The plugin sets up a separate webpack rule so user source files are processed twice: once with the BG-target transform, once with the LEPUS-target transform.
Worklet transform. Files containing the string
'main thread'are run through@lynx-js/react/transform. The transform:- Replaces a worklet expression in the BG bundle with a
{_wkltId, _c}placeholder so the BG renderer can reference it without shipping the function body. - Emits
registerWorkletInternal("main-thread", "<id>", function(...) { ... })calls into the MT bundle so Lynx native can invoke the worklet body when it dispatches a touch event.
- Replaces a worklet expression in the BG bundle with a
MT-bundle bootstrap. Every file in the MT bundle gets three side-effect imports prepended:
@sigx/lynx-runtime-main/entry-main— installs theprocessData/renderPage/sigxPatchUpdateglobals Lynx expects.@lynx-js/react/runtime/worklet-runtime/main.js— populateslynxWorkletImpl,registerWorkletInternal,runWorklet.@sigx/lynx-runtime-main/install-hybrid-worklet— registers the hybrid dispatcher used by thebindtap+main-thread-bindtapslot machine.
Listing them as separate entries in webpack isn't sufficient because the chunk graph can evaluate user code before the bootstrap chain. Prepending side-effect imports per-file forces the dep-graph order.
Workspace import preservation. Top-level imports of
@sigx/*packages (e.g.import { Draggable } from '@sigx/gestures') are preserved as side-effect imports on the MT layer, so workspace component packages that ship MT worklets get walked by webpack and theirregisterWorkletInternalcalls land in the MT bundle.
Worklet author quick reference
Mark an event handler as MT-thread by adding the directive as the first statement:
<view
main-thread-bindtap={(e) => {
'main thread';
elRef.current?.setStyleProperties({ opacity: '0.5' });
}}
/>The plugin handles the rest — the handler body lives in the MT bundle, the BG bundle keeps a {_wkltId, _c} placeholder, and Lynx native dispatches the touch event directly to the MT thread.
For higher-level abstractions (drag, tap, swipe, animations), see @sigx/gestures.
Limitations
- Custom worklet bodies require
'main thread'directives. Worklets aren't auto-detected from JSX shape; the directive is the marker. - Variables declared inside a worklet body are MT-locals. They can't cross the bridge via
runOnBackgroundclosure capture — pass them as arguments instead. See@sigx/gesturesREADME, "Performance notes." - Mappers for
useAnimatedStyleship as MT-side code. Custom mappers must be registered from a MT-side module viaregisterMapper(name, fn)— BG-sideuseAnimatedStyleonly carries the name across the build pipeline.
License
MIT
