@lynx-js/web-mainthread-apis-canary 0.16.1 → 0.17.0-canary-20250918-b17b7cb2
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,19 @@
|
|
|
1
1
|
# @lynx-js/web-mainthread-apis
|
|
2
2
|
|
|
3
|
+
## 0.17.0-canary-20250918080343-b17b7cb2bb92d1539e76276f136806eefa788258
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fix: \_\_QueryComponentImpl in mts should execute only once for same url ([#1763](https://github.com/lynx-family/lynx-stack/pull/1763))
|
|
8
|
+
|
|
9
|
+
- fix: avoid duplicate style transformation ([#1748](https://github.com/lynx-family/lynx-stack/pull/1748))
|
|
10
|
+
|
|
11
|
+
After this commit, we use DAG methods to handle the styleInfos
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`93d707b`](https://github.com/lynx-family/lynx-stack/commit/93d707b82a59f7256952e21da6dcad2999f8233d)]:
|
|
14
|
+
- @lynx-js/web-constants@0.17.0-canary-20250918080343-b17b7cb2bb92d1539e76276f136806eefa788258
|
|
15
|
+
- @lynx-js/web-style-transformer@0.17.0-canary-20250918080343-b17b7cb2bb92d1539e76276f136806eefa788258
|
|
16
|
+
|
|
3
17
|
## 0.16.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -212,25 +226,25 @@
|
|
|
212
226
|
lynxView.initI18nResources = [
|
|
213
227
|
{
|
|
214
228
|
options: {
|
|
215
|
-
locale:
|
|
216
|
-
channel:
|
|
217
|
-
fallback_url:
|
|
229
|
+
locale: "en",
|
|
230
|
+
channel: "1",
|
|
231
|
+
fallback_url: "",
|
|
218
232
|
},
|
|
219
233
|
resource: {
|
|
220
|
-
hello:
|
|
221
|
-
lynx:
|
|
234
|
+
hello: "hello",
|
|
235
|
+
lynx: "lynx web platform1",
|
|
222
236
|
},
|
|
223
237
|
},
|
|
224
238
|
];
|
|
225
|
-
lynxView.addEventListener(
|
|
239
|
+
lynxView.addEventListener("i18nResourceMissed", (e) => {
|
|
226
240
|
console.log(e);
|
|
227
241
|
});
|
|
228
242
|
|
|
229
243
|
// mts
|
|
230
244
|
_I18nResourceTranslation({
|
|
231
|
-
locale:
|
|
232
|
-
channel:
|
|
233
|
-
fallback_url:
|
|
245
|
+
locale: "en",
|
|
246
|
+
channel: "1",
|
|
247
|
+
fallback_url: "",
|
|
234
248
|
});
|
|
235
249
|
```
|
|
236
250
|
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import { queryComponentEndpoint, updateBTSTemplateCacheEndpoint, } from '@lynx-js/web-constants';
|
|
2
2
|
export function createQueryComponent(loadTemplate, updateLazyComponentStyle, backgroundThreadRpc, mtsGlobalThisRef, jsContext, mtsRealm) {
|
|
3
3
|
const updateBTSTemplateCache = backgroundThreadRpc.createCall(updateBTSTemplateCacheEndpoint);
|
|
4
|
+
const lazyCache = new Map();
|
|
4
5
|
const __QueryComponentImpl = (url, callback) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
lepusRootChunkExport =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
const cacheLazy = lazyCache.get(url);
|
|
7
|
+
const loadPromise = cacheLazy
|
|
8
|
+
?? loadTemplate(url).then(async (template) => {
|
|
9
|
+
const updateBTSCachePromise = updateBTSTemplateCache(url, template);
|
|
10
|
+
let lepusRootChunkExport = await mtsRealm.loadScript(template.lepusCode.root);
|
|
11
|
+
if (mtsGlobalThisRef.mtsGlobalThis.processEvalResult) {
|
|
12
|
+
lepusRootChunkExport = mtsGlobalThisRef.mtsGlobalThis
|
|
13
|
+
.processEvalResult(lepusRootChunkExport, url);
|
|
14
|
+
}
|
|
15
|
+
updateLazyComponentStyle(template.styleInfo, url);
|
|
16
|
+
await updateBTSCachePromise;
|
|
17
|
+
jsContext.dispatchEvent({
|
|
18
|
+
type: '__OnDynamicJSSourcePrepared',
|
|
19
|
+
data: url,
|
|
20
|
+
});
|
|
21
|
+
return lepusRootChunkExport;
|
|
16
22
|
});
|
|
23
|
+
!cacheLazy && lazyCache.set(url, loadPromise);
|
|
24
|
+
loadPromise.then(lepusRootChunkExport => {
|
|
17
25
|
callback?.({
|
|
18
26
|
code: 0,
|
|
19
27
|
data: {
|
|
@@ -23,6 +31,7 @@ export function createQueryComponent(loadTemplate, updateLazyComponentStyle, bac
|
|
|
23
31
|
});
|
|
24
32
|
}).catch((error) => {
|
|
25
33
|
console.error(`lynx web: lazy bundle load failed:`, error);
|
|
34
|
+
lazyCache.delete(url);
|
|
26
35
|
callback?.({
|
|
27
36
|
code: -1,
|
|
28
37
|
data: undefined,
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { type StyleInfo, type CssOGInfo, type PageConfig, type SSRHydrateInfo } from '@lynx-js/web-constants';
|
|
2
|
-
|
|
1
|
+
import { type StyleInfo, type CssOGInfo, type PageConfig, type SSRHydrateInfo, type FlattenedStyleInfo } from '@lynx-js/web-constants';
|
|
2
|
+
/**
|
|
3
|
+
* get Transitive Closure of a Direct Acyclic Graph (DAG)
|
|
4
|
+
* 1. for each css, find all the imported by css files (directly and indirectly)
|
|
5
|
+
* 2. for each css, find all the importing css files (directly and indirectly)
|
|
6
|
+
* 3. return the flattened style info, do not modify the content and rules
|
|
7
|
+
*/
|
|
8
|
+
export declare function flattenStyleInfo(styleInfo: StyleInfo): FlattenedStyleInfo;
|
|
3
9
|
/**
|
|
4
10
|
* apply the lynx css -> web css transformation
|
|
5
11
|
*/
|
|
6
|
-
export declare function transformToWebCss(styleInfo:
|
|
12
|
+
export declare function transformToWebCss(styleInfo: FlattenedStyleInfo): void;
|
|
7
13
|
/**
|
|
8
14
|
* generate those styles applied by <style>...</style>
|
|
9
15
|
*/
|
|
10
|
-
export declare function genCssContent(styleInfo:
|
|
16
|
+
export declare function genCssContent(styleInfo: FlattenedStyleInfo, pageConfig: PageConfig, entryName?: string): string;
|
|
11
17
|
/**
|
|
12
18
|
* generate the css-in-js data
|
|
13
19
|
*/
|
|
14
|
-
export declare function genCssOGInfo(styleInfo:
|
|
20
|
+
export declare function genCssOGInfo(styleInfo: FlattenedStyleInfo): CssOGInfo;
|
|
15
21
|
export declare function appendStyleElement(styleInfo: StyleInfo, pageConfig: PageConfig, rootDom: Node, document: Document, entryName?: string, ssrHydrateInfo?: SSRHydrateInfo): {
|
|
16
22
|
updateCssOGStyle: (uniqueId: number, newClassName: string, cssID: string | null) => void;
|
|
17
23
|
updateLazyComponentStyle: (styleInfo: StyleInfo, entryName: string) => void;
|
|
@@ -4,36 +4,94 @@
|
|
|
4
4
|
import { cssIdAttribute, lynxTagAttribute, lynxUniqueIdAttribute, lynxEntryNameAttribute, } from '@lynx-js/web-constants';
|
|
5
5
|
import { transformParsedStyles } from './tokenizer.js';
|
|
6
6
|
import { decodeCssOG } from './decodeCssOG.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
7
|
+
function topologicalSort(styleInfo) {
|
|
8
|
+
/**
|
|
9
|
+
* kahn's algorithm
|
|
10
|
+
* 1. The styleInfo is already equivalent to a adjacency list. (cssId, import)
|
|
11
|
+
* 2. The styleInfo is a DAG therefore we don't need to do cyclic detection
|
|
12
|
+
*/
|
|
13
|
+
const queue = [];
|
|
14
|
+
const inDegreeMap = new Map();
|
|
15
|
+
for (const [cssId, oneStyleInfo] of Object.entries(styleInfo)) {
|
|
16
|
+
!inDegreeMap.has(cssId) && inDegreeMap.set(cssId, 0); // initialize
|
|
17
|
+
for (const importCssId of oneStyleInfo.imports ?? []) {
|
|
18
|
+
const currentInDegree = inDegreeMap.get(importCssId) ?? 0;
|
|
19
|
+
inDegreeMap.set(importCssId, currentInDegree + 1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const [cssId, inDegree] of inDegreeMap.entries()) {
|
|
23
|
+
if (inDegree === 0) {
|
|
24
|
+
queue.push(cssId);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const sortedCssIds = [];
|
|
28
|
+
while (queue.length > 0) {
|
|
29
|
+
const currentCssId = queue.shift();
|
|
30
|
+
sortedCssIds.push(currentCssId);
|
|
31
|
+
const currentAdjunction = styleInfo[currentCssId]?.imports;
|
|
32
|
+
if (currentAdjunction) {
|
|
33
|
+
for (const importCssId of currentAdjunction) {
|
|
34
|
+
const importInDegree = inDegreeMap.get(importCssId) - 1;
|
|
35
|
+
inDegreeMap.set(importCssId, importInDegree);
|
|
36
|
+
if (importInDegree === 0) {
|
|
37
|
+
queue.push(importCssId);
|
|
22
38
|
}
|
|
23
39
|
}
|
|
24
|
-
oneInfo.imports = undefined;
|
|
25
40
|
}
|
|
26
|
-
return oneInfo;
|
|
27
41
|
}
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
return sortedCssIds;
|
|
43
|
+
}
|
|
44
|
+
function generateImportByMap(styleInfo, sortedCssIds) {
|
|
45
|
+
const cssIdToImportBy = new Map();
|
|
46
|
+
for (const cssId of sortedCssIds) {
|
|
47
|
+
const currentAdjunction = styleInfo[cssId]?.imports;
|
|
48
|
+
if (currentAdjunction) {
|
|
49
|
+
const currentImportBy = cssIdToImportBy.get(cssId) ?? new Set([cssId]);
|
|
50
|
+
for (const importCssId of currentAdjunction) {
|
|
51
|
+
const importDeps = cssIdToImportBy.get(importCssId)
|
|
52
|
+
?? new Set([importCssId]);
|
|
53
|
+
importDeps.add(cssId);
|
|
54
|
+
cssIdToImportBy.set(importCssId, currentImportBy.union(importDeps));
|
|
55
|
+
}
|
|
56
|
+
cssIdToImportBy.set(cssId, currentImportBy);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return cssIdToImportBy;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* get Transitive Closure of a Direct Acyclic Graph (DAG)
|
|
63
|
+
* 1. for each css, find all the imported by css files (directly and indirectly)
|
|
64
|
+
* 2. for each css, find all the importing css files (directly and indirectly)
|
|
65
|
+
* 3. return the flattened style info, do not modify the content and rules
|
|
66
|
+
*/
|
|
67
|
+
export function flattenStyleInfo(styleInfo) {
|
|
68
|
+
// Step 1. Topological sorting
|
|
69
|
+
const sortedCssIds = topologicalSort(styleInfo);
|
|
70
|
+
// Step 2. generate deps;
|
|
71
|
+
const cssIdToImportBy = generateImportByMap(styleInfo, sortedCssIds);
|
|
72
|
+
sortedCssIds.reverse();
|
|
73
|
+
// Step 3. generate the flattened style info
|
|
74
|
+
return sortedCssIds.map(cssId => {
|
|
75
|
+
const oneInfo = styleInfo[cssId];
|
|
76
|
+
const flattenedInfo = oneInfo
|
|
77
|
+
? {
|
|
78
|
+
content: oneInfo.content,
|
|
79
|
+
rules: oneInfo.rules,
|
|
80
|
+
importBy: Array.from(cssIdToImportBy.get(cssId) ?? [cssId]),
|
|
81
|
+
}
|
|
82
|
+
: {
|
|
83
|
+
content: [],
|
|
84
|
+
rules: [],
|
|
85
|
+
importBy: [cssId],
|
|
86
|
+
};
|
|
87
|
+
return flattenedInfo;
|
|
30
88
|
});
|
|
31
89
|
}
|
|
32
90
|
/**
|
|
33
91
|
* apply the lynx css -> web css transformation
|
|
34
92
|
*/
|
|
35
93
|
export function transformToWebCss(styleInfo) {
|
|
36
|
-
for (const cssInfos of
|
|
94
|
+
for (const cssInfos of styleInfo) {
|
|
37
95
|
for (const rule of cssInfos.rules) {
|
|
38
96
|
const { sel: selectors, decl: declarations } = rule;
|
|
39
97
|
const { transformedStyle, childStyle } = transformParsedStyles(declarations);
|
|
@@ -56,13 +114,7 @@ export function genCssContent(styleInfo, pageConfig, entryName) {
|
|
|
56
114
|
function getExtraSelectors(cssId) {
|
|
57
115
|
let suffix;
|
|
58
116
|
if (!pageConfig.enableRemoveCSSScope) {
|
|
59
|
-
|
|
60
|
-
suffix = `[${cssIdAttribute}="${cssId}"]`;
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
// To make sure the Specificity correct
|
|
64
|
-
suffix = `[${lynxTagAttribute}]`;
|
|
65
|
-
}
|
|
117
|
+
suffix = `[${cssIdAttribute}="${cssId}"]`;
|
|
66
118
|
}
|
|
67
119
|
else {
|
|
68
120
|
suffix = `[${lynxTagAttribute}]`;
|
|
@@ -76,13 +128,15 @@ export function genCssContent(styleInfo, pageConfig, entryName) {
|
|
|
76
128
|
return suffix;
|
|
77
129
|
}
|
|
78
130
|
const finalCssContent = [];
|
|
79
|
-
for (const
|
|
80
|
-
const suffix = getExtraSelectors(cssId);
|
|
131
|
+
for (const cssInfos of styleInfo) {
|
|
81
132
|
const declarationContent = cssInfos.rules.map((rule) => {
|
|
82
133
|
const { sel: selectorList, decl: declarations } = rule;
|
|
83
134
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
|
|
84
|
-
const selectorString =
|
|
85
|
-
|
|
135
|
+
const selectorString = cssInfos.importBy.map(cssId => {
|
|
136
|
+
const suffix = getExtraSelectors(cssId);
|
|
137
|
+
return selectorList.map((selectors) => {
|
|
138
|
+
return selectors.toSpliced(-4, 0, [suffix]).flat().join('');
|
|
139
|
+
}).join(',');
|
|
86
140
|
}).join(',');
|
|
87
141
|
const declarationString = declarations.map(([k, v]) => `${k}:${v};`).join('');
|
|
88
142
|
return `${selectorString}{${declarationString}}`;
|
|
@@ -95,10 +149,10 @@ export function genCssContent(styleInfo, pageConfig, entryName) {
|
|
|
95
149
|
* generate the css-in-js data
|
|
96
150
|
*/
|
|
97
151
|
export function genCssOGInfo(styleInfo) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
152
|
+
const cssOGInfo = {};
|
|
153
|
+
for (const oneInfo of styleInfo) {
|
|
154
|
+
oneInfo.rules = oneInfo.rules.filter(oneRule => {
|
|
155
|
+
oneRule.sel = oneRule.sel.filter(selectorList => {
|
|
102
156
|
const [classSelectors, pseudoClassSelectors, pseudoElementSelectors, combinator,] = selectorList;
|
|
103
157
|
if (
|
|
104
158
|
// only one class selector
|
|
@@ -107,21 +161,26 @@ export function genCssOGInfo(styleInfo) {
|
|
|
107
161
|
&& pseudoElementSelectors.length === 0
|
|
108
162
|
&& combinator.length === 0) {
|
|
109
163
|
const selectorName = classSelectors[0].substring(1);
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
164
|
+
for (const cssId of oneInfo.importBy) {
|
|
165
|
+
if (!cssOGInfo[cssId]) {
|
|
166
|
+
cssOGInfo[cssId] = {};
|
|
167
|
+
}
|
|
168
|
+
const currentDeclarations = cssOGInfo[cssId][selectorName];
|
|
169
|
+
if (currentDeclarations) {
|
|
170
|
+
currentDeclarations.push(...oneRule.decl);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
cssOGInfo[cssId][selectorName] = oneRule.decl;
|
|
174
|
+
}
|
|
116
175
|
}
|
|
117
176
|
return false; // remove this selector from style info
|
|
118
177
|
}
|
|
119
178
|
return true;
|
|
120
179
|
});
|
|
121
|
-
return
|
|
180
|
+
return oneRule.sel.length > 0;
|
|
122
181
|
});
|
|
123
|
-
|
|
124
|
-
|
|
182
|
+
}
|
|
183
|
+
return cssOGInfo;
|
|
125
184
|
}
|
|
126
185
|
export function appendStyleElement(styleInfo, pageConfig, rootDom, document, entryName, ssrHydrateInfo) {
|
|
127
186
|
const lynxUniqueIdToStyleRulesIndex = ssrHydrateInfo?.lynxUniqueIdToStyleRulesIndex ?? [];
|
|
@@ -133,18 +192,18 @@ export function appendStyleElement(styleInfo, pageConfig, rootDom, document, ent
|
|
|
133
192
|
* 4. create the style element
|
|
134
193
|
* 5. append the style element to the root dom
|
|
135
194
|
*/
|
|
136
|
-
flattenStyleInfo(styleInfo
|
|
137
|
-
transformToWebCss(
|
|
195
|
+
const flattenedStyleInfo = flattenStyleInfo(styleInfo);
|
|
196
|
+
transformToWebCss(flattenedStyleInfo);
|
|
138
197
|
const cssOGInfo = pageConfig.enableCSSSelector
|
|
139
198
|
? {}
|
|
140
|
-
: genCssOGInfo(
|
|
199
|
+
: genCssOGInfo(flattenedStyleInfo);
|
|
141
200
|
let cardStyleElement;
|
|
142
201
|
if (ssrHydrateInfo?.cardStyleElement) {
|
|
143
202
|
cardStyleElement = ssrHydrateInfo.cardStyleElement;
|
|
144
203
|
}
|
|
145
204
|
else {
|
|
146
205
|
cardStyleElement = document.createElement('style');
|
|
147
|
-
cardStyleElement.textContent = genCssContent(
|
|
206
|
+
cardStyleElement.textContent = genCssContent(flattenedStyleInfo, pageConfig, entryName);
|
|
148
207
|
rootDom.appendChild(cardStyleElement);
|
|
149
208
|
}
|
|
150
209
|
const cardStyleElementSheet = cardStyleElement.sheet;
|
|
@@ -161,9 +220,9 @@ export function appendStyleElement(styleInfo, pageConfig, rootDom, document, ent
|
|
|
161
220
|
}
|
|
162
221
|
};
|
|
163
222
|
const updateLazyComponentStyle = (styleInfo, entryName) => {
|
|
164
|
-
flattenStyleInfo(styleInfo
|
|
165
|
-
transformToWebCss(
|
|
166
|
-
const newStyleSheet = genCssContent(
|
|
223
|
+
const flattenedStyleInfo = flattenStyleInfo(styleInfo);
|
|
224
|
+
transformToWebCss(flattenedStyleInfo);
|
|
225
|
+
const newStyleSheet = genCssContent(flattenedStyleInfo, pageConfig, entryName);
|
|
167
226
|
cardStyleElement.textContent += newStyleSheet;
|
|
168
227
|
};
|
|
169
228
|
return { updateCssOGStyle, updateLazyComponentStyle };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynx-js/web-mainthread-apis-canary",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0-canary-20250918-b17b7cb2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "",
|
|
6
6
|
"keywords": [],
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"**/*.css"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@lynx-js/web-constants": "npm:@lynx-js/web-constants-canary@0.
|
|
28
|
-
"@lynx-js/web-style-transformer": "npm:@lynx-js/web-style-transformer-canary@0.
|
|
27
|
+
"@lynx-js/web-constants": "npm:@lynx-js/web-constants-canary@0.17.0-canary-20250918-b17b7cb2",
|
|
28
|
+
"@lynx-js/web-style-transformer": "npm:@lynx-js/web-style-transformer-canary@0.17.0-canary-20250918-b17b7cb2",
|
|
29
29
|
"hyphenate-style-name": "^1.1.0"
|
|
30
30
|
}
|
|
31
31
|
}
|