diff --git a/.changeset/forty-jars-scream.md b/.changeset/forty-jars-scream.md new file mode 100644 index 0000000000..63660e9287 --- /dev/null +++ b/.changeset/forty-jars-scream.md @@ -0,0 +1,12 @@ +--- +"@lynx-js/web-mainthread-apis": patch +"@lynx-js/web-core-server": patch +"@lynx-js/web-constants": patch +"@lynx-js/web-core": patch +--- + +feat: add `_SetSourceMapRelease(errInfo)` MTS API. + +You can get `errInfo.release` through `e.detail.release` in the error event callback of lynx-view. + +The `_SetSourceMapRelease` function is not complete yet, because it is currently limited by the Web platform and some functions and some props such as `err.stack` do not need to be supported for the time being. diff --git a/packages/web-platform/web-constants/src/endpoints.ts b/packages/web-platform/web-constants/src/endpoints.ts index ec2bb4c707..5136a138ea 100644 --- a/packages/web-platform/web-constants/src/endpoints.ts +++ b/packages/web-platform/web-constants/src/endpoints.ts @@ -79,7 +79,7 @@ export const BackgroundThreadStartEndpoint = createRpcEndpoint<[ * Error message, info */ export const reportErrorEndpoint = createRpcEndpoint< - [Error, unknown], + [Error, unknown, string], void >('reportError', false, false); diff --git a/packages/web-platform/web-constants/src/types/MainThreadGlobalThis.ts b/packages/web-platform/web-constants/src/types/MainThreadGlobalThis.ts index df66387ae9..1d3e2bed5e 100644 --- a/packages/web-platform/web-constants/src/types/MainThreadGlobalThis.ts +++ b/packages/web-platform/web-constants/src/types/MainThreadGlobalThis.ts @@ -267,6 +267,10 @@ export type GetTemplatePartsPAPI = ( templateElement: WebFiberElementImpl, ) => Record | undefined; +interface JSErrorInfo { + release: string; +} + export interface MainThreadGlobalThis { __AddEvent: AddEventPAPI; __GetEvent: GetEventPAPI; @@ -327,6 +331,7 @@ export interface MainThreadGlobalThis { ssrEncode?: () => string; ssrHydrate?: (encodeData?: string) => void; _ReportError: (error: Error, _: unknown) => void; + _SetSourceMapRelease: (errInfo: JSErrorInfo) => void; __OnLifecycleEvent: (lifeCycleEvent: Cloneable) => void; __LoadLepusChunk: (path: string) => boolean; __FlushElementTree: ( diff --git a/packages/web-platform/web-core-server/src/utils/loadTemplate.ts b/packages/web-platform/web-core-server/src/utils/loadTemplate.ts index 12905ffc59..05371be3d3 100644 --- a/packages/web-platform/web-core-server/src/utils/loadTemplate.ts +++ b/packages/web-platform/web-core-server/src/utils/loadTemplate.ts @@ -61,6 +61,7 @@ const mainThreadInjectVars = [ 'lynx', 'globalThis', '_ReportError', + '_SetSourceMapRelease', '__AddConfig', '__AddDataset', '__GetAttributes', diff --git a/packages/web-platform/web-core/src/apis/LynxView.ts b/packages/web-platform/web-core/src/apis/LynxView.ts index f2fe54c941..bea55ae9de 100644 --- a/packages/web-platform/web-core/src/apis/LynxView.ts +++ b/packages/web-platform/web-core/src/apis/LynxView.ts @@ -439,7 +439,7 @@ export class LynxView extends HTMLElement { napiModulesCall: (...args) => { return this.#onNapiModulesCall?.(...args); }, - onError: (error: Error) => { + onError: (error: Error, release: string) => { this.dispatchEvent( new CustomEvent('error', { detail: { @@ -450,6 +450,7 @@ export class LynxView extends HTMLElement { }, }, error, + release, }, }), ); diff --git a/packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts b/packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts index d5a933fa12..65be43157f 100644 --- a/packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts +++ b/packages/web-platform/web-core/src/uiThread/createRenderAllOnUI.ts @@ -26,7 +26,7 @@ export function createRenderAllOnUI( timeStamp?: number, ) => void, callbacks: { - onError?: (err: Error) => void; + onError?: (err: Error, release: string) => void; }, ) { if (!globalThis.module) { @@ -48,8 +48,8 @@ export function createRenderAllOnUI( document.createElement.bind(document), () => {}, markTimingInternal, - (err) => { - callbacks.onError?.(err); + (err, _, release) => { + callbacks.onError?.(err, release); }, triggerI18nResourceFallback, (initI18nResources: InitI18nResources) => { diff --git a/packages/web-platform/web-core/src/uiThread/createRenderMultiThread.ts b/packages/web-platform/web-core/src/uiThread/createRenderMultiThread.ts index f25994af03..046db5cb44 100644 --- a/packages/web-platform/web-core/src/uiThread/createRenderMultiThread.ts +++ b/packages/web-platform/web-core/src/uiThread/createRenderMultiThread.ts @@ -12,7 +12,7 @@ export function createRenderMultiThread( mainThreadRpc: Rpc, shadowRoot: ShadowRoot, callbacks: { - onError?: (err: Error) => void; + onError?: (err: Error, release: string) => void; }, ) { registerReportErrorHandler( diff --git a/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerReportErrorHandler.ts b/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerReportErrorHandler.ts index 835bc52353..82ea5334c5 100644 --- a/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerReportErrorHandler.ts +++ b/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerReportErrorHandler.ts @@ -6,12 +6,12 @@ import type { Rpc } from '@lynx-js/web-worker-rpc'; export function registerReportErrorHandler( rpc: Rpc, - onError?: (e: Error) => void, + onError?: (e: Error, release: string) => void, ) { rpc.registerHandler( reportErrorEndpoint, - (e) => { - onError?.(e); + (e, _, release) => { + onError?.(e, release); }, ); } diff --git a/packages/web-platform/web-core/src/uiThread/startUIThread.ts b/packages/web-platform/web-core/src/uiThread/startUIThread.ts index a00bf0af53..d38d1a1e41 100644 --- a/packages/web-platform/web-core/src/uiThread/startUIThread.ts +++ b/packages/web-platform/web-core/src/uiThread/startUIThread.ts @@ -22,7 +22,7 @@ import { createRenderAllOnUI } from './createRenderAllOnUI.js'; export type StartUIThreadCallbacks = { nativeModulesCall: NativeModulesCall; napiModulesCall: NapiModulesCall; - onError?: (err: Error) => void; + onError?: (err: Error, release: string) => void; customTemplateLoader?: (url: string) => Promise; }; diff --git a/packages/web-platform/web-core/src/utils/loadTemplate.ts b/packages/web-platform/web-core/src/utils/loadTemplate.ts index eb1d099780..cea1590899 100644 --- a/packages/web-platform/web-core/src/utils/loadTemplate.ts +++ b/packages/web-platform/web-core/src/utils/loadTemplate.ts @@ -48,6 +48,7 @@ const mainThreadInjectVars = [ 'lynx', 'globalThis', '_ReportError', + '_SetSourceMapRelease', '__AddConfig', '__AddDataset', '__GetAttributes', diff --git a/packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts b/packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts index 6b2366385f..b2a5265f53 100644 --- a/packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts +++ b/packages/web-platform/web-mainthread-apis/src/createMainThreadGlobalThis.ts @@ -619,6 +619,7 @@ export function createMainThreadGlobalThis( return pageElement; }; + let release = ''; const isCSSOG = !pageConfig.enableCSSSelector; const mtsGlobalThis: MainThreadGlobalThis = { __AddEvent, @@ -679,7 +680,8 @@ export function createMainThreadGlobalThis( ...config.browserConfig, }, lynx: createMainThreadLynx(config), - _ReportError: callbacks._ReportError, + _ReportError: (err, _) => callbacks._ReportError(err, _, release), + _SetSourceMapRelease: (errInfo) => release = errInfo?.release, __OnLifecycleEvent: callbacks.__OnLifecycleEvent, __FlushElementTree, __lynxGlobalBindingValues: lynxGlobalBindingValues, diff --git a/packages/web-platform/web-tests/shell-project/mainthread-test.ts b/packages/web-platform/web-tests/shell-project/mainthread-test.ts index d805a900b0..bc47da2ebe 100644 --- a/packages/web-platform/web-tests/shell-project/mainthread-test.ts +++ b/packages/web-platform/web-tests/shell-project/mainthread-test.ts @@ -130,7 +130,7 @@ function initializeMainThreadTest() { docu.commit(); decodeOperation(elementOperations); }, - _ReportError: function(error: string, info?: unknown): void { + _ReportError: function(): void { document.body.innerHTML = ''; }, __OnLifecycleEvent() { @@ -146,6 +146,7 @@ function initializeMainThreadTest() { }); }, createElement: docu.createElement.bind(docu), + _I18nResourceTranslation: () => {}, }, }); const originalGlobalThis = globalThis; diff --git a/packages/web-platform/web-tests/tests/react.spec.ts b/packages/web-platform/web-tests/tests/react.spec.ts index 2bcea7c9b1..64675e2718 100644 --- a/packages/web-platform/web-tests/tests/react.spec.ts +++ b/packages/web-platform/web-tests/tests/react.spec.ts @@ -667,6 +667,28 @@ test.describe('reactlynx3 tests', () => { await wait(500); expect(offset).toBe(true); }); + test('api-set-release', async ({ page }, { title }) => { + let success = false; + await page.on('console', async (msg) => { + const event = await msg.args()[0]?.evaluate((e) => { + return { + type: e.type, + release: e.detail?.release, + }; + }); + if (!event || event.type !== 'error') { + return; + } + if ( + typeof event.release === 'string' && event.release === '1' + ) { + success = true; + } + }); + await goto(page, title); + await wait(500); + expect(success).toBe(true); + }); test('api-preheat', async ({ page }, { title }) => { await goto(page, title); diff --git a/packages/web-platform/web-tests/tests/react/api-set-release/index.jsx b/packages/web-platform/web-tests/tests/react/api-set-release/index.jsx new file mode 100644 index 0000000000..86973c24b4 --- /dev/null +++ b/packages/web-platform/web-tests/tests/react/api-set-release/index.jsx @@ -0,0 +1,13 @@ +// 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 { root } from '@lynx-js/react'; + +function App() { + if (__MAIN_THREAD__) { + _SetSourceMapRelease({ release: '1' }); + } + throw new Error('error'); +} + +root.render();