@lynx-js/web-mainthread-apis 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @lynx-js/web-mainthread-apis
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - fix: mts lynx will no longer provide requireModule, requireModuleAsync methods, which is aligned with Native. ([#537](https://github.com/lynx-family/lynx-stack/pull/537))
8
+
9
+ ### Patch Changes
10
+
11
+ - refactor: isolate SystemInfo ([#628](https://github.com/lynx-family/lynx-stack/pull/628))
12
+
13
+ Never assign `SystemInfo` on worker's self object.
14
+
15
+ - feat: support thread strategy `all-on-ui` ([#625](https://github.com/lynx-family/lynx-stack/pull/625))
16
+
17
+ ```html
18
+ <lynx-view thread-strategy="all-on-ui"></lynx-view>
19
+ ```
20
+
21
+ This will make the lynx's main-thread run on the UA's main thread.
22
+
23
+ Note that the `all-on-ui` does not support the HMR & chunk splitting yet.
24
+
25
+ - fix(web): `:root` not work on web platform ([#607](https://github.com/lynx-family/lynx-stack/pull/607))
26
+
27
+ Note: To solve this issue, you need to upgrade your `react-rsbuild-plugin`
28
+
29
+ - refactor: move mainthread impl into mainthread-api packages ([#622](https://github.com/lynx-family/lynx-stack/pull/622))
30
+
31
+ - fix(web): css selector not work for selectors with combinator and pseudo-class on WEB ([#608](https://github.com/lynx-family/lynx-stack/pull/608))
32
+
33
+ like `.parent > :not([hidden]) ~ :not([hidden])`
34
+
35
+ you will need to upgrade your `react-rsbuild-plugin` to fix this issue
36
+
37
+ - Updated dependencies [[`4ee0465`](https://github.com/lynx-family/lynx-stack/commit/4ee0465f6e5846a0d038b49d2a7c95e87c9e5c77), [`5a3d9af`](https://github.com/lynx-family/lynx-stack/commit/5a3d9afe52ba639987db124ca35580261e0718b5), [`5269cab`](https://github.com/lynx-family/lynx-stack/commit/5269cabef7609159bdd0dd14a03c5da667907424)]:
38
+ - @lynx-js/web-constants@0.13.0
39
+
3
40
  ## 0.12.0
4
41
 
5
42
  ### Patch Changes
@@ -1,11 +1,9 @@
1
- import { type MainThreadConfig, MainThreadRuntime } from './MainThreadRuntime.js';
2
- export declare function createMainThreadLynx(config: MainThreadConfig, lepusRuntime: MainThreadRuntime): {
1
+ import { type MainThreadConfig } from './MainThreadRuntime.js';
2
+ export declare function createMainThreadLynx(config: MainThreadConfig): {
3
3
  getJSContext(): import("@lynx-js/web-constants").LynxContextEventTarget;
4
4
  requestAnimationFrame(cb: FrameRequestCallback): number;
5
5
  cancelAnimationFrame(handler: number): void;
6
6
  __globalProps: unknown;
7
- requireModule(path: string): unknown;
8
- requireModuleAsync(path: string, callback: (error: Error | null, exports?: unknown) => void): void;
9
7
  getCustomSectionSync(key: string): import("@lynx-js/web-constants").Cloneable;
10
8
  markPipelineTiming: (pipelineId: string, timingKey: string) => void;
11
9
  };
@@ -1,5 +1,8 @@
1
- import { MainThreadRuntime, } from './MainThreadRuntime.js';
2
- export function createMainThreadLynx(config, lepusRuntime) {
1
+ // Copyright 2023 The Lynx Authors. All rights reserved.
2
+ // Licensed under the Apache License Version 2.0 that can be found in the
3
+ // LICENSE file in the root directory of this source tree.
4
+ import {} from './MainThreadRuntime.js';
5
+ export function createMainThreadLynx(config) {
3
6
  return {
4
7
  getJSContext() {
5
8
  return config.jsContext;
@@ -11,33 +14,6 @@ export function createMainThreadLynx(config, lepusRuntime) {
11
14
  return cancelAnimationFrame(handler);
12
15
  },
13
16
  __globalProps: config.globalProps,
14
- requireModule(path) {
15
- // @ts-expect-error
16
- if (self.WorkerGlobalScope) {
17
- const lepusChunkUrl = config.lepusCode[`${path}`];
18
- if (lepusChunkUrl)
19
- path = lepusChunkUrl;
20
- // @ts-expect-error
21
- importScripts(path);
22
- const entry = globalThis.module.exports;
23
- return entry?.(lepusRuntime);
24
- }
25
- else {
26
- throw new Error('importing scripts synchronously is only available for the multi-thread running mode');
27
- }
28
- },
29
- requireModuleAsync(path, callback) {
30
- const lepusChunkUrl = config.lepusCode[`${path}`];
31
- if (lepusChunkUrl)
32
- path = lepusChunkUrl;
33
- import(
34
- /* webpackIgnore: true */
35
- path).catch(callback).then(() => {
36
- const entry = globalThis.module.exports;
37
- const ret = entry?.(lepusRuntime);
38
- callback(null, ret);
39
- });
40
- },
41
17
  getCustomSectionSync(key) {
42
18
  return config.customSections[key]?.content;
43
19
  },
@@ -1,4 +1,4 @@
1
- import { type LynxTemplate, type PageConfig, type ProcessDataCallback, type StyleInfo, type FlushElementTreeOptions, type Cloneable, type BrowserConfig, type publishEventEndpoint, type publicComponentEventEndpoint, type reportErrorEndpoint, type RpcCallType, type postExposureEndpoint, type LynxContextEventTarget } from '@lynx-js/web-constants';
1
+ import { type LynxTemplate, type PageConfig, type ProcessDataCallback, type StyleInfo, type FlushElementTreeOptions, type Cloneable, type BrowserConfig, type publishEventEndpoint, type publicComponentEventEndpoint, type reportErrorEndpoint, type RpcCallType, type postExposureEndpoint, type LynxContextEventTarget, type LynxJSModule, systemInfo } from '@lynx-js/web-constants';
2
2
  import { type MainThreadLynx } from './MainThreadLynx.js';
3
3
  import type { LynxRuntimeInfo } from './elementAPI/ElementThreadElement.js';
4
4
  export interface MainThreadRuntimeCallbacks {
@@ -17,7 +17,7 @@ export interface MainThreadConfig {
17
17
  callbacks: MainThreadRuntimeCallbacks;
18
18
  styleInfo: StyleInfo;
19
19
  customSections: LynxTemplate['customSections'];
20
- lepusCode: LynxTemplate['lepusCode'];
20
+ lepusCode: Record<string, LynxJSModule>;
21
21
  browserConfig: BrowserConfig;
22
22
  tagMap: Record<string, string>;
23
23
  docu: Pick<Document, 'append' | 'createElement' | 'addEventListener'>;
@@ -70,6 +70,7 @@ export declare class MainThreadRuntime {
70
70
  */
71
71
  __lynxGlobalBindingValues: Record<string, any>;
72
72
  get globalThis(): this;
73
+ SystemInfo: typeof systemInfo;
73
74
  lynx: MainThreadLynx;
74
75
  __globalProps: unknown;
75
76
  processData?: ProcessDataCallback;
@@ -1,7 +1,7 @@
1
1
  // Copyright 2023 The Lynx Authors. All rights reserved.
2
2
  // Licensed under the Apache License Version 2.0 that can be found in the
3
3
  // LICENSE file in the root directory of this source tree.
4
- import { lynxUniqueIdAttribute, } from '@lynx-js/web-constants';
4
+ import { lynxUniqueIdAttribute, systemInfo, } from '@lynx-js/web-constants';
5
5
  import { globalMuteableVars } from '@lynx-js/web-constants';
6
6
  import { createMainThreadLynx } from './MainThreadLynx.js';
7
7
  import { initializeElementCreatingFunction } from './elementAPI/elementCreating/elementCreatingFunctions.js';
@@ -49,7 +49,7 @@ export class MainThreadRuntime {
49
49
  constructor(config) {
50
50
  this.config = config;
51
51
  this.__globalProps = config.globalProps;
52
- this.lynx = createMainThreadLynx(config, this);
52
+ this.lynx = createMainThreadLynx(config);
53
53
  /**
54
54
  * now create the style content
55
55
  * 1. flatten the styleInfo
@@ -63,7 +63,6 @@ export class MainThreadRuntime {
63
63
  const cssInJsInfo = this.config.pageConfig.enableCSSSelector
64
64
  ? {}
65
65
  : genCssInJsInfo(this.config.styleInfo);
66
- this._rootDom = this.config.docu.createElement('div');
67
66
  const cardStyleElement = this.config.docu.createElement('style');
68
67
  cardStyleElement.innerHTML = genCssContent(this.config.styleInfo, this.config.pageConfig);
69
68
  this._rootDom = this.config.docu;
@@ -74,6 +73,10 @@ export class MainThreadRuntime {
74
73
  Object.assign(this, createAttributeAndPropertyFunctions(this), domTreeApis, createEventFunctions(this), createStyleFunctions(this, cssInJsInfo), initializeElementCreatingFunction(this));
75
74
  this._ReportError = this.config.callbacks._ReportError;
76
75
  this.__OnLifecycleEvent = this.config.callbacks.__OnLifecycleEvent;
76
+ this.SystemInfo = {
77
+ ...systemInfo,
78
+ pixelRatio: config.browserConfig.pixelRatio,
79
+ };
77
80
  /**
78
81
  * Start the exposure service
79
82
  */
@@ -128,6 +131,7 @@ export class MainThreadRuntime {
128
131
  get globalThis() {
129
132
  return this;
130
133
  }
134
+ SystemInfo;
131
135
  lynx;
132
136
  __globalProps;
133
137
  processData;
@@ -135,18 +139,20 @@ export class MainThreadRuntime {
135
139
  _ReportError;
136
140
  __OnLifecycleEvent;
137
141
  __LoadLepusChunk = (path) => {
138
- try {
139
- this.lynx.requireModule(path);
142
+ const lepusModule = this.config.lepusCode[`${path}`];
143
+ if (lepusModule) {
144
+ const entry = lepusModule.exports;
145
+ entry?.(this);
140
146
  return true;
141
147
  }
142
- catch {
148
+ else {
149
+ return false;
143
150
  }
144
- return false;
145
151
  };
146
152
  __FlushElementTree = (_subTree, options) => {
147
153
  const timingFlags = this._timingFlags;
148
154
  this._timingFlags = [];
149
- if (this._page && !this._page.parentElement) {
155
+ if (this._page && !this._page.parentNode) {
150
156
  this._rootDom.append(this._page);
151
157
  }
152
158
  this.config.callbacks.flushElementTree(options, timingFlags);
@@ -0,0 +1,3 @@
1
+ import { type Rpc } from '@lynx-js/web-constants';
2
+ import type { MainThreadRuntime } from '../MainThreadRuntime.js';
3
+ export declare function registerCallLepusMethodHandler(rpc: Rpc, runtime: MainThreadRuntime): void;
@@ -0,0 +1,10 @@
1
+ // Copyright 2023 The Lynx Authors. All rights reserved.
2
+ // Licensed under the Apache License Version 2.0 that can be found in the
3
+ // LICENSE file in the root directory of this source tree.
4
+ import { callLepusMethodEndpoint } from '@lynx-js/web-constants';
5
+ export function registerCallLepusMethodHandler(rpc, runtime) {
6
+ rpc.registerHandler(callLepusMethodEndpoint, (methodName, data) => {
7
+ (runtime[methodName])(data);
8
+ });
9
+ }
10
+ //# sourceMappingURL=registerCallLepusMethodHandler.js.map
@@ -0,0 +1,2 @@
1
+ import { type LynxTemplate, type Rpc } from '@lynx-js/web-constants';
2
+ export declare function registerGetCustomSectionHandler(rpc: Rpc, customSections: LynxTemplate['customSections']): void;
@@ -0,0 +1,10 @@
1
+ // Copyright 2023 The Lynx Authors. All rights reserved.
2
+ // Licensed under the Apache License Version 2.0 that can be found in the
3
+ // LICENSE file in the root directory of this source tree.
4
+ import { getCustomSectionsEndpoint, } from '@lynx-js/web-constants';
5
+ export function registerGetCustomSectionHandler(rpc, customSections) {
6
+ rpc.registerHandler(getCustomSectionsEndpoint, (key) => {
7
+ return customSections[key]?.content;
8
+ });
9
+ }
10
+ //# sourceMappingURL=registerGetCustomSectionHandler.js.map
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
+ export { loadMainThread } from './loadMainThread.js';
1
2
  export * from './MainThreadRuntime.js';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // Copyright 2023 The Lynx Authors. All rights reserved.
2
2
  // Licensed under the Apache License Version 2.0 that can be found in the
3
3
  // LICENSE file in the root directory of this source tree.
4
+ export { loadMainThread } from './loadMainThread.js';
4
5
  export * from './MainThreadRuntime.js';
5
6
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,5 @@
1
+ import { type Rpc, type MainThreadStartConfigs, type RpcCallType, type reportErrorEndpoint } from '@lynx-js/web-constants';
2
+ import { MainThreadRuntime } from './MainThreadRuntime.js';
3
+ export declare function loadMainThread(backgroundThreadRpc: Rpc, docu: Pick<Document, 'append' | 'createElement' | 'addEventListener'>, commitDocument: () => Promise<void> | void, markTimingInternal: (timingKey: string, pipelineId?: string) => void, reportError: RpcCallType<typeof reportErrorEndpoint>): {
4
+ startMainThread: (config: MainThreadStartConfigs) => Promise<MainThreadRuntime>;
5
+ };
@@ -0,0 +1,120 @@
1
+ // Copyright 2023 The Lynx Authors. All rights reserved.
2
+ // Licensed under the Apache License Version 2.0 that can be found in the
3
+ // LICENSE file in the root directory of this source tree.
4
+ import { BackgroundThreadStartEndpoint, publishEventEndpoint, publicComponentEventEndpoint, postExposureEndpoint, switchExposureServiceEndpoint, postTimingFlagsEndpoint, dispatchCoreContextOnBackgroundEndpoint, dispatchJSContextOnMainThreadEndpoint, LynxCrossThreadContext, } from '@lynx-js/web-constants';
5
+ import { registerCallLepusMethodHandler } from './crossThreadHandlers/registerCallLepusMethodHandler.js';
6
+ import { registerGetCustomSectionHandler } from './crossThreadHandlers/registerGetCustomSectionHandler.js';
7
+ import { MainThreadRuntime, switchExposureService, } from './MainThreadRuntime.js';
8
+ const moduleCache = {};
9
+ export function loadMainThread(backgroundThreadRpc, docu, commitDocument, markTimingInternal, reportError) {
10
+ const postTimingFlags = backgroundThreadRpc.createCall(postTimingFlagsEndpoint);
11
+ const backgroundStart = backgroundThreadRpc.createCall(BackgroundThreadStartEndpoint);
12
+ const publishEvent = backgroundThreadRpc.createCall(publishEventEndpoint);
13
+ const publicComponentEvent = backgroundThreadRpc.createCall(publicComponentEventEndpoint);
14
+ const postExposure = backgroundThreadRpc.createCall(postExposureEndpoint);
15
+ markTimingInternal('lepus_execute_start');
16
+ async function startMainThread(config) {
17
+ let isFp = true;
18
+ const { globalProps, template, browserConfig, nativeModulesMap, napiModulesMap, tagMap, } = config;
19
+ const { styleInfo, pageConfig, customSections, cardType, lepusCode } = template;
20
+ markTimingInternal('decode_start');
21
+ const lepusCodeEntries = await Promise.all(Object.entries(lepusCode).map(async ([name, url]) => {
22
+ const cachedModule = moduleCache[name];
23
+ if (cachedModule) {
24
+ return [name, cachedModule];
25
+ }
26
+ else {
27
+ Object.assign(globalThis, { module: {} });
28
+ await import(/* webpackIgnore: true */ url);
29
+ const module = globalThis.module;
30
+ Object.assign(globalThis, { module: {} });
31
+ moduleCache[name] = module;
32
+ return [name, module];
33
+ }
34
+ }));
35
+ const lepusCodeLoaded = Object.fromEntries(lepusCodeEntries);
36
+ const entry = lepusCodeLoaded['root'].exports;
37
+ const jsContext = new LynxCrossThreadContext({
38
+ rpc: backgroundThreadRpc,
39
+ receiveEventEndpoint: dispatchJSContextOnMainThreadEndpoint,
40
+ sendEventEndpoint: dispatchCoreContextOnBackgroundEndpoint,
41
+ });
42
+ const runtime = new MainThreadRuntime({
43
+ jsContext,
44
+ tagMap,
45
+ browserConfig,
46
+ customSections,
47
+ globalProps,
48
+ pageConfig,
49
+ styleInfo,
50
+ lepusCode: lepusCodeLoaded,
51
+ docu,
52
+ callbacks: {
53
+ mainChunkReady: () => {
54
+ markTimingInternal('data_processor_start');
55
+ const initData = runtime.processData
56
+ ? runtime.processData(config.initData)
57
+ : config.initData;
58
+ markTimingInternal('data_processor_end');
59
+ registerCallLepusMethodHandler(backgroundThreadRpc, runtime);
60
+ registerGetCustomSectionHandler(backgroundThreadRpc, customSections);
61
+ backgroundThreadRpc.registerHandler(switchExposureServiceEndpoint, runtime[switchExposureService]);
62
+ backgroundStart({
63
+ initData,
64
+ globalProps,
65
+ template,
66
+ cardType: cardType ?? 'react',
67
+ customSections: Object.fromEntries(Object.entries(customSections).filter(([, value]) => value.type !== 'lazy').map(([k, v]) => [k, v.content])),
68
+ nativeModulesMap,
69
+ napiModulesMap,
70
+ browserConfig,
71
+ });
72
+ runtime.renderPage(initData);
73
+ runtime.__FlushElementTree(undefined, {});
74
+ },
75
+ flushElementTree: async (options, timingFlags) => {
76
+ const pipelineId = options?.pipelineOptions?.pipelineID;
77
+ markTimingInternal('dispatch_start', pipelineId);
78
+ if (isFp) {
79
+ isFp = false;
80
+ jsContext.dispatchEvent({
81
+ type: '__OnNativeAppReady',
82
+ data: undefined,
83
+ });
84
+ }
85
+ markTimingInternal('layout_start', pipelineId);
86
+ markTimingInternal('ui_operation_flush_start', pipelineId);
87
+ await commitDocument();
88
+ markTimingInternal('ui_operation_flush_end', pipelineId);
89
+ markTimingInternal('layout_end', pipelineId);
90
+ markTimingInternal('dispatch_end', pipelineId);
91
+ requestAnimationFrame(() => {
92
+ postTimingFlags(timingFlags, pipelineId);
93
+ });
94
+ },
95
+ _ReportError: reportError,
96
+ __OnLifecycleEvent: (data) => {
97
+ jsContext.dispatchEvent({
98
+ type: '__OnLifecycleEvent',
99
+ data,
100
+ });
101
+ },
102
+ /**
103
+ * Note :
104
+ * The parameter of lynx.performance.markTiming is (pipelineId:string, timingFlag:string)=>void
105
+ * But our markTimingInternal is (timingFlag:string, pipelineId?:string, timeStamp?:number) => void
106
+ */
107
+ markTiming: (a, b) => markTimingInternal(b, a),
108
+ publishEvent,
109
+ publicComponentEvent,
110
+ postExposure,
111
+ },
112
+ }).globalThis;
113
+ markTimingInternal('decode_end');
114
+ entry(runtime);
115
+ jsContext.__start(); // start the jsContext after the runtime is created
116
+ return runtime;
117
+ }
118
+ return { startMainThread };
119
+ }
120
+ //# sourceMappingURL=loadMainThread.js.map
@@ -34,11 +34,9 @@ export function transformToWebCss(styleInfo) {
34
34
  rule.decl = transformedStyle;
35
35
  if (childStyle.length > 0) {
36
36
  cssInfos.rules.push({
37
- sel: selectors.map(selector => [
38
- selector[0].concat(['>', '*']),
39
- selector[1],
40
- selector[2],
41
- ]),
37
+ sel: selectors.map(selector => selector.toSpliced(-2, 1,
38
+ /* replace the last combinator and insert at the end */
39
+ ['>'], ['*'], [], [], [])),
42
40
  decl: childStyle,
43
41
  });
44
42
  }
@@ -50,7 +48,7 @@ export function transformToWebCss(styleInfo) {
50
48
  */
51
49
  export function genCssContent(styleInfo, pageConfig) {
52
50
  function getExtraSelectors(cssId) {
53
- let prepend = '', suffix = '';
51
+ let suffix = '';
54
52
  if (!pageConfig.enableRemoveCSSScope) {
55
53
  if (cssId !== undefined) {
56
54
  suffix += `[${cssIdAttribute}="${cssId}"]`;
@@ -63,21 +61,16 @@ export function genCssContent(styleInfo, pageConfig) {
63
61
  else {
64
62
  suffix += `[${lynxTagAttribute}]`;
65
63
  }
66
- return { prepend, suffix };
64
+ return suffix;
67
65
  }
68
66
  const finalCssContent = [];
69
67
  for (const [cssId, cssInfos] of Object.entries(styleInfo)) {
70
- const { prepend, suffix } = getExtraSelectors(cssId);
68
+ const suffix = getExtraSelectors(cssId);
71
69
  const declarationContent = cssInfos.rules.map((rule) => {
72
- const { sel: selectors, decl: declarations } = rule;
73
- const selectorString = selectors.map(([plainSelectors, pseudoClassSelectors, pseudoElementSelectors]) => {
74
- return [
75
- prepend,
76
- plainSelectors.join(''),
77
- suffix,
78
- pseudoClassSelectors.join(''),
79
- pseudoElementSelectors.join(''),
80
- ].join('');
70
+ const { sel: selectorList, decl: declarations } = rule;
71
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
72
+ const selectorString = selectorList.map((selectors) => {
73
+ return selectors.toSpliced(-4, 0, [suffix]).join('');
81
74
  }).join(',');
82
75
  const declarationString = declarations.map(([k, v]) => `${k}:${v};`).join('');
83
76
  return `${selectorString}{${declarationString}}`;
@@ -94,10 +87,13 @@ export function genCssInJsInfo(styleInfo) {
94
87
  const oneCssInJsInfo = {};
95
88
  cssInfos.rules = cssInfos.rules.filter(oneCssInfo => {
96
89
  oneCssInfo.sel = oneCssInfo.sel.filter(selectorList => {
97
- const [classSelectors, pseudoClassSelectors, pseudoElementSelectors] = selectorList;
98
- if (classSelectors.length === 1 && classSelectors[0][0] === '.'
90
+ const [classSelectors, pseudoClassSelectors, pseudoElementSelectors, combinator,] = selectorList;
91
+ if (
92
+ // only one class selector
93
+ classSelectors.length === 1 && classSelectors[0][0] === '.'
99
94
  && pseudoClassSelectors.length === 0
100
- && pseudoElementSelectors.length === 0) {
95
+ && pseudoElementSelectors.length === 0
96
+ && combinator.length === 0) {
101
97
  const selectorName = classSelectors[0].substring(1);
102
98
  const currentDeclarations = oneCssInJsInfo[selectorName];
103
99
  if (currentDeclarations) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lynx-js/web-mainthread-apis",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "private": false,
5
5
  "description": "",
6
6
  "keywords": [],
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "css-tree": "^3.1.0",
27
27
  "hyphenate-style-name": "^1.1.0",
28
- "@lynx-js/web-constants": "0.12.0",
28
+ "@lynx-js/web-constants": "0.13.0",
29
29
  "@lynx-js/web-style-transformer": "0.3.0"
30
30
  }
31
31
  }