Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/all-melons-fall.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 2 additions & 0 deletions packages/web-platform/web-constants/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ export const __lynx_timing_flag = '__lynx_timing_flag' as const;

export const globalMuteableVars = [
'registerDataProcessor',
'registerWorkletInternal',
'lynxWorkletImpl',
] as const;
1 change: 1 addition & 0 deletions packages/web-platform/web-core/src/utils/loadTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const mainThreadInjectVars = [
'__SetCSSId',
'__OnLifecycleEvent',
'__FlushElementTree',
'__LoadLepusChunk',
];

const backgroundInjectVars = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export function createMainThreadLynx(
lepusRuntime: MainThreadRuntime,
) {
return {
getJSContext() {
// TODO: implement this
return new EventTarget();
},
requestAnimationFrame(cb: FrameRequestCallback) {
return requestAnimationFrame(cb);
},
Expand All @@ -23,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;
Expand All @@ -39,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@ export class MainThreadRuntime {
},
set: (v: any) => {
this.__lynxGlobalBindingValues[nm] = v;
this._updateVars?.();
for (const handler of this.__varsUpdateHandlers) {
handler();
}
},
});
}
Expand Down Expand Up @@ -237,6 +239,10 @@ export class MainThreadRuntime {
};

updatePage?: (data: Cloneable, options?: Record<string, string>) => void;
runWorklet?: (obj: unknown, event: unknown) => void;

_updateVars?: () => void;
private __varsUpdateHandlers: (() => void)[] = [];
set _updateVars(handler: () => void) {
this.__varsUpdateHandlers.push(handler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ export interface LynxRuntimeInfo {
eventHandlerMap: Record<string, {
capture: {
type: LynxEventType;
handler: string;
handler: string | { type: 'worklet'; value: unknown };
} | undefined;
bind: {
type: LynxEventType;
handler: string;
handler: string | { type: 'worklet'; value: unknown };
} | undefined;
}>;
componentAtIndex?: ComponentAtIndexCallback;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
LynxEventNameToW3cCommon,
lynxTagAttribute,
W3cEventNameToLynx,
type LynxCrossThreadEvent,
type LynxEventType,
} from '@lynx-js/web-constants';
import {
Expand All @@ -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,
Expand All @@ -58,6 +57,8 @@ export function createEventFunctions(runtime: MainThreadRuntime) {
);
}
return true;
} else if (hname) {
runtime.runWorklet?.(hname.value, []);
}
return false;
};
Expand All @@ -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';
Expand Down Expand Up @@ -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');
Expand All @@ -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,
});
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'",
Expand Down
14 changes: 14 additions & 0 deletions packages/web-platform/web-tests/tests/react.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

const expectHasText = async (page: Page, text: string) => {
const hasText = (await page.getByText(text).count()) === 1;
await expect(hasText).toBe(true);

Check failure on line 37 in packages/web-platform/web-tests/tests/react.spec.ts

View workflow job for this annotation

GitHub Actions / playwright-linux / check

[webkit] › tests/react.spec.ts:104:5 › reactlynx3 tests › basic › basic-setstate-in-constructor

3) [webkit] › tests/react.spec.ts:104:5 › reactlynx3 tests › basic › basic-setstate-in-constructor Error: expect(received).toBe(expected) // Object.is equality Expected: true Received: false 35 | const expectHasText = async (page: Page, text: string) => { 36 | const hasText = (await page.getByText(text).count()) === 1; > 37 | await expect(hasText).toBe(true); | ^ 38 | }; 39 | 40 | const expectNoText = async (page: Page, text: string) => { at expectHasText (/home/runner/_work/lynx-stack/lynx-stack/packages/web-platform/web-tests/tests/react.spec.ts:37:25) at /home/runner/_work/lynx-stack/lynx-stack/packages/web-platform/web-tests/tests/react.spec.ts:107:7

Check failure on line 37 in packages/web-platform/web-tests/tests/react.spec.ts

View workflow job for this annotation

GitHub Actions / playwright-linux / check

[webkit] › tests/react.spec.ts:109:5 › reactlynx3 tests › basic › basic-setsate-with-cb

4) [webkit] › tests/react.spec.ts:109:5 › reactlynx3 tests › basic › basic-setsate-with-cb ─────── Error: expect(received).toBe(expected) // Object.is equality Expected: true Received: false 35 | const expectHasText = async (page: Page, text: string) => { 36 | const hasText = (await page.getByText(text).count()) === 1; > 37 | await expect(hasText).toBe(true); | ^ 38 | }; 39 | 40 | const expectNoText = async (page: Page, text: string) => { at expectHasText (/home/runner/_work/lynx-stack/lynx-stack/packages/web-platform/web-tests/tests/react.spec.ts:37:25) at /home/runner/_work/lynx-stack/lynx-stack/packages/web-platform/web-tests/tests/react.spec.ts:112:7
};

