@lynx-js/web-mainthread-apis 0.14.2 → 0.15.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 +24 -0
- package/dist/createMainThreadGlobalThis.d.ts +1 -1
- package/dist/createMainThreadGlobalThis.js +41 -10
- package/dist/prepareMainThreadAPIs.d.ts +1 -1
- package/dist/prepareMainThreadAPIs.js +5 -2
- package/dist/pureElementPAPIs.js +8 -5
- package/dist/style/transformInlineStyle.d.ts +1 -8
- package/dist/style/transformInlineStyle.js +1 -38
- package/dist/utils/createExposureService.js +16 -12
- package/dist/utils/decodeCssOG.d.ts +8 -0
- package/dist/utils/{decodeCssInJs.js → decodeCssOG.js} +2 -2
- package/dist/utils/processStyleInfo.d.ts +2 -2
- package/dist/utils/processStyleInfo.js +8 -8
- package/dist/utils/tokenizer.d.ts +6 -0
- package/dist/utils/tokenizer.js +78 -0
- package/package.json +4 -4
- package/dist/utils/decodeCssInJs.d.ts +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @lynx-js/web-mainthread-apis
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- refactor: move exposure system to web-core ([#1254](https://github.com/lynx-family/lynx-stack/pull/1254))
|
|
8
|
+
|
|
9
|
+
**THIS IS A BREAKING CHANGE**
|
|
10
|
+
|
|
11
|
+
**You'll need to upgrade your @lynx-js/web-elements to >= 0.8.0**
|
|
12
|
+
|
|
13
|
+
For SSR and better performance, we moved the lynx's exposure system from web-element to web-core.
|
|
14
|
+
|
|
15
|
+
Before this commit, we create Intersection observers by creating HTMLElements.
|
|
16
|
+
|
|
17
|
+
After this commit, we will create such Intersection observers after dom stabled.
|
|
18
|
+
|
|
19
|
+
Also, the setInterval for exposure has been removed, now we use an on time lazy timer for such features.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [[`16f402f`](https://github.com/lynx-family/lynx-stack/commit/16f402f557ba12ec34a35a1b9b00115bf576c20f), [`60095d7`](https://github.com/lynx-family/lynx-stack/commit/60095d741ae969e76a8faeb669a0fbe7e6e81f7c), [`224c653`](https://github.com/lynx-family/lynx-stack/commit/224c653f370d807281fa0a9ffbb4f4dd5c9d308e)]:
|
|
24
|
+
- @lynx-js/web-style-transformer@0.3.2
|
|
25
|
+
- @lynx-js/web-constants@0.15.0
|
|
26
|
+
|
|
3
27
|
## 0.14.2
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type LynxTemplate, type PageConfig, type StyleInfo, type FlushElementTreeOptions, type Cloneable, type BrowserConfig, type publishEventEndpoint, type publicComponentEventEndpoint, type reportErrorEndpoint, type RpcCallType, type LynxContextEventTarget, type LynxJSModule, type MainThreadGlobalThis, type WebFiberElementImpl, type I18nResourceTranslationOptions } from '@lynx-js/web-constants';
|
|
2
2
|
export interface MainThreadRuntimeCallbacks {
|
|
3
3
|
mainChunkReady: () => void;
|
|
4
|
-
flushElementTree: (options: FlushElementTreeOptions, timingFlags: string[]) => void;
|
|
4
|
+
flushElementTree: (options: FlushElementTreeOptions, timingFlags: string[], exposureChangedElements: WebFiberElementImpl[]) => void;
|
|
5
5
|
_ReportError: RpcCallType<typeof reportErrorEndpoint>;
|
|
6
6
|
__OnLifecycleEvent: (lifeCycleEvent: Cloneable) => void;
|
|
7
7
|
markTiming: (pipelineId: string, timingKey: string) => void;
|
|
@@ -4,10 +4,22 @@
|
|
|
4
4
|
import { lynxUniqueIdAttribute, systemInfo, parentComponentUniqueIdAttribute, componentIdAttribute, LynxEventNameToW3cByTagName, LynxEventNameToW3cCommon, lynxTagAttribute, W3cEventNameToLynx, cssIdAttribute, lynxDefaultDisplayLinearAttribute, __lynx_timing_flag, lynxDisposedAttribute, } from '@lynx-js/web-constants';
|
|
5
5
|
import { globalMuteableVars } from '@lynx-js/web-constants';
|
|
6
6
|
import { createMainThreadLynx } from './createMainThreadLynx.js';
|
|
7
|
-
import { flattenStyleInfo, genCssContent,
|
|
7
|
+
import { flattenStyleInfo, genCssContent, genCssOGInfo, transformToWebCss, } from './utils/processStyleInfo.js';
|
|
8
8
|
import { __AddClass, __AddConfig, __AddDataset, __AddInlineStyle, __AppendElement, __ElementIsEqual, __FirstElement, __GetAttributes, __GetChildren, __GetClasses, __GetComponentID, __GetDataByKey, __GetDataset, __GetElementConfig, __GetElementUniqueID, __GetID, __GetParent, __GetTag, __InsertElementBefore, __LastElement, __NextElement, __RemoveElement, __ReplaceElement, __ReplaceElements, __SetClasses, __SetConfig, __SetCSSId, __SetDataset, __SetID, __SetInlineStyles, __UpdateComponentID, } from './pureElementPAPIs.js';
|
|
9
9
|
import { createCrossThreadEvent } from './utils/createCrossThreadEvent.js';
|
|
10
|
-
import {
|
|
10
|
+
import { decodeCssOG } from './utils/decodeCssOG.js';
|
|
11
|
+
const exposureRelatedAttributes = new Set([
|
|
12
|
+
'exposure-id',
|
|
13
|
+
'exposure-area',
|
|
14
|
+
'exposure-screen-margin-top',
|
|
15
|
+
'exposure-screen-margin-right',
|
|
16
|
+
'exposure-screen-margin-bottom',
|
|
17
|
+
'exposure-screen-margin-left',
|
|
18
|
+
'exposure-ui-margin-top',
|
|
19
|
+
'exposure-ui-margin-right',
|
|
20
|
+
'exposure-ui-margin-bottom',
|
|
21
|
+
'exposure-ui-margin-left',
|
|
22
|
+
]);
|
|
11
23
|
export function createMainThreadGlobalThis(config) {
|
|
12
24
|
let pageElement;
|
|
13
25
|
let uniqueIdInc = 1;
|
|
@@ -22,6 +34,7 @@ export function createMainThreadGlobalThis(config) {
|
|
|
22
34
|
*/
|
|
23
35
|
const varsUpdateHandlers = [];
|
|
24
36
|
const lynxGlobalBindingValues = {};
|
|
37
|
+
const exposureChangedElements = new Set();
|
|
25
38
|
/**
|
|
26
39
|
* now create the style content
|
|
27
40
|
* 1. flatten the styleInfo
|
|
@@ -32,15 +45,15 @@ export function createMainThreadGlobalThis(config) {
|
|
|
32
45
|
*/
|
|
33
46
|
flattenStyleInfo(styleInfo, pageConfig.enableCSSSelector);
|
|
34
47
|
transformToWebCss(styleInfo);
|
|
35
|
-
const
|
|
48
|
+
const cssOGInfo = pageConfig.enableCSSSelector
|
|
36
49
|
? {}
|
|
37
|
-
:
|
|
50
|
+
: genCssOGInfo(styleInfo);
|
|
38
51
|
const cardStyleElement = callbacks.createElement('style');
|
|
39
52
|
cardStyleElement.innerHTML = genCssContent(styleInfo, pageConfig);
|
|
40
53
|
// @ts-expect-error
|
|
41
54
|
rootDom.append(cardStyleElement);
|
|
42
55
|
const cardStyleElementSheet = cardStyleElement.sheet;
|
|
43
|
-
const
|
|
56
|
+
const updateCssOGStyle = (uniqueId, newStyles) => {
|
|
44
57
|
if (lynxUniqueIdToStyleRulesIndex[uniqueId] !== undefined) {
|
|
45
58
|
const rule = cardStyleElementSheet
|
|
46
59
|
.cssRules[lynxUniqueIdToStyleRulesIndex[uniqueId]];
|
|
@@ -121,6 +134,12 @@ export function createMainThreadGlobalThis(config) {
|
|
|
121
134
|
element.removeEventListener(eventName, currentRegisteredHandler, {
|
|
122
135
|
capture: isCapture,
|
|
123
136
|
});
|
|
137
|
+
// remove the exposure id if the exposure-id is a placeholder value
|
|
138
|
+
const isExposure = eventName === 'uiappear'
|
|
139
|
+
|| eventName === 'uidisappear';
|
|
140
|
+
if (isExposure && element.getAttribute('exposure-id') === '-1') {
|
|
141
|
+
mtsGlobalThis.__SetAttribute(element, 'exposure-id', null);
|
|
142
|
+
}
|
|
124
143
|
}
|
|
125
144
|
}
|
|
126
145
|
else {
|
|
@@ -133,6 +152,12 @@ export function createMainThreadGlobalThis(config) {
|
|
|
133
152
|
element.addEventListener(htmlEventName, currentRegisteredHandler, {
|
|
134
153
|
capture: isCapture,
|
|
135
154
|
});
|
|
155
|
+
// add exposure id if no exposure-id is set
|
|
156
|
+
const isExposure = eventName === 'uiappear'
|
|
157
|
+
|| eventName === 'uidisappear';
|
|
158
|
+
if (isExposure && element.getAttribute('exposure-id') === null) {
|
|
159
|
+
mtsGlobalThis.__SetAttribute(element, 'exposure-id', '-1');
|
|
160
|
+
}
|
|
136
161
|
}
|
|
137
162
|
}
|
|
138
163
|
if (newEventHandler) {
|
|
@@ -276,6 +301,10 @@ export function createMainThreadGlobalThis(config) {
|
|
|
276
301
|
if (key === __lynx_timing_flag && value) {
|
|
277
302
|
timingFlags.push(value);
|
|
278
303
|
}
|
|
304
|
+
if (exposureRelatedAttributes.has(key)) {
|
|
305
|
+
// if the attribute is related to exposure, we need to mark the element as changed
|
|
306
|
+
exposureChangedElements.add(element);
|
|
307
|
+
}
|
|
279
308
|
}
|
|
280
309
|
};
|
|
281
310
|
const __UpdateListCallbacks = (element, componentAtIndex, enqueueComponent) => {
|
|
@@ -306,13 +335,13 @@ export function createMainThreadGlobalThis(config) {
|
|
|
306
335
|
const newClassName = ((element.getAttribute('class') ?? '') + ' ' + className)
|
|
307
336
|
.trim();
|
|
308
337
|
element.setAttribute('class', newClassName);
|
|
309
|
-
const newStyleStr =
|
|
310
|
-
|
|
338
|
+
const newStyleStr = decodeCssOG(newClassName, cssOGInfo, element.getAttribute(cssIdAttribute));
|
|
339
|
+
updateCssOGStyle(Number(element.getAttribute(lynxUniqueIdAttribute)), newStyleStr);
|
|
311
340
|
};
|
|
312
341
|
const __SetClassesForCSSOG = (element, classNames) => {
|
|
313
342
|
__SetClasses(element, classNames);
|
|
314
|
-
const newStyleStr =
|
|
315
|
-
|
|
343
|
+
const newStyleStr = decodeCssOG(classNames ?? '', cssOGInfo, element.getAttribute(cssIdAttribute));
|
|
344
|
+
updateCssOGStyle(Number(element.getAttribute(lynxUniqueIdAttribute)), newStyleStr ?? '');
|
|
316
345
|
};
|
|
317
346
|
const __LoadLepusChunk = (path) => {
|
|
318
347
|
const lepusModule = lepusCode[`${path}`];
|
|
@@ -333,7 +362,9 @@ export function createMainThreadGlobalThis(config) {
|
|
|
333
362
|
// @ts-expect-error
|
|
334
363
|
rootDom.append(pageElement);
|
|
335
364
|
}
|
|
336
|
-
|
|
365
|
+
const exposureChangedElementsArray = Array.from(exposureChangedElements);
|
|
366
|
+
exposureChangedElements.clear();
|
|
367
|
+
callbacks.flushElementTree(options, timingFlagsCopied, exposureChangedElementsArray);
|
|
337
368
|
};
|
|
338
369
|
const __GetTemplateParts = () => {
|
|
339
370
|
return undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type Rpc, type StartMainThreadContextConfig, type RpcCallType, type reportErrorEndpoint, type MainThreadGlobalThis, type I18nResourceTranslationOptions, type InitI18nResources, type I18nResources } from '@lynx-js/web-constants';
|
|
2
|
-
export declare function prepareMainThreadAPIs(backgroundThreadRpc: Rpc, rootDom: Document | ShadowRoot, createElement: Document['createElement'], commitDocument: () => Promise<void> | void, markTimingInternal: (timingKey: string, pipelineId?: string) => void, flushMarkTimingInternal: () => void, reportError: RpcCallType<typeof reportErrorEndpoint>, triggerI18nResourceFallback: (options: I18nResourceTranslationOptions) => void, initialI18nResources: (data: InitI18nResources) => I18nResources): {
|
|
2
|
+
export declare function prepareMainThreadAPIs(backgroundThreadRpc: Rpc, rootDom: Document | ShadowRoot, createElement: Document['createElement'], commitDocument: (exposureChangedElements: HTMLElement[]) => Promise<void> | void, markTimingInternal: (timingKey: string, pipelineId?: string) => void, flushMarkTimingInternal: () => void, reportError: RpcCallType<typeof reportErrorEndpoint>, triggerI18nResourceFallback: (options: I18nResourceTranslationOptions) => void, initialI18nResources: (data: InitI18nResources) => I18nResources): {
|
|
3
3
|
startMainThread: (config: StartMainThreadContextConfig) => Promise<MainThreadGlobalThis>;
|
|
4
4
|
};
|
|
@@ -6,6 +6,8 @@ import { registerCallLepusMethodHandler } from './crossThreadHandlers/registerCa
|
|
|
6
6
|
import { registerGetCustomSectionHandler } from './crossThreadHandlers/registerGetCustomSectionHandler.js';
|
|
7
7
|
import { createMainThreadGlobalThis } from './createMainThreadGlobalThis.js';
|
|
8
8
|
import { createExposureService } from './utils/createExposureService.js';
|
|
9
|
+
import { initTokenizer } from './utils/tokenizer.js';
|
|
10
|
+
const initTokenizerPromise = initTokenizer();
|
|
9
11
|
const moduleCache = {};
|
|
10
12
|
export function prepareMainThreadAPIs(backgroundThreadRpc, rootDom, createElement, commitDocument, markTimingInternal, flushMarkTimingInternal, reportError, triggerI18nResourceFallback, initialI18nResources) {
|
|
11
13
|
const postTimingFlags = backgroundThreadRpc.createCall(postTimingFlagsEndpoint);
|
|
@@ -20,6 +22,7 @@ export function prepareMainThreadAPIs(backgroundThreadRpc, rootDom, createElemen
|
|
|
20
22
|
const { globalProps, template, browserConfig, nativeModulesMap, napiModulesMap, tagMap, initI18nResources, } = config;
|
|
21
23
|
const { styleInfo, pageConfig, customSections, cardType, lepusCode } = template;
|
|
22
24
|
markTimingInternal('decode_start');
|
|
25
|
+
await initTokenizerPromise;
|
|
23
26
|
const lepusCodeEntries = await Promise.all(Object.entries(lepusCode).map(async ([name, url]) => {
|
|
24
27
|
const cachedModule = moduleCache[url];
|
|
25
28
|
if (cachedModule) {
|
|
@@ -78,7 +81,7 @@ export function prepareMainThreadAPIs(backgroundThreadRpc, rootDom, createElemen
|
|
|
78
81
|
mtsGlobalThis.renderPage(initData);
|
|
79
82
|
mtsGlobalThis.__FlushElementTree(undefined, {});
|
|
80
83
|
},
|
|
81
|
-
flushElementTree: async (options, timingFlags) => {
|
|
84
|
+
flushElementTree: async (options, timingFlags, exposureChangedElements) => {
|
|
82
85
|
const pipelineId = options?.pipelineOptions?.pipelineID;
|
|
83
86
|
markTimingInternal('dispatch_start', pipelineId);
|
|
84
87
|
if (isFp) {
|
|
@@ -90,7 +93,7 @@ export function prepareMainThreadAPIs(backgroundThreadRpc, rootDom, createElemen
|
|
|
90
93
|
}
|
|
91
94
|
markTimingInternal('layout_start', pipelineId);
|
|
92
95
|
markTimingInternal('ui_operation_flush_start', pipelineId);
|
|
93
|
-
await commitDocument();
|
|
96
|
+
await commitDocument(exposureChangedElements);
|
|
94
97
|
markTimingInternal('ui_operation_flush_end', pipelineId);
|
|
95
98
|
markTimingInternal('layout_end', pipelineId);
|
|
96
99
|
markTimingInternal('dispatch_end', pipelineId);
|
package/dist/pureElementPAPIs.js
CHANGED
|
@@ -128,13 +128,16 @@ export const __AddClass = /*#__PURE__*/ (element, className) => {
|
|
|
128
128
|
export const __SetInlineStyles = /*#__PURE__*/ (element, value) => {
|
|
129
129
|
if (!value)
|
|
130
130
|
return;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
if (typeof value === 'string') {
|
|
132
|
+
element.setAttribute('style', transformInlineStyleString(value));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const { transformedStyle } = transformParsedStyles(Object.entries(value).map(([k, value]) => [
|
|
134
136
|
hyphenateStyleName(k),
|
|
135
137
|
value,
|
|
136
138
|
]));
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
const transformedStyleStr = transformedStyle.map(([property, value]) => `${property}:${value};`).join('');
|
|
140
|
+
element.setAttribute('style', transformedStyleStr);
|
|
141
|
+
}
|
|
139
142
|
};
|
|
140
143
|
//# sourceMappingURL=pureElementPAPIs.js.map
|
|
@@ -1,8 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
childStyle: [string, string][];
|
|
3
|
-
transformedStyle: [string, string][];
|
|
4
|
-
};
|
|
5
|
-
export declare function transformParsedStyles(hyphenatedStyleObject: [property: string, value: string][]): {
|
|
6
|
-
childStyle: [string, string][];
|
|
7
|
-
transformedStyle: [string, string][];
|
|
8
|
-
};
|
|
1
|
+
export { transformInlineStyleString, transformParsedStyles, } from '../utils/tokenizer.js';
|
|
@@ -1,42 +1,5 @@
|
|
|
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
|
-
|
|
5
|
-
import * as tokenizer from 'css-tree/tokenizer';
|
|
6
|
-
import { transformLynxStyles } from '@lynx-js/web-style-transformer';
|
|
7
|
-
function parseStyleStringToObject(str) {
|
|
8
|
-
const hyphenNameStyles = [];
|
|
9
|
-
let beforeColonToken = true;
|
|
10
|
-
let propertyStart = 0;
|
|
11
|
-
let propertyEnd = 0;
|
|
12
|
-
let valueStart = 0;
|
|
13
|
-
let valueEnd = 0;
|
|
14
|
-
tokenizer.tokenize(str + ';', (type, start, end) => {
|
|
15
|
-
if (type === tokenizer.Semicolon || tokenizer.EOF) {
|
|
16
|
-
valueEnd = start;
|
|
17
|
-
const trimmedProperty = str.substring(propertyStart, propertyEnd).trim();
|
|
18
|
-
const trimmedValue = str.substring(valueStart, valueEnd).trim();
|
|
19
|
-
if (!beforeColonToken && trimmedValue && trimmedProperty) {
|
|
20
|
-
hyphenNameStyles.push([
|
|
21
|
-
trimmedProperty,
|
|
22
|
-
trimmedValue,
|
|
23
|
-
]);
|
|
24
|
-
}
|
|
25
|
-
beforeColonToken = true;
|
|
26
|
-
propertyStart = end;
|
|
27
|
-
}
|
|
28
|
-
else if (type === tokenizer.Colon && beforeColonToken) {
|
|
29
|
-
beforeColonToken = false;
|
|
30
|
-
valueStart = end;
|
|
31
|
-
propertyEnd = start;
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
return hyphenNameStyles;
|
|
35
|
-
}
|
|
36
|
-
export function transformInlineStyleString(str) {
|
|
37
|
-
return transformParsedStyles(parseStyleStringToObject(str));
|
|
38
|
-
}
|
|
39
|
-
export function transformParsedStyles(hyphenatedStyleObject) {
|
|
40
|
-
return transformLynxStyles(hyphenatedStyleObject);
|
|
41
|
-
}
|
|
4
|
+
export { transformInlineStyleString, transformParsedStyles, } from '../utils/tokenizer.js';
|
|
42
5
|
//# sourceMappingURL=transformInlineStyle.js.map
|
|
@@ -7,6 +7,7 @@ export function createExposureService(rootDom, postExposure) {
|
|
|
7
7
|
let working = true;
|
|
8
8
|
let exposureCache = [];
|
|
9
9
|
let disexposureCache = [];
|
|
10
|
+
let delayCallback = null;
|
|
10
11
|
const onScreen = new Map();
|
|
11
12
|
function exposureEventHandler(ev) {
|
|
12
13
|
const exposureEvent = createCrossThreadEvent(ev, ev.type);
|
|
@@ -20,19 +21,22 @@ export function createExposureService(rootDom, postExposure) {
|
|
|
20
21
|
disexposureCache.push(exposureEvent);
|
|
21
22
|
onScreen.delete(exposureID);
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
if (!delayCallback) {
|
|
25
|
+
delayCallback = setTimeout(() => {
|
|
26
|
+
if (exposureCache.length > 0 || disexposureCache.length > 0) {
|
|
27
|
+
const currentExposure = exposureCache;
|
|
28
|
+
const currentDisexposure = disexposureCache;
|
|
29
|
+
exposureCache = [];
|
|
30
|
+
disexposureCache = [];
|
|
31
|
+
postExposure({
|
|
32
|
+
exposures: currentExposure,
|
|
33
|
+
disExposures: currentDisexposure,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
delayCallback = null;
|
|
37
|
+
}, 1000 / 20);
|
|
34
38
|
}
|
|
35
|
-
}
|
|
39
|
+
}
|
|
36
40
|
rootDom.addEventListener('exposure', exposureEventHandler, {
|
|
37
41
|
passive: true,
|
|
38
42
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CssOGInfo } from '@lynx-js/web-constants';
|
|
2
|
+
/**
|
|
3
|
+
* @param classes
|
|
4
|
+
* @param styleInfo it should be flattened, which means there is no imports field in the styleInfo
|
|
5
|
+
* @param cssId
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export declare function decodeCssOG(classes: string, styleInfo: CssOGInfo, cssId: string | null): string;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @param cssId
|
|
5
5
|
* @returns
|
|
6
6
|
*/
|
|
7
|
-
export function
|
|
7
|
+
export function decodeCssOG(classes, styleInfo, cssId) {
|
|
8
8
|
const classList = classes.split(' ').filter(e => e);
|
|
9
9
|
let declarations = [];
|
|
10
10
|
const currentStyleInfo = styleInfo[cssId ?? '0'];
|
|
@@ -20,4 +20,4 @@ export function decodeCssInJs(classes, styleInfo, cssId) {
|
|
|
20
20
|
}
|
|
21
21
|
return declarations.map(([property, value]) => `${property}:${value};`).join('');
|
|
22
22
|
}
|
|
23
|
-
//# sourceMappingURL=
|
|
23
|
+
//# sourceMappingURL=decodeCssOG.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type StyleInfo, type
|
|
1
|
+
import { type StyleInfo, type CssOGInfo, type PageConfig } from '@lynx-js/web-constants';
|
|
2
2
|
export declare function flattenStyleInfo(styleInfo: StyleInfo, enableCSSSelector: boolean): void;
|
|
3
3
|
/**
|
|
4
4
|
* apply the lynx css -> web css transformation
|
|
@@ -11,4 +11,4 @@ export declare function genCssContent(styleInfo: StyleInfo, pageConfig: PageConf
|
|
|
11
11
|
/**
|
|
12
12
|
* generate the css-in-js data
|
|
13
13
|
*/
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function genCssOGInfo(styleInfo: StyleInfo): CssOGInfo;
|
|
@@ -2,7 +2,7 @@
|
|
|
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
4
|
import { cssIdAttribute, lynxTagAttribute, } from '@lynx-js/web-constants';
|
|
5
|
-
import {
|
|
5
|
+
import { transformParsedStyles } from './tokenizer.js';
|
|
6
6
|
export function flattenStyleInfo(styleInfo, enableCSSSelector) {
|
|
7
7
|
function flattenOneStyleInfo(cssId) {
|
|
8
8
|
const oneInfo = styleInfo[cssId];
|
|
@@ -16,7 +16,7 @@ export function flattenStyleInfo(styleInfo, enableCSSSelector) {
|
|
|
16
16
|
oneInfo.rules.push(...(enableCSSSelector
|
|
17
17
|
? flatInfo.rules
|
|
18
18
|
// when enableCSSSelector is false, need to make a shallow copy of rules.sel
|
|
19
|
-
// otherwise updating `oneCssInfo.sel` in `
|
|
19
|
+
// otherwise updating `oneCssInfo.sel` in `genCssOGInfo()` will affect other imported cssInfo
|
|
20
20
|
: flatInfo.rules.map(i => ({ ...i }))));
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -35,7 +35,7 @@ export function transformToWebCss(styleInfo) {
|
|
|
35
35
|
for (const cssInfos of Object.values(styleInfo)) {
|
|
36
36
|
for (const rule of cssInfos.rules) {
|
|
37
37
|
const { sel: selectors, decl: declarations } = rule;
|
|
38
|
-
const { transformedStyle, childStyle } =
|
|
38
|
+
const { transformedStyle, childStyle } = transformParsedStyles(declarations);
|
|
39
39
|
rule.decl = transformedStyle;
|
|
40
40
|
if (childStyle.length > 0) {
|
|
41
41
|
cssInfos.rules.push({
|
|
@@ -87,9 +87,9 @@ export function genCssContent(styleInfo, pageConfig) {
|
|
|
87
87
|
/**
|
|
88
88
|
* generate the css-in-js data
|
|
89
89
|
*/
|
|
90
|
-
export function
|
|
90
|
+
export function genCssOGInfo(styleInfo) {
|
|
91
91
|
return Object.fromEntries(Object.entries(styleInfo).map(([cssId, cssInfos]) => {
|
|
92
|
-
const
|
|
92
|
+
const oneCssOGInfo = {};
|
|
93
93
|
cssInfos.rules = cssInfos.rules.filter(oneCssInfo => {
|
|
94
94
|
oneCssInfo.sel = oneCssInfo.sel.filter(selectorList => {
|
|
95
95
|
const [classSelectors, pseudoClassSelectors, pseudoElementSelectors, combinator,] = selectorList;
|
|
@@ -100,12 +100,12 @@ export function genCssInJsInfo(styleInfo) {
|
|
|
100
100
|
&& pseudoElementSelectors.length === 0
|
|
101
101
|
&& combinator.length === 0) {
|
|
102
102
|
const selectorName = classSelectors[0].substring(1);
|
|
103
|
-
const currentDeclarations =
|
|
103
|
+
const currentDeclarations = oneCssOGInfo[selectorName];
|
|
104
104
|
if (currentDeclarations) {
|
|
105
105
|
currentDeclarations.push(...oneCssInfo.decl);
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
108
|
-
|
|
108
|
+
oneCssOGInfo[selectorName] = oneCssInfo.decl;
|
|
109
109
|
}
|
|
110
110
|
return false; // remove this selector from style info
|
|
111
111
|
}
|
|
@@ -113,7 +113,7 @@ export function genCssInJsInfo(styleInfo) {
|
|
|
113
113
|
});
|
|
114
114
|
return oneCssInfo.sel.length > 0;
|
|
115
115
|
});
|
|
116
|
-
return [cssId,
|
|
116
|
+
return [cssId, oneCssOGInfo];
|
|
117
117
|
}));
|
|
118
118
|
}
|
|
119
119
|
//# sourceMappingURL=processStyleInfo.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const initTokenizer: () => Promise<void>;
|
|
2
|
+
export declare function transformInlineStyleString(str: string): string;
|
|
3
|
+
export declare function transformParsedStyles(styles: [string, string][]): {
|
|
4
|
+
childStyle: [string, string][];
|
|
5
|
+
transformedStyle: [string, string][];
|
|
6
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// @ts-ignore the wasm module built later than the ts code
|
|
2
|
+
import init from '@lynx-js/web-style-transformer';
|
|
3
|
+
let wasm;
|
|
4
|
+
let HEAPU16;
|
|
5
|
+
var ENVIRONMENT_IS_NODE = typeof process == 'object'
|
|
6
|
+
&& typeof process.versions == 'object'
|
|
7
|
+
&& typeof process.versions.node == 'string';
|
|
8
|
+
export const initTokenizer = async () => {
|
|
9
|
+
// initialize wasm module in node.js environment
|
|
10
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
11
|
+
const path = await import(/* webpackIgnore:true */ 'node:path');
|
|
12
|
+
const fs = await import(/* webpackIgnore:true */ 'node:fs/promises');
|
|
13
|
+
const wasmModuleBuffer = await fs.readFile(path.join(import.meta.dirname, '..', '..', 'node_modules', '@lynx-js', 'web-style-transformer', 'dist', 'index_bg.wasm'));
|
|
14
|
+
wasm = await init(wasmModuleBuffer);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
wasm = await init();
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const stringToUTF16 = (str) => {
|
|
21
|
+
const len = str.length;
|
|
22
|
+
const ptr = wasm.malloc(len << 1);
|
|
23
|
+
if (!HEAPU16 || HEAPU16.byteLength == 0) {
|
|
24
|
+
HEAPU16 = new Uint16Array(wasm.memory.buffer);
|
|
25
|
+
}
|
|
26
|
+
for (let i = 0; i < len; i++) {
|
|
27
|
+
HEAPU16[(ptr >> 1) + i] = str.charCodeAt(i);
|
|
28
|
+
}
|
|
29
|
+
return { ptr, len };
|
|
30
|
+
};
|
|
31
|
+
export function transformInlineStyleString(str) {
|
|
32
|
+
const { ptr, len } = stringToUTF16(str);
|
|
33
|
+
try {
|
|
34
|
+
const transformedStyle = wasm.transform_raw_u16_inline_style_ptr(ptr, len)
|
|
35
|
+
?? str;
|
|
36
|
+
wasm.free(ptr, len << 1);
|
|
37
|
+
return transformedStyle;
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
wasm.free(ptr, len << 1);
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function transformParsedStyles(styles) {
|
|
45
|
+
let childStyle = [];
|
|
46
|
+
let transformedStyle = [];
|
|
47
|
+
for (const [property, value] of styles) {
|
|
48
|
+
const { ptr: propertyPtr, len: propertyLen } = stringToUTF16(property);
|
|
49
|
+
const { ptr: valuePtr, len: valueLen } = stringToUTF16(value);
|
|
50
|
+
try {
|
|
51
|
+
const transformedResult = wasm
|
|
52
|
+
.transform_raw_u16_inline_style_ptr_parsed(propertyPtr, propertyLen, valuePtr, valueLen);
|
|
53
|
+
wasm.free(propertyPtr, propertyLen << 1);
|
|
54
|
+
wasm.free(valuePtr, valueLen << 1);
|
|
55
|
+
if (transformedResult) {
|
|
56
|
+
const [transformedStyleForCurrent, childStyleForCurrent] = transformedResult;
|
|
57
|
+
transformedStyle = transformedStyle.concat(transformedStyleForCurrent);
|
|
58
|
+
if (childStyleForCurrent) {
|
|
59
|
+
childStyle = childStyle.concat(childStyleForCurrent);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// If the transformation fails, we keep the original style
|
|
64
|
+
transformedStyle.push([property, value]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
wasm.free(propertyPtr, propertyLen << 1);
|
|
69
|
+
wasm.free(valuePtr, valueLen << 1);
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
childStyle,
|
|
75
|
+
transformedStyle,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=tokenizer.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynx-js/web-mainthread-apis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "",
|
|
6
6
|
"keywords": [],
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"typings": "dist/index.d.ts",
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
|
+
"binary",
|
|
18
19
|
"!dist/**/*.js.map",
|
|
19
20
|
"LICENSE.txt",
|
|
20
21
|
"Notice.txt",
|
|
@@ -23,9 +24,8 @@
|
|
|
23
24
|
"**/*.css"
|
|
24
25
|
],
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"css-tree": "^3.1.0",
|
|
27
27
|
"hyphenate-style-name": "^1.1.0",
|
|
28
|
-
"@lynx-js/web-constants": "0.
|
|
29
|
-
"@lynx-js/web-style-transformer": "0.3.
|
|
28
|
+
"@lynx-js/web-constants": "0.15.0",
|
|
29
|
+
"@lynx-js/web-style-transformer": "0.3.2"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { CssInJsInfo } from '@lynx-js/web-constants';
|
|
2
|
-
/**
|
|
3
|
-
* @param classes
|
|
4
|
-
* @param styleInfo it should be flattened, which means there is no imports field in the styleInfo
|
|
5
|
-
* @param cssId
|
|
6
|
-
* @returns
|
|
7
|
-
*/
|
|
8
|
-
export declare function decodeCssInJs(classes: string, styleInfo: CssInJsInfo, cssId: string | null): string;
|