@lynx-js/template-webpack-plugin-canary 0.7.0-canary-20250523-790e6b63 → 0.7.0-canary-20250523-5ddec124
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 +5 -1
- package/lib/WebEncodePlugin.d.ts +13 -0
- package/lib/WebEncodePlugin.js +96 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/web/StyleInfo.d.ts +10 -0
- package/lib/web/StyleInfo.js +5 -0
- package/lib/web/genStyleInfo.d.ts +3 -0
- package/lib/web/genStyleInfo.js +97 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @lynx-js/template-webpack-plugin
|
|
2
2
|
|
|
3
|
-
## 0.7.0-canary-
|
|
3
|
+
## 0.7.0-canary-20250523154624-5ddec124ab26e61e415576d575a400e76c7bd8d2
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
multi-thread: startMainWorker -> prepareMainThreadAPIs -> startMainThread -> createMainThreadContext(new MainThreadRuntime)
|
|
34
34
|
all-on-ui: prepareMainThreadAPIs -> startMainThread -> createMainThreadContext(new MainThreadRuntime)
|
|
35
35
|
|
|
36
|
+
- Add `WebEncodePlugin`. ([#904](https://github.com/lynx-family/lynx-stack/pull/904))
|
|
37
|
+
|
|
38
|
+
This is previously known as `WebWebpackPlugin` from `@lynx-js/web-webpack-plugin`.
|
|
39
|
+
|
|
36
40
|
- Fix a bug that the `lepus` arg of `beforeEmit` hook does not contains the `root` main chunk of the main thread. ([#898](https://github.com/lynx-family/lynx-stack/pull/898))
|
|
37
41
|
|
|
38
42
|
## 0.6.11
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Compilation, Compiler } from 'webpack';
|
|
2
|
+
export declare class WebEncodePlugin {
|
|
3
|
+
static name: string;
|
|
4
|
+
static BEFORE_ENCODE_HOOK_STAGE: number;
|
|
5
|
+
static ENCODE_HOOK_STAGE: number;
|
|
6
|
+
apply(compiler: Compiler): void;
|
|
7
|
+
/**
|
|
8
|
+
* The deleteDebuggingAssets delete all the assets that are inlined into the template.
|
|
9
|
+
*/
|
|
10
|
+
deleteDebuggingAssets(compilation: Compilation, assets: ({
|
|
11
|
+
name: string;
|
|
12
|
+
} | undefined)[]): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Copyright 2024 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 { LynxTemplatePlugin, isDebug, isRsdoctor, } from './LynxTemplatePlugin.js';
|
|
5
|
+
import { genStyleInfo } from './web/genStyleInfo.js';
|
|
6
|
+
export class WebEncodePlugin {
|
|
7
|
+
static name = 'WebEncodePlugin';
|
|
8
|
+
static BEFORE_ENCODE_HOOK_STAGE = 100;
|
|
9
|
+
static ENCODE_HOOK_STAGE = 100;
|
|
10
|
+
apply(compiler) {
|
|
11
|
+
const isDev = process.env['NODE_ENV'] === 'development'
|
|
12
|
+
|| compiler.options.mode === 'development';
|
|
13
|
+
compiler.hooks.thisCompilation.tap(WebEncodePlugin.name, (compilation) => {
|
|
14
|
+
const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation);
|
|
15
|
+
const inlinedAssets = new Set();
|
|
16
|
+
const { Compilation } = compiler.webpack;
|
|
17
|
+
compilation.hooks.processAssets.tap({
|
|
18
|
+
name: WebEncodePlugin.name,
|
|
19
|
+
// `PROCESS_ASSETS_STAGE_REPORT` is the last stage of the `processAssets` hook.
|
|
20
|
+
// We need to run our asset deletion after this stage to ensure all assets have been processed.
|
|
21
|
+
// E.g.: upload source-map to sentry.
|
|
22
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_REPORT + 1,
|
|
23
|
+
}, () => {
|
|
24
|
+
inlinedAssets.forEach((name) => {
|
|
25
|
+
compilation.deleteAsset(name);
|
|
26
|
+
});
|
|
27
|
+
inlinedAssets.clear();
|
|
28
|
+
});
|
|
29
|
+
hooks.beforeEncode.tap({
|
|
30
|
+
name: WebEncodePlugin.name,
|
|
31
|
+
stage: WebEncodePlugin.BEFORE_ENCODE_HOOK_STAGE,
|
|
32
|
+
}, (encodeOptions) => {
|
|
33
|
+
const { encodeData } = encodeOptions;
|
|
34
|
+
const { cssMap } = encodeData.css;
|
|
35
|
+
const styleInfo = genStyleInfo(cssMap);
|
|
36
|
+
const [name, content] = last(Object.entries(encodeData.manifest));
|
|
37
|
+
if (!isDebug() && !isDev && !isRsdoctor()) {
|
|
38
|
+
[
|
|
39
|
+
{ name },
|
|
40
|
+
encodeData.lepusCode.root,
|
|
41
|
+
...encodeData.lepusCode.chunks,
|
|
42
|
+
...encodeData.css.chunks,
|
|
43
|
+
]
|
|
44
|
+
.filter(asset => asset !== undefined)
|
|
45
|
+
.forEach(asset => inlinedAssets.add(asset.name));
|
|
46
|
+
}
|
|
47
|
+
Object.assign(encodeData, {
|
|
48
|
+
styleInfo,
|
|
49
|
+
manifest: {
|
|
50
|
+
// `app-service.js` is the entry point of a template.
|
|
51
|
+
'/app-service.js': content,
|
|
52
|
+
},
|
|
53
|
+
customSections: encodeData.customSections,
|
|
54
|
+
cardType: encodeData.sourceContent.dsl.substring(0, 5),
|
|
55
|
+
pageConfig: encodeData.compilerOptions,
|
|
56
|
+
});
|
|
57
|
+
return encodeOptions;
|
|
58
|
+
});
|
|
59
|
+
hooks.encode.tap({
|
|
60
|
+
name: WebEncodePlugin.name,
|
|
61
|
+
stage: WebEncodePlugin.ENCODE_HOOK_STAGE,
|
|
62
|
+
}, ({ encodeOptions }) => {
|
|
63
|
+
return {
|
|
64
|
+
buffer: Buffer.from(JSON.stringify({
|
|
65
|
+
styleInfo: encodeOptions['styleInfo'],
|
|
66
|
+
manifest: encodeOptions.manifest,
|
|
67
|
+
cardType: encodeOptions['cardType'],
|
|
68
|
+
pageConfig: encodeOptions.compilerOptions,
|
|
69
|
+
lepusCode: {
|
|
70
|
+
// flatten the lepusCode to a single object
|
|
71
|
+
...encodeOptions.lepusCode.lepusChunk,
|
|
72
|
+
root: encodeOptions.lepusCode.root,
|
|
73
|
+
},
|
|
74
|
+
customSections: encodeOptions.customSections,
|
|
75
|
+
})),
|
|
76
|
+
debugInfo: '',
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The deleteDebuggingAssets delete all the assets that are inlined into the template.
|
|
83
|
+
*/
|
|
84
|
+
deleteDebuggingAssets(compilation, assets) {
|
|
85
|
+
assets
|
|
86
|
+
.filter(asset => asset !== undefined)
|
|
87
|
+
.forEach(asset => deleteAsset(asset));
|
|
88
|
+
function deleteAsset({ name }) {
|
|
89
|
+
return compilation.deleteAsset(name);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function last(array) {
|
|
94
|
+
return array[array.length - 1];
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=WebEncodePlugin.js.map
|
package/lib/index.d.ts
CHANGED
|
@@ -7,5 +7,6 @@ export { LynxTemplatePlugin } from './LynxTemplatePlugin.js';
|
|
|
7
7
|
export type { LynxTemplatePluginOptions, TemplateHooks, } from './LynxTemplatePlugin.js';
|
|
8
8
|
export { LynxEncodePlugin } from './LynxEncodePlugin.js';
|
|
9
9
|
export type { LynxEncodePluginOptions, EncodeCSSOptions, } from './LynxEncodePlugin.js';
|
|
10
|
+
export { WebEncodePlugin } from './WebEncodePlugin.js';
|
|
10
11
|
export * as CSSPlugins from './css/plugins/index.js';
|
|
11
12
|
export * as CSS from './css/index.js';
|
package/lib/index.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { LynxTemplatePlugin } from './LynxTemplatePlugin.js';
|
|
10
10
|
export { LynxEncodePlugin } from './LynxEncodePlugin.js';
|
|
11
|
+
export { WebEncodePlugin } from './WebEncodePlugin.js';
|
|
11
12
|
export * as CSSPlugins from './css/plugins/index.js';
|
|
12
13
|
export * as CSS from './css/index.js';
|
|
13
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright 2024 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 * as CSS from '../css/index.js';
|
|
5
|
+
export function genStyleInfo(cssMap) {
|
|
6
|
+
return Object.fromEntries(Object.entries(cssMap).map(([cssId, nodes]) => {
|
|
7
|
+
/**
|
|
8
|
+
* note that "0" implies it's a common style
|
|
9
|
+
*/
|
|
10
|
+
const contentsAtom = [];
|
|
11
|
+
const imports = [];
|
|
12
|
+
const rules = [];
|
|
13
|
+
for (const node of nodes) {
|
|
14
|
+
if (node.type === 'FontFaceRule') {
|
|
15
|
+
contentsAtom.push([
|
|
16
|
+
'@font-face {',
|
|
17
|
+
node.style.map((declaration) => `${declaration.name}:${declaration.value}`).join(';'),
|
|
18
|
+
'}',
|
|
19
|
+
].join(''));
|
|
20
|
+
}
|
|
21
|
+
else if (node.type === 'ImportRule') {
|
|
22
|
+
imports.push(node.href);
|
|
23
|
+
}
|
|
24
|
+
else if (node.type === 'KeyframesRule') {
|
|
25
|
+
contentsAtom.push([
|
|
26
|
+
`@keyframes ${node.name.value} {`,
|
|
27
|
+
node.styles.map((keyframesStyle) => `${keyframesStyle.keyText.value} {${keyframesStyle.style.map((declaration) => `${declaration.name}:${declaration.value};`).join('')}}`).join(' '),
|
|
28
|
+
'}',
|
|
29
|
+
].join(''));
|
|
30
|
+
}
|
|
31
|
+
else if (node.type === 'StyleRule') {
|
|
32
|
+
const ast = CSS.csstree.parse(`${node.selectorText.value}{ --mocked-declaration:1;}`);
|
|
33
|
+
const selectors = ast.children.first
|
|
34
|
+
.prelude.children
|
|
35
|
+
.toArray();
|
|
36
|
+
const groupedSelectors = [];
|
|
37
|
+
for (const selectorList of selectors) {
|
|
38
|
+
let plainSelectors = [];
|
|
39
|
+
let pseudoClassSelectors = [];
|
|
40
|
+
let pseudoElementSelectors = [];
|
|
41
|
+
const currentSplittedSelectorInfo = [];
|
|
42
|
+
for (const selector of selectorList.children.toArray()) {
|
|
43
|
+
if (selector.type === 'PseudoClassSelector'
|
|
44
|
+
&& selector.name === 'root') {
|
|
45
|
+
/**
|
|
46
|
+
* [aa]:root {
|
|
47
|
+
* }
|
|
48
|
+
* ===>
|
|
49
|
+
* [aa][lynx-tag="page"] {
|
|
50
|
+
* }
|
|
51
|
+
*/
|
|
52
|
+
plainSelectors.push('[lynx-tag="page"]');
|
|
53
|
+
}
|
|
54
|
+
else if (selector.type === 'PseudoClassSelector') {
|
|
55
|
+
pseudoClassSelectors.push(CSS.csstree.generate(selector));
|
|
56
|
+
}
|
|
57
|
+
else if (selector.type === 'PseudoElementSelector') {
|
|
58
|
+
pseudoElementSelectors.push(CSS.csstree.generate(selector));
|
|
59
|
+
}
|
|
60
|
+
else if (selector.type === 'TypeSelector') {
|
|
61
|
+
plainSelectors.push(`[lynx-tag="${selector.name}"]`);
|
|
62
|
+
}
|
|
63
|
+
else if (selector.type === 'Combinator') {
|
|
64
|
+
currentSplittedSelectorInfo.push(plainSelectors, pseudoClassSelectors, pseudoElementSelectors, [CSS.csstree.generate(selector)]);
|
|
65
|
+
plainSelectors = [];
|
|
66
|
+
pseudoClassSelectors = [];
|
|
67
|
+
pseudoElementSelectors = [];
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
plainSelectors.push(CSS.csstree.generate(selector));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
currentSplittedSelectorInfo.push(plainSelectors, pseudoClassSelectors, pseudoElementSelectors, []);
|
|
74
|
+
groupedSelectors.push(currentSplittedSelectorInfo);
|
|
75
|
+
}
|
|
76
|
+
const decl = node.style.map((declaration) => [
|
|
77
|
+
declaration.name,
|
|
78
|
+
declaration.value.replaceAll(/\{\{--([^}]+)\}\}/g, 'var(--$1)'),
|
|
79
|
+
]);
|
|
80
|
+
decl.push(...(Object.entries(node.variables)));
|
|
81
|
+
rules.push({
|
|
82
|
+
sel: groupedSelectors,
|
|
83
|
+
decl,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const info = {
|
|
88
|
+
content: [contentsAtom.join('\n')],
|
|
89
|
+
rules,
|
|
90
|
+
};
|
|
91
|
+
if (imports.length > 0) {
|
|
92
|
+
info.imports = imports;
|
|
93
|
+
}
|
|
94
|
+
return [cssId, info];
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=genStyleInfo.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynx-js/template-webpack-plugin-canary",
|
|
3
|
-
"version": "0.7.0-canary-20250523-
|
|
3
|
+
"version": "0.7.0-canary-20250523-5ddec124",
|
|
4
4
|
"description": "Simplifies creation of Lynx template files to serve your webpack bundles",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"webpack",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"@types/css-tree": "^2.3.10",
|
|
45
45
|
"@types/object.groupby": "^1.0.4",
|
|
46
46
|
"webpack": "^5.99.9",
|
|
47
|
-
"@lynx-js/
|
|
48
|
-
"@lynx-js/
|
|
47
|
+
"@lynx-js/vitest-setup": "0.0.0",
|
|
48
|
+
"@lynx-js/test-tools": "0.0.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=18"
|