const expectNoText = async (page: Page, text: string) => {
Expand Down Expand Up @@ -79,7 +79,7 @@
await wait(100);
const target = page.locator('#target');
await target.click();
await expect(await target.getAttribute('style')).toContain('green');

Check failure on line 82 in packages/web-platform/web-tests/tests/react.spec.ts

View workflow job for this annotation

GitHub Actions / playwright-linux / check

[webkit] › tests/react.spec.ts:77:5 › reactlynx3 tests › basic › basic-bindtap

2) [webkit] › tests/react.spec.ts:77:5 › reactlynx3 tests › basic › basic-bindtap ──────────────── Error: expect(received).toContain(expected) // indexOf Expected substring: "green" Received string: "height: 100px; width: 100px; background: pink;" 80 | const target = page.locator('#target'); 81 | await target.click(); > 82 | await expect(await target.getAttribute('style')).toContain('green'); | ^ 83 | await target.click(); 84 | await expect(await target.getAttribute('style')).toContain('pink'); 85 | }); at /home/runner/_work/lynx-stack/lynx-stack/packages/web-platform/web-tests/tests/react.spec.ts:82:56
await target.click();
await expect(await target.getAttribute('style')).toContain('pink');
});
Expand Down Expand Up @@ -255,6 +255,20 @@
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 }) => {
Expand Down Expand Up @@ -994,7 +1008,7 @@
await target.click();
await expect(await target.getAttribute('style')).toContain('green');
await target.click();
await expect(await target.getAttribute('style')).toContain('pink');

Check failure on line 1011 in packages/web-platform/web-tests/tests/react.spec.ts

View workflow job for this annotation

GitHub Actions / playwright-linux / check

[firefox] › tests/react.spec.ts:1004:5 › reactlynx3 tests › configs › config-mode-dev-with-all-in-one

7) [firefox] › tests/react.spec.ts:1004:5 › reactlynx3 tests › configs › config-mode-dev-with-all-in-one Error: expect(received).toContain(expected) // indexOf Expected substring: "pink" Received string: "height: 100px; width: 100px; background: green;" 1009 | await expect(await target.getAttribute('style')).toContain('green'); 1010 | await target.click(); > 1011 | await expect(await target.getAttribute('style')).toContain('pink'); | ^ 1012 | }); 1013 | 1014 | test( at /home/runner/_work/lynx-stack/lynx-stack/packages/web-platform/web-tests/tests/react.spec.ts:1011:56
});

test(
Expand Down Expand Up @@ -1538,7 +1552,7 @@
}) => {
await goto(page, title);
await wait(300);
await page.evaluate(() => {

Check failure on line 1555 in packages/web-platform/web-tests/tests/react.spec.ts

View workflow job for this annotation

GitHub Actions / playwright-linux / check

[webkit] › tests/react.spec.ts:1548:7 › reactlynx3 tests › elements › scroll-view › basic-element-scroll-view-event-scrollend

5) [webkit] › tests/react.spec.ts:1548:7 › reactlynx3 tests › elements › scroll-view › basic-element-scroll-view-event-scrollend Error: page.evaluate: TypeError: null is not an object (evaluating 'document.querySelector('lynx-view').shadowRoot.querySelector('scroll-view').scrollTop = 200') 1553 | await goto(page, title); 1554 | await wait(300); > 1555 | await page.evaluate(() => { | ^ 1556 | document.querySelector('lynx-view')!.shadowRoot!.querySelector( 1557 | 'scroll-view', 1558 | )!.scrollTop = 200; at /home/runner/_work/lynx-stack/lynx-stack/packages/web-platform/web-tests/tests/react.spec.ts:1555:22
document.querySelector('lynx-view')!.shadowRoot!.querySelector(
'scroll-view',
)!.scrollTop = 200;
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<view
id='target'
main-thread:bindTap={() => {
'main thread';
console.log('hello world');
}}
style={{
height: '100px',
width: '100px',
background: color,
}}
/>
);
}
root.render(<App />);
2 changes: 1 addition & 1 deletion packages/web-platform/web-worker-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ self.onmessage = (ev) => {
}
};
Object.assign(globalThis, {
SystemInfo: { platform: 'web' },
SystemInfo: { platform: 'web', lynxSdkVersion: '3.0' },
module: { exports: null },
});
6 changes: 5 additions & 1 deletion packages/webpack/web-webpack-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: '',
Expand Down
Loading