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
13 changes: 13 additions & 0 deletions .changeset/small-carpets-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@lynx-js/web-core": patch
---

feat: allow user to implement custom template load function

```js
lynxView.customTemplateLoader = (url) => {
return (await (await fetch(url, {
method: 'GET',
})).json());
};
```
10 changes: 10 additions & 0 deletions packages/web-platform/web-core/src/apis/LynxView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from './createLynxView.js';
import {
type Cloneable,
type LynxTemplate,
type NapiModulesCall,
type NapiModulesMap,
type NativeModulesCall,
Expand Down Expand Up @@ -44,6 +45,7 @@ export type INapiModulesCall = (
* @property {INapiModulesCall} onNapiModulesCall [optional] the NapiModule value handler.
* @property {"false" | "true" | null} injectHeadLinks [optional] @default true set it to "false" to disable injecting the <link href="" ref="stylesheet"> styles into shadowroot
* @property {number} lynxGroupId [optional] (attribute: "lynx-group-id") the background shared context id, which is used to share webworker between different lynx cards
* @property {(string)=>Promise<LynxTemplate>} customTemplateLoader [optional] the custom template loader, which is used to load the template
*
* @event error lynx card fired an error
*
Expand Down Expand Up @@ -293,6 +295,13 @@ export class LynxView extends HTMLElement {
}
}

/**
* @public
* allow user to customize the template loader
* @param url the url of the template
*/
customTemplateLoader?: (url: string) => Promise<LynxTemplate>;

/**
* @private the flag to group all changes into one render operation
*/
Expand Down Expand Up @@ -352,6 +361,7 @@ export class LynxView extends HTMLElement {
new CustomEvent('error', {}),
);
},
customTemplateLoader: this.customTemplateLoader,
},
});
this.#instance = lynxView;
Expand Down
1 change: 1 addition & 0 deletions packages/web-platform/web-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
// LICENSE file in the root directory of this source tree.
export { createLynxView } from './apis/createLynxView.js';
export { LynxView } from './apis/LynxView.js';
export type { LynxTemplate } from '@lynx-js/web-constants';
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
mainThreadStartEndpoint,
markTimingEndpoint,
sendGlobalEventEndpoint,
type LynxTemplate,
type MainThreadStartConfigs,
type NapiModulesCall,
type NativeModulesCall,
Expand All @@ -34,10 +35,10 @@ export function startUIThread(
nativeModulesCall: NativeModulesCall;
napiModulesCall: NapiModulesCall;
onError?: () => void;
customTemplateLoader?: (url: string) => Promise<LynxTemplate>;
},
): LynxView {
const createLynxStartTiming = performance.now() + performance.timeOrigin;
const { nativeModulesMap, napiModulesMap } = configs;
const {
mainThreadRpc,
backgroundRpc,
Expand All @@ -56,13 +57,11 @@ export function startUIThread(
};
markTimingInternal('create_lynx_start', undefined, createLynxStartTiming);
markTimingInternal('load_template_start');
loadTemplate(templateUrl).then((template) => {
loadTemplate(templateUrl, callbacks.customTemplateLoader).then((template) => {
markTimingInternal('load_template_end');
mainThreadStart({
...configs,
template,
nativeModulesMap,
napiModulesMap,
});
});
registerReportErrorHandler(
Expand Down
13 changes: 9 additions & 4 deletions packages/web-platform/web-core/src/utils/loadTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,17 @@ const backgroundInjectWithBind = [
'Component',
];

export async function loadTemplate(url: string): Promise<LynxTemplate> {
export async function loadTemplate(
url: string,
customTemplateLoader?: (url: string) => Promise<LynxTemplate>,
): Promise<LynxTemplate> {
const cachedTemplate = TemplateCache[url];
if (cachedTemplate) return cachedTemplate;
const template = (await (await fetch(url, {
method: 'GET',
})).json()) as LynxTemplate;
const template = customTemplateLoader
? await customTemplateLoader(url)
: (await (await fetch(url, {
method: 'GET',
})).json()) as LynxTemplate;
const decodedTemplate: LynxTemplate = {
...template,
lepusCode: generateJavascriptUrl(
Expand Down
30 changes: 30 additions & 0 deletions packages/web-platform/web-tests/shell-project/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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 type { LynxTemplate } from '@lynx-js/web-core';
import { lynxViewTests } from './lynx-view.ts';

const nativeModulesMap = {
Expand Down Expand Up @@ -45,6 +46,35 @@ if (casename) {
return data.color;
}
};
if (casename.includes('custom-template-loader')) {
lynxView.customTemplateLoader = async () => {
const template: LynxTemplate = {
styleInfo: {},
pageConfig: {
enableCSSSelector: true,
enableRemoveCSSScope: true,
defaultDisplayLinear: true,
defaultOverflowVisible: true,
},
customSections: {},
lepusCode: {
root: `

let root = __CreatePage('page', 0);
__AddInlineStyle(root, 'min-height', '80px');
__AddInlineStyle(root, 'width', '80px');
__AddInlineStyle(root, 'background', 'green');
__SetID(root, 'target');
__FlushElementTree();
`,
},
manifest: {
'/app-service.js': '',
},
};
return template;
};
}
});
if (casename2) {
lynxViewTests(lynxView2 => {
Expand Down
6 changes: 6 additions & 0 deletions packages/web-platform/web-tests/tests/react.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,12 @@ test.describe('reactlynx3 tests', () => {
});
});
test.describe('apis', () => {
test('api-custom-template-loader', async ({ page }, { title }) => {
await goto(page, title);
await wait(100);
const target = page.locator('#target');
await expect(target).toHaveCSS('background-color', 'rgb(0, 128, 0)'); // green
});
test('api-animation-event', async ({ page }, { title }) => {
await goto(page, title);
await page.locator('#tap1').click();
Expand Down