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
14 changes: 14 additions & 0 deletions .changeset/lemon-colts-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@lynx-js/web-mainthread-apis": patch
"@lynx-js/web-core-server": patch
"@lynx-js/web-constants": patch
"@lynx-js/web-core": patch
---

feat: move SSR hydrate essential info to the ssr attribute

We found that in browser there is no simple tool to decode a base64 string

Therefore we move the data to `ssr` attribute

Also fix some ssr issues
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ export interface MainThreadGlobalThis {
lynx: MainThreadLynx;
processData?: ProcessDataCallback;
ssrEncode?: () => string;
ssrHydrate?: (encodeData?: string) => void;
ssrHydrate?: (encodeData?: string | null) => void;
_ReportError: (error: Error, _: unknown) => void;
_SetSourceMapRelease: (errInfo: JSErrorInfo) => void;
__OnLifecycleEvent: (lifeCycleEvent: Cloneable) => void;
Expand Down
17 changes: 17 additions & 0 deletions packages/web-platform/web-constants/src/types/SSR.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { AddEventPAPI } from './MainThreadGlobalThis.js';

export type SSREventReplayInfo = [
number,
Parameters<AddEventPAPI>[1],
Parameters<AddEventPAPI>[2],
Parameters<AddEventPAPI>[3],
];

export type SSRDumpInfo = {
ssrEncodeData: string | null | undefined;
events: SSREventReplayInfo[];
};

export type SSRDehydrateHooks = {
__AddEvent: AddEventPAPI;
};
1 change: 1 addition & 0 deletions packages/web-platform/web-constants/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * from './MainThreadLynx.js';
export * from './I18n.js';
export * from './BackThreadStartConfigs.js';
export * from './MarkTiming.js';
export * from './SSR.js';
43 changes: 20 additions & 23 deletions packages/web-platform/web-core-server/src/createLynxView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import {
inShadowRootStyles,
lynxPartIdAttribute,
lynxUniqueIdAttribute,
type AddEventPAPI,
type InitI18nResources,
type StartMainThreadContextConfig,
type SSREventReplayInfo,
type SSRDumpInfo,
} from '@lynx-js/web-constants';
import { Rpc } from '@lynx-js/web-worker-rpc';
import { prepareMainThreadAPIs } from '@lynx-js/web-mainthread-apis';
Expand Down Expand Up @@ -117,6 +118,7 @@ export async function createLynxView(
},
});
const i18nResources = new I18nResources();
const events: SSREventReplayInfo[] = [];
const { startMainThread } = prepareMainThreadAPIs(
backgroundThreadRpc,
offscreenDocument,
Expand All @@ -140,6 +142,16 @@ export async function createLynxView(
i18nResources.setData(initI18nResources);
return i18nResources;
},
{
__AddEvent(element, eventName, eventData, eventOptions) {
events.push([
Number(element.getAttribute(lynxUniqueIdAttribute)!),
eventName,
eventData,
eventOptions,
]);
},
},
);
const runtime = await startMainThread({
template,
Expand All @@ -155,17 +167,6 @@ export async function createLynxView(
initI18nResources,
});

const events: [
number,
Parameters<AddEventPAPI>[1],
Parameters<AddEventPAPI>[2],
Parameters<AddEventPAPI>[3],
][] = [];
runtime.__AddEvent = (element, eventType, eventName, newEventHandler) => {
const uniqueId = runtime.__GetElementUniqueID(element);
events.push([uniqueId, eventType, eventName, newEventHandler]);
};

const elementTemplates = {
...builtinElementTemplates,
...overrideElementTemplates,
Expand All @@ -174,11 +175,17 @@ export async function createLynxView(
async function renderToString(): Promise<string> {
await firstPaintReadyPromise;
const ssrEncodeData = runtime?.ssrEncode?.();
const ssrDumpInfo: SSRDumpInfo = {
ssrEncodeData,
events,
};
const buffer: string[] = [];
buffer.push(
'<lynx-view url="',
hydrateUrl,
'" ssr ',
'" ssr ="',
encodeURI(JSON.stringify(ssrDumpInfo)),
'" ',
'thread-strategy="',
threadStrategy,
'"',
Expand All @@ -205,16 +212,6 @@ export async function createLynxView(
buffer.push(
'</template>',
);

if (ssrEncodeData) {
buffer.push(
'<!--',
Buffer.from(JSON.stringify({ ssrEncodeData, events })).toString(
'base64',
),
'-->',
); // encodeURI to avoid XSS
}
buffer.push('</lynx-view>');
return buffer.join('');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
type MinimalRawEventObject,
type I18nResourceTranslationOptions,
lynxDisposedAttribute,
type SSRDehydrateHooks,
} from '@lynx-js/web-constants';
import { globalMuteableVars } from '@lynx-js/web-constants';
import { createMainThreadLynx } from './createMainThreadLynx.js';
Expand Down Expand Up @@ -149,6 +150,7 @@ export interface MainThreadRuntimeConfig {
& Pick<Element, 'append' | 'addEventListener'>
& Partial<Pick<Element, 'querySelectorAll'>>;
jsContext: LynxContextEventTarget;
ssrHooks?: SSRDehydrateHooks;
}

export function createMainThreadGlobalThis(
Expand All @@ -166,6 +168,7 @@ export function createMainThreadGlobalThis(
rootDom,
globalProps,
styleInfo,
ssrHooks,
} = config;
const lynxUniqueIdToElement: WeakRef<WebFiberElementImpl>[] = [];
const elementToRuntimeInfoMap: WeakMap<WebFiberElementImpl, LynxRuntimeInfo> =
Expand Down Expand Up @@ -669,7 +672,7 @@ export function createMainThreadGlobalThis(
: undefined,
__MarkTemplateElement,
__MarkPartElement,
__AddEvent,
__AddEvent: ssrHooks?.__AddEvent ?? __AddEvent,
__GetEvent,
__GetEvents,
__SetEvents,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
type I18nResources,
dispatchI18nResourceEndpoint,
type Cloneable,
type SSRDehydrateHooks,
} from '@lynx-js/web-constants';
import { registerCallLepusMethodHandler } from './crossThreadHandlers/registerCallLepusMethodHandler.js';
import { registerGetCustomSectionHandler } from './crossThreadHandlers/registerGetCustomSectionHandler.js';
Expand All @@ -47,6 +48,7 @@ export function prepareMainThreadAPIs(
options: I18nResourceTranslationOptions,
) => void,
initialI18nResources: (data: InitI18nResources) => I18nResources,
ssrHooks?: SSRDehydrateHooks,
) {
const postTimingFlags = backgroundThreadRpc.createCall(
postTimingFlagsEndpoint,
Expand Down Expand Up @@ -115,6 +117,7 @@ export function prepareMainThreadAPIs(
styleInfo,
lepusCode: lepusCodeLoaded,
rootDom,
ssrHooks,
callbacks: {
mainChunkReady: () => {
markTimingInternal('data_processor_start');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,12 @@ export const __SetInlineStyles: SetInlineStylesPAPI = /*#__PURE__*/ (
element.setAttribute('style', transformInlineStyleString(value));
} else {
const { transformedStyle } = transformParsedStyles(
Object.entries(value).map(([k, value]) => [
hyphenateStyleName(k),
value,
]),
Object.entries(value).map(([k, value]) =>
[
hyphenateStyleName(k),
value?.toString?.() ?? '',
] as [string, string]
),
);
const transformedStyleStr = transformedStyle.map((
[property, value],
Expand Down

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions packages/web-platform/web-tests/tests/server.vitest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ describe('server-tests', () => {
const html = await genTemplate('config-css-selector-false-exchange-class');
expect(html).toContain('[l-uid="2"]');
});

test('basic-bindtap-contains-bind-event', async () => {
const html = await genTemplate('basic-bindtap');
expect(html).toContain('bindEvent');
});
});
Loading