From bcbe72c67e98d5ced29be4948c781086fa69eb0f Mon Sep 17 00:00:00 2001 From: pupiltong <12288479+PupilTong@users.noreply.github.com> Date: Mon, 7 Apr 2025 12:56:42 +0800 Subject: [PATCH 1/5] feat: implement mts event handler support and update related constants now the main-thread:bindxx handler could be invoked. The params of the handler will be implemented later. --- .changeset/all-melons-fall.md | 11 +++++++ .../web-constants/src/constants.ts | 2 ++ .../web-core/src/utils/loadTemplate.ts | 1 + .../web-mainthread-apis/src/MainThreadLynx.ts | 6 +++- .../src/MainThreadRuntime.ts | 10 +++++-- .../src/elementAPI/ElementThreadElement.ts | 4 +-- .../src/elementAPI/event/eventFunctions.ts | 29 +++++++++---------- .../web-tests/tests/react.spec.ts | 14 +++++++++ .../tests/react/basic-mts-bindtap/index.jsx | 22 ++++++++++++++ .../web-worker-runtime/src/index.ts | 2 +- .../webpack/web-webpack-plugin/src/index.ts | 6 +++- 11 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 .changeset/all-melons-fall.md create mode 100644 packages/web-platform/web-tests/tests/react/basic-mts-bindtap/index.jsx diff --git a/.changeset/all-melons-fall.md b/.changeset/all-melons-fall.md new file mode 100644 index 0000000000..8cba95252c --- /dev/null +++ b/.changeset/all-melons-fall.md @@ -0,0 +1,11 @@ +--- +"@lynx-js/web-mainthread-apis": patch +"@lynx-js/web-worker-runtime": patch +"@lynx-js/web-constants": patch +"@lynx-js/web-webpack-plugin": patch +"@lynx-js/web-core": patch +--- + +feat: support mts event handler (1/n) + +now the main-thread:bind handler could be invoked. The params of the handler will be implemented later. diff --git a/packages/web-platform/web-constants/src/constants.ts b/packages/web-platform/web-constants/src/constants.ts index 78dbf5c1e2..5e007a1121 100644 --- a/packages/web-platform/web-constants/src/constants.ts +++ b/packages/web-platform/web-constants/src/constants.ts @@ -20,4 +20,6 @@ export const __lynx_timing_flag = '__lynx_timing_flag' as const; export const globalMuteableVars = [ 'registerDataProcessor', + 'registerWorkletInternal', + 'lynxWorkletImpl', ] as const; diff --git a/packages/web-platform/web-core/src/utils/loadTemplate.ts b/packages/web-platform/web-core/src/utils/loadTemplate.ts index f119ef7d1d..d153bfce9d 100644 --- a/packages/web-platform/web-core/src/utils/loadTemplate.ts +++ b/packages/web-platform/web-core/src/utils/loadTemplate.ts @@ -98,6 +98,7 @@ const mainThreadInjectVars = [ '__SetCSSId', '__OnLifecycleEvent', '__FlushElementTree', + '__LoadLepusChunk', ]; const backgroundInjectVars = [ diff --git a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts index 301972d977..29794249a9 100644 --- a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts +++ b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts @@ -12,6 +12,10 @@ export function createMainThreadLynx( lepusRuntime: MainThreadRuntime, ) { return { + getJSContext() { + // TODO: implment this + return new EventTarget(); + }, requestAnimationFrame(cb: FrameRequestCallback) { return requestAnimationFrame(cb); }, @@ -23,7 +27,7 @@ export function createMainThreadLynx( requireModule(path: string) { // @ts-expect-error if (self.WorkerGlobalScope) { - const mainfestUrl = config.lepusCode[`/${path}`]; + const mainfestUrl = config.lepusCode[`${path}`]; if (mainfestUrl) path = mainfestUrl; // @ts-expect-error importScripts(path); diff --git a/packages/web-platform/web-mainthread-apis/src/MainThreadRuntime.ts b/packages/web-platform/web-mainthread-apis/src/MainThreadRuntime.ts index 1b2b8bc35a..5a480c96a9 100644 --- a/packages/web-platform/web-mainthread-apis/src/MainThreadRuntime.ts +++ b/packages/web-platform/web-mainthread-apis/src/MainThreadRuntime.ts @@ -167,7 +167,9 @@ export class MainThreadRuntime { }, set: (v: any) => { this.__lynxGlobalBindingValues[nm] = v; - this._updateVars?.(); + for (const handler of this.__varsUpdateHandlers) { + handler(); + } }, }); } @@ -237,6 +239,10 @@ export class MainThreadRuntime { }; updatePage?: (data: Cloneable, options?: Record) => void; + runWorklet?: (obj: unknown, event: unknown) => void; - _updateVars?: () => void; + private __varsUpdateHandlers: (() => void)[] = []; + set _updateVars(handler: () => void) { + this.__varsUpdateHandlers.push(handler); + } } diff --git a/packages/web-platform/web-mainthread-apis/src/elementAPI/ElementThreadElement.ts b/packages/web-platform/web-mainthread-apis/src/elementAPI/ElementThreadElement.ts index 83af7ab62d..3e99998135 100644 --- a/packages/web-platform/web-mainthread-apis/src/elementAPI/ElementThreadElement.ts +++ b/packages/web-platform/web-mainthread-apis/src/elementAPI/ElementThreadElement.ts @@ -11,11 +11,11 @@ export interface LynxRuntimeInfo { eventHandlerMap: Record; componentAtIndex?: ComponentAtIndexCallback; diff --git a/packages/web-platform/web-mainthread-apis/src/elementAPI/event/eventFunctions.ts b/packages/web-platform/web-mainthread-apis/src/elementAPI/event/eventFunctions.ts index 1d3300ed2d..aa497e9ac5 100644 --- a/packages/web-platform/web-mainthread-apis/src/elementAPI/event/eventFunctions.ts +++ b/packages/web-platform/web-mainthread-apis/src/elementAPI/event/eventFunctions.ts @@ -7,7 +7,6 @@ import { LynxEventNameToW3cCommon, lynxTagAttribute, W3cEventNameToLynx, - type LynxCrossThreadEvent, type LynxEventType, } from '@lynx-js/web-constants'; import { @@ -31,7 +30,7 @@ export function createEventFunctions(runtime: MainThreadRuntime) { ?.handler : runtimeInfo.eventHandlerMap[lynxEventName]?.bind ?.handler; - if (hname) { + if (typeof hname === 'string') { const crossThreadEvent = createCrossThreadEvent( runtime, event, @@ -58,6 +57,8 @@ export function createEventFunctions(runtime: MainThreadRuntime) { ); } return true; + } else if (hname) { + runtime.runWorklet?.(hname.value, []); } return false; }; @@ -69,8 +70,7 @@ export function createEventFunctions(runtime: MainThreadRuntime) { element: HTMLElement, eventType: LynxEventType, eventName: string, - newEventHandler: string | undefined // | ((ev: LynxCrossThreadEvent) => void) | undefined, - , + newEventHandler: string | { type: 'worklet'; value: unknown } | undefined, ) { eventName = eventName.toLowerCase(); const isCatch = eventType === 'catchEvent' || eventType === 'capture-catch'; @@ -125,7 +125,7 @@ export function createEventFunctions(runtime: MainThreadRuntime) { element: HTMLElement, eventName: string, eventType: LynxEventType, - ): string | ((ev: LynxCrossThreadEvent) => void) | undefined { + ): string | { type: 'worklet'; value: unknown } | undefined { const runtimeInfo = runtime[elementToRuntimeInfoMap].get(element)!; eventName = eventName.toLowerCase(); const isCapture = eventType.startsWith('capture'); @@ -138,26 +138,25 @@ export function createEventFunctions(runtime: MainThreadRuntime) { function __GetEvents(element: HTMLElement): { type: LynxEventType; name: string; - function: string | ((ev: Event) => void) | undefined; + function: string | { type: 'worklet'; value: unknown } | undefined; }[] { const eventHandlerMap = runtime[elementToRuntimeInfoMap].get(element)!.eventHandlerMap; const eventInfos: { type: LynxEventType; name: string; - function: string | ((ev: Event) => void) | undefined; + function: string | { type: 'worklet'; value: unknown } | undefined; }[] = []; for (const [lynxEventName, info] of Object.entries(eventHandlerMap)) { for (const atomInfo of [info.bind, info.capture]) { if (atomInfo) { - for (const [type, handler] of Object.values(atomInfo)) { - if (handler) { - eventInfos.push({ - type: type as LynxEventType, - name: lynxEventName, - function: handler, - }); - } + const { type, handler } = atomInfo; + if (handler) { + eventInfos.push({ + type: type as LynxEventType, + name: lynxEventName, + function: handler, + }); } } } diff --git a/packages/web-platform/web-tests/tests/react.spec.ts b/packages/web-platform/web-tests/tests/react.spec.ts index 52167a631c..12126096a0 100644 --- a/packages/web-platform/web-tests/tests/react.spec.ts +++ b/packages/web-platform/web-tests/tests/react.spec.ts @@ -255,6 +255,20 @@ test.describe('reactlynx3 tests', () => { await expect(target).toHaveCSS('width', '100px'); await expect(target).toHaveCSS('background-color', 'rgb(255, 192, 203)'); }); + test('basic-mts-bindtap', async ({ page }, { title }) => { + let eventHandlerTriggered = false; + page.on('console', (message) => { + if (message.text() === 'hello world') { + eventHandlerTriggered = true; + } + }); + await goto(page, title); + await wait(100); + const target = page.locator('#target'); + await target.click(); + await wait(100); + expect(eventHandlerTriggered).toBe(true); + }); }); test.describe('basic-css', () => { test('basic-css-asset-in-css', async ({ page }, { title }) => { diff --git a/packages/web-platform/web-tests/tests/react/basic-mts-bindtap/index.jsx b/packages/web-platform/web-tests/tests/react/basic-mts-bindtap/index.jsx new file mode 100644 index 0000000000..3fff7e79bf --- /dev/null +++ b/packages/web-platform/web-tests/tests/react/basic-mts-bindtap/index.jsx @@ -0,0 +1,22 @@ +// Copyright 2023 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 { useState, root } from '@lynx-js/react'; +function App() { + const [color] = useState('pink'); + return ( + { + 'main thread'; + console.log('hello world'); + }} + style={{ + height: '100px', + width: '100px', + background: color, + }} + /> + ); +} +root.render(); diff --git a/packages/web-platform/web-worker-runtime/src/index.ts b/packages/web-platform/web-worker-runtime/src/index.ts index 8a297eb982..c455180429 100644 --- a/packages/web-platform/web-worker-runtime/src/index.ts +++ b/packages/web-platform/web-worker-runtime/src/index.ts @@ -23,6 +23,6 @@ self.onmessage = (ev) => { } }; Object.assign(globalThis, { - SystemInfo: { platform: 'web' }, + SystemInfo: { platform: 'web', lynxSdkVersion: '2.14' }, module: { exports: null }, }); diff --git a/packages/webpack/web-webpack-plugin/src/index.ts b/packages/webpack/web-webpack-plugin/src/index.ts index 484ed8c9bc..4e5bcb957c 100644 --- a/packages/webpack/web-webpack-plugin/src/index.ts +++ b/packages/webpack/web-webpack-plugin/src/index.ts @@ -68,7 +68,11 @@ export class WebWebpackPlugin { manifest: encodeOptions.manifest, cardType: encodeOptions['cardType'], pageConfig: encodeOptions.compilerOptions, - lepusCode: encodeOptions.lepusCode, + lepusCode: { + // flatten the lepusCode to a single object + ...encodeOptions.lepusCode.lepusChunk, + root: encodeOptions.lepusCode.root, + }, customSections: encodeOptions.customSections, })), debugInfo: '', From 1cde955452246de3be29ba2d8a2562abd9270581 Mon Sep 17 00:00:00 2001 From: pupiltong <12288479+PupilTong@users.noreply.github.com> Date: Mon, 7 Apr 2025 13:05:42 +0800 Subject: [PATCH 2/5] copilot comment --- .../web-platform/web-mainthread-apis/src/MainThreadLynx.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts index 29794249a9..3c00b5537b 100644 --- a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts +++ b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts @@ -27,8 +27,8 @@ export function createMainThreadLynx( requireModule(path: string) { // @ts-expect-error if (self.WorkerGlobalScope) { - const mainfestUrl = config.lepusCode[`${path}`]; - if (mainfestUrl) path = mainfestUrl; + const lepusChunkUrl = config.lepusCode[`${path}`]; + if (lepusChunkUrl) path = lepusChunkUrl; // @ts-expect-error importScripts(path); const entry = (globalThis.module as LynxJSModule).exports; From 038bba53108aa2c1c1ea603fd8da79e54a776086 Mon Sep 17 00:00:00 2001 From: pupiltong <12288479+PupilTong@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:14:46 +0800 Subject: [PATCH 3/5] fix tests --- .../web-platform/web-mainthread-apis/src/MainThreadLynx.ts | 4 ++-- .../web-tests/resources/web-core.main-thread.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts index 3c00b5537b..19ae5173d7 100644 --- a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts +++ b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts @@ -43,8 +43,8 @@ export function createMainThreadLynx( path: string, callback: (error: Error | null, exports?: unknown) => void, ) { - const mainfestUrl = config.lepusCode[`/${path}`]; - if (mainfestUrl) path = mainfestUrl; + const lepusChunkUrl = config.lepusCode[`${path}`]; + if (lepusChunkUrl) path = lepusChunkUrl; import( /* webpackIgnore: true */ path diff --git a/packages/web-platform/web-tests/resources/web-core.main-thread.json b/packages/web-platform/web-tests/resources/web-core.main-thread.json index 36503a8edc..2027acd174 100644 --- a/packages/web-platform/web-tests/resources/web-core.main-thread.json +++ b/packages/web-platform/web-tests/resources/web-core.main-thread.json @@ -2,8 +2,8 @@ "styleInfo": {}, "lepusCode": { "root": "self.runtime = lynx_runtime;self.__lynx_worker_type = 'main'; globalThis.registerDataProcessor='pass'; self.registerDataProcessor = registerDataProcessor;", - "/manifest-chunk.js": "module.exports = 'hello';", - "/manifest-chunk2.js": "module.exports = 'world';" + "manifest-chunk.js": "module.exports = 'hello';", + "manifest-chunk2.js": "module.exports = 'world';" }, "manifest": { "/app-service.js": "self.runtime = lynx_runtime; self.__lynx_worker_type = 'background'", From 8945b133c4121e9da66e9b8545d8ce287e0affa2 Mon Sep 17 00:00:00 2001 From: pupiltong <12288479+PupilTong@users.noreply.github.com> Date: Tue, 8 Apr 2025 14:07:44 +0800 Subject: [PATCH 4/5] set lynxSdkVersion to 3.0 --- packages/web-platform/web-worker-runtime/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-platform/web-worker-runtime/src/index.ts b/packages/web-platform/web-worker-runtime/src/index.ts index c455180429..499e6f76b1 100644 --- a/packages/web-platform/web-worker-runtime/src/index.ts +++ b/packages/web-platform/web-worker-runtime/src/index.ts @@ -23,6 +23,6 @@ self.onmessage = (ev) => { } }; Object.assign(globalThis, { - SystemInfo: { platform: 'web', lynxSdkVersion: '2.14' }, + SystemInfo: { platform: 'web', lynxSdkVersion: '3.0' }, module: { exports: null }, }); From 4bc79a7a81f2407e6b3d7d477700df7e04476cdb Mon Sep 17 00:00:00 2001 From: PupilTong <12288479+PupilTong@users.noreply.github.com> Date: Tue, 8 Apr 2025 14:11:53 +0800 Subject: [PATCH 5/5] Update packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: PupilTong <12288479+PupilTong@users.noreply.github.com> --- packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts index 19ae5173d7..98513c654a 100644 --- a/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts +++ b/packages/web-platform/web-mainthread-apis/src/MainThreadLynx.ts @@ -13,7 +13,7 @@ export function createMainThreadLynx( ) { return { getJSContext() { - // TODO: implment this + // TODO: implement this return new EventTarget(); }, requestAnimationFrame(cb: FrameRequestCallback) {