@blotch/rsbuild-plugin-angular-lynx 22.2.1 → 22.2.3
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/README.md +20 -3
- package/dist/544.js +21 -0
- package/dist/angular-cli-context.d.ts +34 -0
- package/dist/angular-diagnostics.d.ts +58 -0
- package/dist/angular-diagnostics.test.d.ts +1 -0
- package/dist/angular-rebuild-coordinator.d.ts +1 -1
- package/dist/angular.d.ts +5 -3
- package/dist/background-entry.d.ts +96 -0
- package/dist/background-entry.test.d.ts +1 -0
- package/dist/budgets-plugin.d.ts +64 -0
- package/dist/budgets-plugin.test.d.ts +1 -0
- package/dist/client/background-hot-updates.d.ts +50 -0
- package/dist/client/background-hot-updates.js +77 -0
- package/dist/client/background-hot-updates.test.d.ts +1 -0
- package/dist/client/css-hot-update.cjs +9 -0
- package/dist/client/css-hot-update.d.ts +44 -0
- package/dist/client/css-hot-update.js +42 -0
- package/dist/client/css-hot-update.test.d.ts +1 -0
- package/dist/client/hmr-background.js +16 -0
- package/dist/client/hmr-main-thread.js +9 -0
- package/dist/client/hmr-protocol.d.ts +74 -0
- package/dist/client/main-thread-hot-updates.d.ts +40 -0
- package/dist/client/main-thread-hot-updates.js +78 -0
- package/dist/client/main-thread-hot-updates.test.d.ts +1 -0
- package/dist/client/testing/test-context.d.ts +16 -0
- package/dist/component-styles-cache.d.ts +13 -31
- package/dist/component-styles.d.ts +73 -0
- package/dist/component-styles.test.d.ts +1 -0
- package/dist/cross-thread-transform.d.ts +38 -0
- package/dist/cross-thread-transform.test.d.ts +1 -0
- package/dist/css.d.ts +2 -2
- package/dist/entry.d.ts +28 -2
- package/dist/hot-updates.d.ts +67 -0
- package/dist/hot-updates.test.d.ts +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1494 -638
- package/dist/layers.d.ts +6 -4
- package/dist/logger/dev-logger-middleware.d.ts +13 -7
- package/dist/logger/dev-logger.d.ts +13 -0
- package/dist/polyfills.js +56 -0
- package/dist/polyfills.test.d.ts +1 -0
- package/dist/pure-classes.d.ts +27 -0
- package/dist/pure-classes.test.d.ts +1 -0
- package/dist/resolve.d.ts +19 -0
- package/dist/resolve.test.d.ts +1 -0
- package/dist/split-chunks.d.ts +2 -2
- package/dist/styles/blur-view.css +16 -0
- package/dist/transform-module.d.ts +43 -17
- package/dist/utils/angular/budgets.d.ts +72 -0
- package/dist/utils/angular/budgets.test.d.ts +1 -0
- package/dist/utils/angular/build-internals.d.ts +14 -0
- package/dist/utils/angular/component-scope-id.d.ts +5 -3
- package/dist/utils/angular/component-style-bundler.d.ts +1 -1
- package/dist/utils/angular/options.d.ts +80 -2
- package/dist/utils/angular/read-workspace.d.ts +5 -1
- package/dist/utils/angular/resolve-primary-build.d.ts +26 -0
- package/dist/utils/angular/resolve-primary-build.test.d.ts +1 -0
- package/dist/utils/options.d.ts +40 -1
- package/package.json +13 -8
- package/dist/loaders/thread-globals-loader.d.ts +0 -8
- package/dist/loaders/thread-globals-loader.js +0 -6
- package/patch/patch-angular-build.cjs +0 -27
- /package/dist/{loaders/thread-globals-loader.test.d.ts → angular-cli-context.test.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
/*! LICENSE: index.js.LICENSE.txt */
|
|
2
2
|
import node_fs, { existsSync } from "node:fs";
|
|
3
|
-
import node_path, { join, resolve } from "node:path";
|
|
4
|
-
import { DiagnosticModes, createAngularCompilation } from "@angular/build/src/tools/angular/compilation";
|
|
5
|
-
import { JavaScriptTransformer } from "@angular/build/src/tools/javascript-transformer";
|
|
6
|
-
import { createHash } from "node:crypto";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { availableParallelism } from "node:os";
|
|
9
|
-
import node_assert from "node:assert";
|
|
10
|
-
import { access, constants } from "node:fs/promises";
|
|
11
|
-
import { workspaces } from "@angular-devkit/core";
|
|
12
|
-
import { NodeJsSyncHost } from "@angular-devkit/core/node";
|
|
3
|
+
import node_path, { join, resolve as external_node_path_resolve } from "node:path";
|
|
13
4
|
import { CSSPlugins, LynxEncodePlugin, LynxTemplatePlugin, WebEncodePlugin } from "@lynx-js/template-webpack-plugin";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
14
7
|
import { RuntimeWrapperWebpackPlugin } from "@lynx-js/runtime-wrapper-webpack-plugin";
|
|
15
8
|
import { RuntimeGlobals } from "@lynx-js/webpack-runtime-globals";
|
|
16
9
|
import tiny_invariant from "tiny-invariant";
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import { availableParallelism } from "node:os";
|
|
12
|
+
import { workspaces } from "@angular-devkit/core";
|
|
13
|
+
import { NodeJsSyncHost } from "@angular-devkit/core/node";
|
|
14
|
+
import { access, constants } from "node:fs/promises";
|
|
19
15
|
import * as __rspack_external_typescript from "typescript";
|
|
20
16
|
import * as __rspack_external_node_path_c5b9b54f from "node:path";
|
|
17
|
+
const ANGULAR_CLI_CONTEXT = Symbol.for('@blotch/rsbuild-plugin-angular-lynx:angular-cli-context');
|
|
18
|
+
const ANGULAR_CLI_CONTEXT_PLUGIN_NAME = 'lynx:angular-cli-context';
|
|
19
|
+
const pluginAngularCliContext = (context)=>({
|
|
20
|
+
name: ANGULAR_CLI_CONTEXT_PLUGIN_NAME,
|
|
21
|
+
enforce: 'pre',
|
|
22
|
+
setup: (api)=>{
|
|
23
|
+
api.expose(ANGULAR_CLI_CONTEXT, context);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
const getAngularCliContext = (api)=>api.useExposed(ANGULAR_CLI_CONTEXT);
|
|
21
27
|
const TYPESCRIPT_FILE = /\.[cm]?tsx?$/;
|
|
22
28
|
const readFileVersion = (file)=>node_fs.statSync(file, {
|
|
23
29
|
throwIfNoEntry: false
|
|
@@ -64,17 +70,572 @@ const createAngularRebuildCoordinator = ({ compile, getFileVersion = readFileVer
|
|
|
64
70
|
pendingFiles.add(file);
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
|
-
const run = queue.then(runCompile);
|
|
68
|
-
queue = run.catch(()=>{});
|
|
69
|
-
await run;
|
|
70
|
-
const lastSeen = environmentGenerations.get(environmentName);
|
|
71
|
-
environmentGenerations.set(environmentName, generation);
|
|
72
|
-
const outdated = new Set();
|
|
73
|
-
if (void 0 === lastSeen) return outdated;
|
|
74
|
-
for (const [file, outputGeneration] of outputGenerations)if (outputGeneration > lastSeen) outdated.add(file);
|
|
75
|
-
return outdated;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
73
|
+
const run = queue.then(runCompile);
|
|
74
|
+
queue = run.catch(()=>{});
|
|
75
|
+
await run;
|
|
76
|
+
const lastSeen = environmentGenerations.get(environmentName);
|
|
77
|
+
environmentGenerations.set(environmentName, generation);
|
|
78
|
+
const outdated = new Set();
|
|
79
|
+
if (void 0 === lastSeen) return outdated;
|
|
80
|
+
for (const [file, outputGeneration] of outputGenerations)if (outputGeneration > lastSeen) outdated.add(file);
|
|
81
|
+
return outdated;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
const LAYERS = {
|
|
86
|
+
BACKGROUND: 'background',
|
|
87
|
+
MAIN_THREAD: 'main'
|
|
88
|
+
};
|
|
89
|
+
const applyLayers = (api)=>{
|
|
90
|
+
api.modifyBundlerChain((chain)=>{
|
|
91
|
+
for (const [layer, target, isMainThread] of [
|
|
92
|
+
[
|
|
93
|
+
LAYERS.BACKGROUND,
|
|
94
|
+
'es2015',
|
|
95
|
+
false
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
LAYERS.MAIN_THREAD,
|
|
99
|
+
'es2019',
|
|
100
|
+
true
|
|
101
|
+
]
|
|
102
|
+
])chain.module.rule("typescript").oneOf(layer).issuerLayer(layer).test(/\.[cm]?[jt]sx?$/).use('builtin:swc-loader').loader('builtin:swc-loader').options({
|
|
103
|
+
jsc: {
|
|
104
|
+
target,
|
|
105
|
+
parser: {
|
|
106
|
+
syntax: "typescript"
|
|
107
|
+
},
|
|
108
|
+
transform: {
|
|
109
|
+
optimizer: {
|
|
110
|
+
simplify: false,
|
|
111
|
+
globals: {
|
|
112
|
+
vars: {
|
|
113
|
+
__MAIN_THREAD__: String(isMainThread)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}).end();
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
const createLynxProcessEvalResultRuntimeModule = (webpack)=>class extends webpack.RuntimeModule {
|
|
123
|
+
constructor(){
|
|
124
|
+
super('Lynx process eval result', webpack.RuntimeModule.STAGE_ATTACH);
|
|
125
|
+
}
|
|
126
|
+
generate() {
|
|
127
|
+
const chunk = this.chunk;
|
|
128
|
+
const compilation = this.compilation;
|
|
129
|
+
if (!chunk || !compilation) return '';
|
|
130
|
+
const chunkGroup = chunk._groupsIterable?.[0];
|
|
131
|
+
const modules = compilation.chunkGraph?.getChunkModules(chunk) ?? [];
|
|
132
|
+
modules.sort((a, b)=>{
|
|
133
|
+
const aIdx = chunkGroup?.getModulePreOrderIndex(a) ?? 0;
|
|
134
|
+
const bIdx = chunkGroup?.getModulePreOrderIndex(b) ?? 0;
|
|
135
|
+
return aIdx - bIdx;
|
|
136
|
+
});
|
|
137
|
+
const sortedIds = modules.map((m)=>compilation.chunkGraph.getModuleId(m)).filter((id)=>null != id);
|
|
138
|
+
const moduleOrder = JSON.stringify(sortedIds);
|
|
139
|
+
return `
|
|
140
|
+
${RuntimeGlobals.lynxProcessEvalResult} = function (result, schema) {
|
|
141
|
+
var chunk = result && result(schema);
|
|
142
|
+
if (chunk && chunk.ids && chunk.modules) {
|
|
143
|
+
${webpack.RuntimeGlobals.externalInstallChunk}(chunk);
|
|
144
|
+
var moduleOrder = ${moduleOrder};
|
|
145
|
+
for (var i = 0; i < moduleOrder.length; i++) {
|
|
146
|
+
if (chunk.modules[moduleOrder[i]]) {
|
|
147
|
+
${webpack.RuntimeGlobals.require}(moduleOrder[i]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return chunk;
|
|
151
|
+
}
|
|
152
|
+
return chunk
|
|
153
|
+
}
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
class AngularWebpackPlugin {
|
|
158
|
+
options;
|
|
159
|
+
constructor(options){
|
|
160
|
+
this.options = options;
|
|
161
|
+
}
|
|
162
|
+
static defaultOptions = Object.freeze({
|
|
163
|
+
disableCreateSelectorQueryIncompatibleWarning: false,
|
|
164
|
+
firstScreenSyncTiming: 'immediately',
|
|
165
|
+
enableSSR: false,
|
|
166
|
+
isWeb: false,
|
|
167
|
+
mainThreadChunks: [],
|
|
168
|
+
extractStr: false,
|
|
169
|
+
experimental_isLazyBundle: false
|
|
170
|
+
});
|
|
171
|
+
apply(compiler) {
|
|
172
|
+
const options = Object.assign({}, AngularWebpackPlugin.defaultOptions, this.options);
|
|
173
|
+
if (options.enableSSR && 'jsReady' !== options.firstScreenSyncTiming) options.firstScreenSyncTiming = 'jsReady';
|
|
174
|
+
const { DefinePlugin, EnvironmentPlugin } = compiler.webpack;
|
|
175
|
+
new EnvironmentPlugin({
|
|
176
|
+
DEBUG: null
|
|
177
|
+
}).apply(compiler);
|
|
178
|
+
new DefinePlugin({
|
|
179
|
+
__DEV__: JSON.stringify('development' === compiler.options.mode),
|
|
180
|
+
__PROFILE__: JSON.stringify('development' === compiler.options.mode),
|
|
181
|
+
__EXTRACT_STR__: JSON.stringify(Boolean(options.extractStr)),
|
|
182
|
+
__FIRST_SCREEN_SYNC_TIMING__: JSON.stringify(options.firstScreenSyncTiming),
|
|
183
|
+
__ENABLE_SSR__: JSON.stringify(options.enableSSR),
|
|
184
|
+
__WEB__: JSON.stringify(Boolean(options.isWeb)),
|
|
185
|
+
__DISABLE_CREATE_SELECTOR_QUERY_INCOMPATIBLE_WARNING__: JSON.stringify(options.disableCreateSelectorQueryIncompatibleWarning)
|
|
186
|
+
}).apply(compiler);
|
|
187
|
+
compiler.hooks.thisCompilation.tap(this.constructor.name, (compilation)=>{
|
|
188
|
+
const onceForChunkSet = new WeakSet();
|
|
189
|
+
compilation.hooks.runtimeRequirementInTree.for(compiler.webpack.RuntimeGlobals.ensureChunkHandlers).tap('VanillaWebpackPlugin', (chunk, runtimeRequirements)=>{
|
|
190
|
+
runtimeRequirements.add(RuntimeGlobals.lynxProcessEvalResult);
|
|
191
|
+
});
|
|
192
|
+
compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.lynxProcessEvalResult).tap('VanillaWebpackPlugin', (chunk)=>{
|
|
193
|
+
if (onceForChunkSet.has(chunk)) return;
|
|
194
|
+
onceForChunkSet.add(chunk);
|
|
195
|
+
const LynxProcessEvalResultRuntimeModule = createLynxProcessEvalResultRuntimeModule(compiler.webpack);
|
|
196
|
+
compilation.addRuntimeModule(chunk, new LynxProcessEvalResultRuntimeModule());
|
|
197
|
+
});
|
|
198
|
+
compilation.hooks.processAssets.tap({
|
|
199
|
+
name: this.constructor.name,
|
|
200
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
|
|
201
|
+
}, ()=>{
|
|
202
|
+
for (const name of options.mainThreadChunks ?? [])this.#updateMainThreadInfo(compilation, name);
|
|
203
|
+
for (const cg of compilation.chunkGroups.filter((cg)=>!cg.isInitial()).filter((cg)=>cg.origins.every((origin)=>origin.module?.layer === LAYERS.MAIN_THREAD))){
|
|
204
|
+
const files = cg.getFiles();
|
|
205
|
+
for (const name of files.filter((name)=>name.endsWith('.js')))this.#updateMainThreadInfo(compilation, name);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
{
|
|
209
|
+
const { ConcatSource } = compiler.webpack.sources;
|
|
210
|
+
const mainThreadChunkSet = new Set(options.mainThreadChunks ?? []);
|
|
211
|
+
compilation.hooks.processAssets.tap({
|
|
212
|
+
name: `${this.constructor.name}:threadGlobals`,
|
|
213
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
|
214
|
+
}, ()=>{
|
|
215
|
+
this.#markMainThreadHotUpdates(compilation, mainThreadChunkSet);
|
|
216
|
+
for (const [name] of Object.entries(compilation.assets).filter(([n])=>n.endsWith('.js') && !compilation.getAsset(n)?.info.hotModuleReplacement)){
|
|
217
|
+
const isMainThread = mainThreadChunkSet.has(name) || compilation.getAsset(name)?.info['lynx:main-thread'] === true;
|
|
218
|
+
const prefix = `globalThis["__MAIN_THREAD__"]=${isMainThread};`;
|
|
219
|
+
compilation.updateAsset(name, (old)=>new ConcatSource(prefix, old));
|
|
220
|
+
}
|
|
221
|
+
if (!options.experimental_isLazyBundle) for (const name of options.mainThreadChunks ?? []){
|
|
222
|
+
const asset = compilation.getAsset(name);
|
|
223
|
+
if (!asset) continue;
|
|
224
|
+
const source = asset.source.source().toString();
|
|
225
|
+
const useStrictPrefix = /^(['"])use strict\1;?/.test(source) ? "'use strict';" : '';
|
|
226
|
+
compilation.updateAsset(name, (old)=>new ConcatSource(`${useStrictPrefix}var globDynamicComponentEntry=globDynamicComponentEntry||'__Card__';`, old));
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation);
|
|
231
|
+
const { ConcatSource } = compiler.webpack.sources;
|
|
232
|
+
hooks.beforeEncode.tap(this.constructor.name, (args)=>{
|
|
233
|
+
const { encodeData } = args;
|
|
234
|
+
encodeData.sourceContent.config = {
|
|
235
|
+
...encodeData.sourceContent.config,
|
|
236
|
+
enableCSSInlineVariables: true
|
|
237
|
+
};
|
|
238
|
+
if (!encodeData.lepusCode.root) return args;
|
|
239
|
+
if ('card' === encodeData.sourceContent.appType) return args;
|
|
240
|
+
compilation.updateAsset(encodeData.lepusCode.root.name, (old)=>new ConcatSource(`\
|
|
241
|
+
(function (globDynamicComponentEntry) {
|
|
242
|
+
const module = { exports: {} }
|
|
243
|
+
const exports = module.exports
|
|
244
|
+
`, old, `
|
|
245
|
+
;return module.exports
|
|
246
|
+
})`));
|
|
247
|
+
return args;
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
#markMainThreadHotUpdates(compilation, mainThreadChunkSet) {
|
|
252
|
+
for (const chunk of compilation.chunks){
|
|
253
|
+
const files = [
|
|
254
|
+
...chunk.files
|
|
255
|
+
];
|
|
256
|
+
if (files.some((file)=>mainThreadChunkSet.has(file) || !compilation.getAsset(file)?.info.hotModuleReplacement && compilation.getAsset(file)?.info['lynx:main-thread'])) {
|
|
257
|
+
for (const file of files)if (file.endsWith('.js') && compilation.getAsset(file)?.info.hotModuleReplacement) this.#updateMainThreadInfo(compilation, file);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
#updateMainThreadInfo(compilation, name) {
|
|
262
|
+
const asset = compilation.getAsset(name);
|
|
263
|
+
tiny_invariant(asset, `Should have main thread asset ${name}`);
|
|
264
|
+
compilation.updateAsset(asset.name, asset.source, {
|
|
265
|
+
...asset.info,
|
|
266
|
+
'lynx:main-thread': true
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const S_LYNX_CONFIG = Symbol.for('@lynx-js/rsbuild-plugin:config');
|
|
271
|
+
const PLUGIN_NAME_TEMPLATE = 'lynx:template';
|
|
272
|
+
const PLUGIN_NAME_RUNTIME_WRAPPER = 'lynx:runtime-wrapper';
|
|
273
|
+
const PLUGIN_NAME_ANGULAR = 'lynx:angular';
|
|
274
|
+
const RULE_BACKGROUND_MODULES = 'lynx:background-modules';
|
|
275
|
+
const PLUGIN_NAME_CSS_HOT_UPDATE = 'lynx:css-hot-update';
|
|
276
|
+
const BLUR_VIEW_STYLESHEET = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './styles/blur-view.css');
|
|
277
|
+
const HMR_BACKGROUND_CLIENT = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './client/hmr-background.js');
|
|
278
|
+
const HMR_MAIN_THREAD_CLIENT = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './client/hmr-main-thread.js');
|
|
279
|
+
const CSS_HOT_UPDATE = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './client/css-hot-update.cjs');
|
|
280
|
+
const CSS_EXTRACT_HOT_UPDATE = /css-extract-webpack-plugin[\\/]runtime[\\/]hotModuleReplacement\.cjs$/;
|
|
281
|
+
const resolveReloadApp = ()=>createRequire(createRequire(import.meta.url).resolve('@lynx-js/rsbuild-plugin')).resolve('@lynx-js/webpack-dev-transport/reloadApp');
|
|
282
|
+
const applyEntry = (api, options, backgroundEntries, appEntries)=>{
|
|
283
|
+
const { customCSSInheritanceList, debugInfoOutside, defaultDisplayLinear, defaultOverflowVisible, enableA11y, enableAccessibilityElement, enableCSSInheritance, enableCSSInvalidation, enableCSSSelector, enableNewGesture, enableRemoveCSSScope, removeDescendantSelectorScope, targetSdkVersion } = options;
|
|
284
|
+
api.modifyBundlerChain((chain, { environment, isDev, rspack })=>{
|
|
285
|
+
const lynxConfig = api.useExposed(S_LYNX_CONFIG);
|
|
286
|
+
if (!lynxConfig) throw new Error('No Lynx config exposed. `pluginLynx` has to be applied for the Lynx build engine to be configured.');
|
|
287
|
+
const isLynx = 'lynx' === environment.name;
|
|
288
|
+
const isWeb = 'web' === environment.name;
|
|
289
|
+
const { hmr, liveReload } = environment.config.dev ?? {};
|
|
290
|
+
const enabledHMR = isDev && !isWeb && false !== hmr;
|
|
291
|
+
const enabledLiveReload = isDev && !isWeb && false !== liveReload;
|
|
292
|
+
const entries = chain.entryPoints.entries() ?? {};
|
|
293
|
+
chain.entryPoints.clear();
|
|
294
|
+
const preEntry = new Set(environment.config.source.preEntry);
|
|
295
|
+
const mainThreadChunks = [];
|
|
296
|
+
for (const [entryName, entryPoint] of Object.entries(entries)){
|
|
297
|
+
const { imports: entryImports } = getChunks(entryName, entryPoint.values());
|
|
298
|
+
const mainThreadImports = isLynx ? [
|
|
299
|
+
BLUR_VIEW_STYLESHEET,
|
|
300
|
+
...entryImports
|
|
301
|
+
] : entryImports;
|
|
302
|
+
const backgroundImports = [
|
|
303
|
+
...entryImports.filter((entryImport)=>preEntry.has(entryImport)),
|
|
304
|
+
backgroundEntries.fileFor(environment.name, entryName)
|
|
305
|
+
];
|
|
306
|
+
for (const entryImport of entryImports)if (entryImport.startsWith('.') || node_path.isAbsolute(entryImport)) appEntries.add(node_path.resolve(api.context.rootPath, entryImport));
|
|
307
|
+
const templateFilename = lynxConfig.resolveBundleFilename({
|
|
308
|
+
entryName,
|
|
309
|
+
platform: environment.name
|
|
310
|
+
});
|
|
311
|
+
const lazyBundleFilename = lynxConfig.resolveLazyBundleFilename({
|
|
312
|
+
platform: environment.name
|
|
313
|
+
});
|
|
314
|
+
const mainThreadEntry = `${entryName}__main-thread`;
|
|
315
|
+
const mainThreadName = node_path.posix.join(`${entryName}/main-thread.js`);
|
|
316
|
+
const backgroundEntry = entryName;
|
|
317
|
+
const backgroundThreadName = node_path.posix.join(`${entryName}/background-thread.js`);
|
|
318
|
+
mainThreadChunks.push(mainThreadName);
|
|
319
|
+
chain.entry(mainThreadEntry).add({
|
|
320
|
+
layer: LAYERS.MAIN_THREAD,
|
|
321
|
+
import: mainThreadImports,
|
|
322
|
+
filename: mainThreadName
|
|
323
|
+
}).when(enabledHMR, (entry)=>{
|
|
324
|
+
entry.prepend({
|
|
325
|
+
layer: LAYERS.MAIN_THREAD,
|
|
326
|
+
import: HMR_MAIN_THREAD_CLIENT
|
|
327
|
+
});
|
|
328
|
+
}).end();
|
|
329
|
+
chain.entry(backgroundEntry).add({
|
|
330
|
+
layer: LAYERS.BACKGROUND,
|
|
331
|
+
import: backgroundImports,
|
|
332
|
+
filename: backgroundThreadName
|
|
333
|
+
}).when(enabledHMR, (entry)=>{
|
|
334
|
+
entry.prepend({
|
|
335
|
+
layer: LAYERS.BACKGROUND,
|
|
336
|
+
import: HMR_BACKGROUND_CLIENT
|
|
337
|
+
});
|
|
338
|
+
}).when(enabledHMR || enabledLiveReload, (entry)=>{
|
|
339
|
+
entry.prepend({
|
|
340
|
+
layer: LAYERS.BACKGROUND,
|
|
341
|
+
import: '@lynx-js/webpack-dev-transport/client'
|
|
342
|
+
});
|
|
343
|
+
}).end();
|
|
344
|
+
chain.plugin(`${PLUGIN_NAME_TEMPLATE}-${entryName}`).use(LynxTemplatePlugin, [
|
|
345
|
+
{
|
|
346
|
+
filename: templateFilename,
|
|
347
|
+
...lazyBundleFilename ? {
|
|
348
|
+
lazyBundleFilename
|
|
349
|
+
} : {},
|
|
350
|
+
intermediate: lynxConfig.resolveIntermediateDir({
|
|
351
|
+
entryName
|
|
352
|
+
}),
|
|
353
|
+
chunks: [
|
|
354
|
+
mainThreadEntry,
|
|
355
|
+
backgroundEntry
|
|
356
|
+
],
|
|
357
|
+
cssPlugins: [
|
|
358
|
+
CSSPlugins.parserPlugins.removeFunctionWhiteSpace()
|
|
359
|
+
],
|
|
360
|
+
customCSSInheritanceList,
|
|
361
|
+
debugInfoOutside,
|
|
362
|
+
defaultDisplayLinear,
|
|
363
|
+
defaultOverflowVisible,
|
|
364
|
+
enableAccessibilityElement,
|
|
365
|
+
enableCSSInheritance,
|
|
366
|
+
enableCSSInvalidation,
|
|
367
|
+
enableCSSSelector,
|
|
368
|
+
enableNewGesture,
|
|
369
|
+
enableRemoveCSSScope,
|
|
370
|
+
removeDescendantSelectorScope,
|
|
371
|
+
targetSdkVersion,
|
|
372
|
+
enableA11y
|
|
373
|
+
}
|
|
374
|
+
]).end();
|
|
375
|
+
}
|
|
376
|
+
chain.module.rule(RULE_BACKGROUND_MODULES).issuerLayer(LAYERS.BACKGROUND).test((file)=>backgroundEntries.isBackgroundModule(file)).sideEffects(true);
|
|
377
|
+
if (enabledHMR) {
|
|
378
|
+
chain.resolve.alias.set('@lynx-js/webpack-dev-transport/reloadApp', resolveReloadApp());
|
|
379
|
+
chain.plugin(PLUGIN_NAME_CSS_HOT_UPDATE).use(rspack.NormalModuleReplacementPlugin, [
|
|
380
|
+
CSS_EXTRACT_HOT_UPDATE,
|
|
381
|
+
CSS_HOT_UPDATE
|
|
382
|
+
]).end();
|
|
383
|
+
}
|
|
384
|
+
if (isLynx) {
|
|
385
|
+
chain.plugin(PLUGIN_NAME_RUNTIME_WRAPPER).use(RuntimeWrapperWebpackPlugin, [
|
|
386
|
+
{
|
|
387
|
+
injectVars (vars) {
|
|
388
|
+
return vars.map((name)=>{
|
|
389
|
+
if ('Component' === name) return '__Component';
|
|
390
|
+
return name;
|
|
391
|
+
});
|
|
392
|
+
},
|
|
393
|
+
targetSdkVersion,
|
|
394
|
+
test: /^(?!.*main-thread(?:\.[A-Fa-f0-9]*)?\.js$).*\.js$/
|
|
395
|
+
}
|
|
396
|
+
]).end();
|
|
397
|
+
chain.plugin(`${LynxEncodePlugin.name}`).use(LynxEncodePlugin, [
|
|
398
|
+
{}
|
|
399
|
+
]).end();
|
|
400
|
+
}
|
|
401
|
+
if (isWeb) chain.plugin(`${WebEncodePlugin.name}`).use(WebEncodePlugin, []).end();
|
|
402
|
+
chain.plugin(PLUGIN_NAME_ANGULAR).after(PLUGIN_NAME_TEMPLATE).use(AngularWebpackPlugin, [
|
|
403
|
+
{
|
|
404
|
+
mainThreadChunks,
|
|
405
|
+
enableSSR: options.enableSSR,
|
|
406
|
+
isWeb
|
|
407
|
+
}
|
|
408
|
+
]);
|
|
409
|
+
});
|
|
410
|
+
};
|
|
411
|
+
const getChunks = (entryName, entryValue)=>{
|
|
412
|
+
const chunks = [
|
|
413
|
+
entryName
|
|
414
|
+
];
|
|
415
|
+
const imports = [];
|
|
416
|
+
for (const item of entryValue){
|
|
417
|
+
if ('string' == typeof item) {
|
|
418
|
+
imports.push(item);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (Array.isArray(item)) {
|
|
422
|
+
imports.push(...imports);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
const { dependOn } = item;
|
|
426
|
+
if (Array.isArray(item.import)) imports.push(...item.import);
|
|
427
|
+
else imports.push(item.import);
|
|
428
|
+
if (dependOn) if ('string' == typeof dependOn) chunks.unshift(dependOn);
|
|
429
|
+
else chunks.unshift(...dependOn);
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
chunks,
|
|
433
|
+
imports
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
const BYTES_IN_KILOBYTE = 1000;
|
|
437
|
+
const calculateBytes = (input, baseline, factor = 1)=>{
|
|
438
|
+
const matches = input.trim().match(/^(\d+(?:\.\d+)?)[ \t]*(%|[kmg]?b)?$/i);
|
|
439
|
+
if (!matches) return NaN;
|
|
440
|
+
const baselineBytes = baseline && calculateBytes(baseline) || 0;
|
|
441
|
+
let value = Number(matches[1]);
|
|
442
|
+
switch(matches[2]?.toLowerCase()){
|
|
443
|
+
case '%':
|
|
444
|
+
value = baselineBytes * value / 100;
|
|
445
|
+
break;
|
|
446
|
+
case 'kb':
|
|
447
|
+
value *= BYTES_IN_KILOBYTE;
|
|
448
|
+
break;
|
|
449
|
+
case 'mb':
|
|
450
|
+
value *= BYTES_IN_KILOBYTE * BYTES_IN_KILOBYTE;
|
|
451
|
+
break;
|
|
452
|
+
case 'gb':
|
|
453
|
+
value *= BYTES_IN_KILOBYTE * BYTES_IN_KILOBYTE * BYTES_IN_KILOBYTE;
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
if (0 === baselineBytes) return value;
|
|
457
|
+
return baselineBytes + value * factor;
|
|
458
|
+
};
|
|
459
|
+
const calculateThresholds = (budget)=>{
|
|
460
|
+
const thresholds = [];
|
|
461
|
+
if (budget.maximumWarning) thresholds.push({
|
|
462
|
+
limit: calculateBytes(budget.maximumWarning, budget.baseline, 1),
|
|
463
|
+
type: 'maximum',
|
|
464
|
+
severity: 'warning'
|
|
465
|
+
});
|
|
466
|
+
if (budget.maximumError) thresholds.push({
|
|
467
|
+
limit: calculateBytes(budget.maximumError, budget.baseline, 1),
|
|
468
|
+
type: 'maximum',
|
|
469
|
+
severity: 'error'
|
|
470
|
+
});
|
|
471
|
+
if (budget.minimumWarning) thresholds.push({
|
|
472
|
+
limit: calculateBytes(budget.minimumWarning, budget.baseline, -1),
|
|
473
|
+
type: 'minimum',
|
|
474
|
+
severity: 'warning'
|
|
475
|
+
});
|
|
476
|
+
if (budget.minimumError) thresholds.push({
|
|
477
|
+
limit: calculateBytes(budget.minimumError, budget.baseline, -1),
|
|
478
|
+
type: 'minimum',
|
|
479
|
+
severity: 'error'
|
|
480
|
+
});
|
|
481
|
+
if (budget.warning) thresholds.push({
|
|
482
|
+
limit: calculateBytes(budget.warning, budget.baseline, -1),
|
|
483
|
+
type: 'minimum',
|
|
484
|
+
severity: 'warning'
|
|
485
|
+
}, {
|
|
486
|
+
limit: calculateBytes(budget.warning, budget.baseline, 1),
|
|
487
|
+
type: 'maximum',
|
|
488
|
+
severity: 'warning'
|
|
489
|
+
});
|
|
490
|
+
if (budget.error) thresholds.push({
|
|
491
|
+
limit: calculateBytes(budget.error, budget.baseline, -1),
|
|
492
|
+
type: 'minimum',
|
|
493
|
+
severity: 'error'
|
|
494
|
+
}, {
|
|
495
|
+
limit: calculateBytes(budget.error, budget.baseline, 1),
|
|
496
|
+
type: 'maximum',
|
|
497
|
+
severity: 'error'
|
|
498
|
+
});
|
|
499
|
+
return thresholds;
|
|
500
|
+
};
|
|
501
|
+
const formatSize = (size)=>{
|
|
502
|
+
if (size <= 0) return '0 bytes';
|
|
503
|
+
const abbreviations = [
|
|
504
|
+
'bytes',
|
|
505
|
+
'kB',
|
|
506
|
+
'MB',
|
|
507
|
+
'GB'
|
|
508
|
+
];
|
|
509
|
+
const index = Math.floor(Math.log(size) / Math.log(BYTES_IN_KILOBYTE));
|
|
510
|
+
const roundedSize = size / Math.pow(BYTES_IN_KILOBYTE, index);
|
|
511
|
+
const fractionDigits = 0 === index ? 0 : 2;
|
|
512
|
+
return `${roundedSize.toFixed(fractionDigits)} ${abbreviations[index]}`;
|
|
513
|
+
};
|
|
514
|
+
const checkThresholds = (thresholds, size, label)=>thresholds.flatMap(({ limit, type, severity })=>{
|
|
515
|
+
if ('maximum' === type) return size <= limit ? [] : [
|
|
516
|
+
{
|
|
517
|
+
severity,
|
|
518
|
+
label,
|
|
519
|
+
message: `${label} exceeded maximum budget. Budget ${formatSize(limit)} was not met by ${formatSize(size - limit)} with a total of ${formatSize(size)}.`
|
|
520
|
+
}
|
|
521
|
+
];
|
|
522
|
+
return size >= limit ? [] : [
|
|
523
|
+
{
|
|
524
|
+
severity,
|
|
525
|
+
label,
|
|
526
|
+
message: `${label} failed to meet minimum budget. Budget ${formatSize(limit)} was not met by ${formatSize(limit - size)} with a total of ${formatSize(size)}.`
|
|
527
|
+
}
|
|
528
|
+
];
|
|
529
|
+
});
|
|
530
|
+
const sum = (sizes)=>sizes.reduce((total, { size })=>total + size, 0);
|
|
531
|
+
const calculateSizes = (budget, assets, componentStyles)=>{
|
|
532
|
+
switch(budget.type){
|
|
533
|
+
case 'initial':
|
|
534
|
+
{
|
|
535
|
+
const bundles = assets.filter((asset)=>void 0 !== asset.entryName);
|
|
536
|
+
return bundles.map((asset)=>({
|
|
537
|
+
size: asset.size,
|
|
538
|
+
label: 1 === bundles.length ? 'bundle initial' : `bundle initial (${asset.entryName})`
|
|
539
|
+
}));
|
|
540
|
+
}
|
|
541
|
+
case 'bundle':
|
|
542
|
+
return budget.name ? [
|
|
543
|
+
{
|
|
544
|
+
size: sum(assets.filter((asset)=>asset.entryName === budget.name)),
|
|
545
|
+
label: budget.name
|
|
546
|
+
}
|
|
547
|
+
] : [];
|
|
548
|
+
case 'all':
|
|
549
|
+
return [
|
|
550
|
+
{
|
|
551
|
+
size: sum(assets),
|
|
552
|
+
label: 'total'
|
|
553
|
+
}
|
|
554
|
+
];
|
|
555
|
+
case 'allScript':
|
|
556
|
+
return [
|
|
557
|
+
{
|
|
558
|
+
size: sum(assets),
|
|
559
|
+
label: "total scripts"
|
|
560
|
+
}
|
|
561
|
+
];
|
|
562
|
+
case 'any':
|
|
563
|
+
case 'anyScript':
|
|
564
|
+
return assets.map((asset)=>({
|
|
565
|
+
size: asset.size,
|
|
566
|
+
label: asset.name
|
|
567
|
+
}));
|
|
568
|
+
case 'anyComponentStyle':
|
|
569
|
+
return componentStyles.map((style)=>({
|
|
570
|
+
...style
|
|
571
|
+
}));
|
|
572
|
+
default:
|
|
573
|
+
return [];
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
const checkBudgets = (budgets, output)=>budgets.flatMap((budget)=>calculateSizes(budget, output.assets, output.componentStyles).flatMap(({ size, label })=>checkThresholds(calculateThresholds(budget), size, label)));
|
|
577
|
+
const PLUGIN_NAME = 'lynx:angular:budgets';
|
|
578
|
+
const MAIN_THREAD_ENTRY_SUFFIX = '__main-thread';
|
|
579
|
+
const toBudgetError = (failure)=>{
|
|
580
|
+
const error = new Error(failure.message);
|
|
581
|
+
error.name = 'error' === failure.severity ? 'AngularBudgetError' : 'AngularBudgetWarning';
|
|
582
|
+
error.hideStack = true;
|
|
583
|
+
return error;
|
|
584
|
+
};
|
|
585
|
+
const bundleEntryName = (chunkGroups, entrypoints)=>chunkGroups.map((chunkGroup)=>chunkGroup.name).find((name)=>!!name && entrypoints.has(name) && !name.endsWith(MAIN_THREAD_ENTRY_SUFFIX));
|
|
586
|
+
const collectBudgetAssets = (assets, entryBundles, intermediateDir)=>assets.filter(({ name, info })=>/\.(bundle|js)$/.test(name) && !info.hotModuleReplacement && !(intermediateDir && name.startsWith(`${intermediateDir}/`))).map(({ name, source })=>{
|
|
587
|
+
const entryName = entryBundles.get(name);
|
|
588
|
+
return {
|
|
589
|
+
name,
|
|
590
|
+
size: source.size(),
|
|
591
|
+
...void 0 === entryName ? {} : {
|
|
592
|
+
entryName
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
});
|
|
596
|
+
class AngularBudgetsPlugin {
|
|
597
|
+
#options;
|
|
598
|
+
constructor(options){
|
|
599
|
+
this.#options = options;
|
|
600
|
+
}
|
|
601
|
+
apply(compiler) {
|
|
602
|
+
const { budgets, componentStyleSizes, intermediateDir } = this.#options;
|
|
603
|
+
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation)=>{
|
|
604
|
+
const entryBundles = new Map();
|
|
605
|
+
LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation).beforeEmit.tap(PLUGIN_NAME, (args)=>{
|
|
606
|
+
const entryName = bundleEntryName(args.chunkGroups, compilation.entrypoints);
|
|
607
|
+
if (void 0 !== entryName) entryBundles.set(args.outputName, entryName);
|
|
608
|
+
return args;
|
|
609
|
+
});
|
|
610
|
+
compilation.hooks.processAssets.tap({
|
|
611
|
+
name: PLUGIN_NAME,
|
|
612
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT + 2
|
|
613
|
+
}, ()=>{
|
|
614
|
+
const failures = checkBudgets(budgets, {
|
|
615
|
+
assets: collectBudgetAssets(compilation.getAssets(), entryBundles, intermediateDir),
|
|
616
|
+
componentStyles: [
|
|
617
|
+
...componentStyleSizes.values()
|
|
618
|
+
]
|
|
619
|
+
});
|
|
620
|
+
for (const failure of failures)('error' === failure.severity ? compilation.errors : compilation.warnings).push(toBudgetError(failure));
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
const applyBudgets = (api, { budgets, componentStyleSizes, underAngularCli })=>{
|
|
626
|
+
if (0 === budgets.length) return;
|
|
627
|
+
if (!underAngularCli && 'dev' === api.context.action) return;
|
|
628
|
+
api.modifyBundlerChain((chain, { environment })=>{
|
|
629
|
+
if ('lynx' !== environment.name) return;
|
|
630
|
+
const lynxConfig = api.useExposed(S_LYNX_CONFIG);
|
|
631
|
+
chain.plugin(PLUGIN_NAME).use(AngularBudgetsPlugin, [
|
|
632
|
+
{
|
|
633
|
+
budgets,
|
|
634
|
+
componentStyleSizes,
|
|
635
|
+
intermediateDir: lynxConfig?.resolveIntermediateDir()
|
|
636
|
+
}
|
|
637
|
+
]);
|
|
638
|
+
});
|
|
78
639
|
};
|
|
79
640
|
const injectLynxSchema = (source)=>{
|
|
80
641
|
if (source.includes('CUSTOM_ELEMENTS_SCHEMA') || source.includes('NO_ERRORS_SCHEMA')) return source;
|
|
@@ -115,68 +676,411 @@ const buildLynxSchemaSourceFileCache = (tsconfig, shouldInclude = ()=>true)=>{
|
|
|
115
676
|
fileNames
|
|
116
677
|
};
|
|
117
678
|
};
|
|
679
|
+
const componentStyleSizeKey = (containingFile, stylesheetKey)=>`${containingFile}#${stylesheetKey}`;
|
|
680
|
+
const forgetComponentStyleSizes = (componentStyleSizes, containingFile)=>{
|
|
681
|
+
const prefix = componentStyleSizeKey(containingFile, '');
|
|
682
|
+
for (const key of componentStyleSizes.keys())if (key.startsWith(prefix)) componentStyleSizes.delete(key);
|
|
683
|
+
};
|
|
684
|
+
const createTransformStylesheet = (params)=>{
|
|
685
|
+
const { basePath, componentStyleSizes } = params;
|
|
686
|
+
return async (data, containingFile, stylesheetFile, order, className)=>{
|
|
687
|
+
const key = componentStyleSizeKey(containingFile, stylesheetFile ?? `__inline_${order}`);
|
|
688
|
+
if (componentStyleSizes && (className || !componentStyleSizes.has(key))) componentStyleSizes.set(key, {
|
|
689
|
+
label: node_path.relative(basePath, stylesheetFile ?? containingFile).replace(/\\/g, '/'),
|
|
690
|
+
size: Buffer.byteLength(data)
|
|
691
|
+
});
|
|
692
|
+
return data;
|
|
693
|
+
};
|
|
694
|
+
};
|
|
118
695
|
const generateComponentScopeId = (className, containingFile)=>{
|
|
119
696
|
const hash = createHash('sha256').update(`${className}|${containingFile}`).digest('hex').slice(0, 10);
|
|
120
697
|
return `l${hash}`;
|
|
121
698
|
};
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
699
|
+
const EMULATED = 0;
|
|
700
|
+
const toLynxScopedCss = (css, scopeId)=>css.replaceAll('[_ngcontent-%COMP%]', `._ngcontent-${scopeId}`).replaceAll('[_nghost-%COMP%]', `._nghost-${scopeId}`).replaceAll('%COMP%', scopeId);
|
|
701
|
+
const fillCssVarNamespace = (css)=>css.replaceAll('%NS%', '');
|
|
702
|
+
const propertyName = (property)=>__rspack_external_typescript.isPropertyAssignment(property) && (__rspack_external_typescript.isIdentifier(property.name) || __rspack_external_typescript.isStringLiteral(property.name)) ? property.name.text : null;
|
|
703
|
+
const isDefineComponentCall = (node)=>{
|
|
704
|
+
if (!__rspack_external_typescript.isCallExpression(node)) return false;
|
|
705
|
+
const callee = node.expression;
|
|
706
|
+
const name = __rspack_external_typescript.isPropertyAccessExpression(callee) ? callee.name.text : __rspack_external_typescript.isIdentifier(callee) ? callee.text : null;
|
|
707
|
+
return 'ɵɵdefineComponent' === name;
|
|
708
|
+
};
|
|
709
|
+
const extractComponentStyles = (code, fileName)=>{
|
|
710
|
+
if (!code.includes('ɵɵdefineComponent')) return {
|
|
711
|
+
code,
|
|
712
|
+
components: []
|
|
713
|
+
};
|
|
714
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(fileName, code, __rspack_external_typescript.ScriptTarget.Latest, true, __rspack_external_typescript.ScriptKind.JS);
|
|
715
|
+
const components = [];
|
|
716
|
+
const removals = [];
|
|
717
|
+
const visit = (node)=>{
|
|
718
|
+
if (isDefineComponentCall(node)) {
|
|
719
|
+
const definition = node.arguments[0];
|
|
720
|
+
if (definition && __rspack_external_typescript.isObjectLiteralExpression(definition)) {
|
|
721
|
+
const properties = definition.properties;
|
|
722
|
+
const find = (name)=>properties.find((property)=>propertyName(property) === name);
|
|
723
|
+
const type = find('type')?.initializer;
|
|
724
|
+
const styles = find('styles');
|
|
725
|
+
const encapsulation = find('encapsulation')?.initializer;
|
|
726
|
+
if (type && __rspack_external_typescript.isIdentifier(type) && styles && __rspack_external_typescript.isArrayLiteralExpression(styles.initializer) && styles.initializer.elements.length > 0 && styles.initializer.elements.every(__rspack_external_typescript.isStringLiteralLike)) {
|
|
727
|
+
const emulated = void 0 === encapsulation || __rspack_external_typescript.isNumericLiteral(encapsulation) && Number(encapsulation.text) === EMULATED;
|
|
728
|
+
const scopeId = emulated ? generateComponentScopeId(type.text, fileName) : void 0;
|
|
729
|
+
const stylesheets = styles.initializer.elements.map((element)=>{
|
|
730
|
+
const css = fillCssVarNamespace(element.text);
|
|
731
|
+
return scopeId ? toLynxScopedCss(css, scopeId) : css;
|
|
732
|
+
});
|
|
733
|
+
components.push({
|
|
734
|
+
className: type.text,
|
|
735
|
+
scopeId,
|
|
736
|
+
stylesheets
|
|
737
|
+
});
|
|
738
|
+
const index = properties.indexOf(styles);
|
|
739
|
+
const next = properties[index + 1];
|
|
740
|
+
removals.push({
|
|
741
|
+
start: styles.getStart(sourceFile),
|
|
742
|
+
end: next ? next.getStart(sourceFile) : properties.hasTrailingComma ? properties.end : styles.end
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
}
|
|
136
746
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
747
|
+
__rspack_external_typescript.forEachChild(node, visit);
|
|
748
|
+
};
|
|
749
|
+
visit(sourceFile);
|
|
750
|
+
let result = code;
|
|
751
|
+
for (const { start, end } of removals.sort((a, b)=>b.start - a.start))result = result.slice(0, start) + result.slice(end);
|
|
752
|
+
return {
|
|
753
|
+
code: result,
|
|
754
|
+
components
|
|
755
|
+
};
|
|
756
|
+
};
|
|
757
|
+
const writeModuleStylesheets = (params)=>{
|
|
758
|
+
const { basePath, cacheDir, fileName, components, onWritten } = params;
|
|
759
|
+
if (0 === components.length) return;
|
|
760
|
+
const prefix = node_path.relative(basePath, fileName).replace(/[/\\]/g, '__').replace(/\.[cm]?[jt]s$/, '');
|
|
761
|
+
const imports = [];
|
|
762
|
+
const scopes = [];
|
|
763
|
+
for (const { className, scopeId, stylesheets } of components){
|
|
764
|
+
stylesheets.forEach((css, index)=>{
|
|
765
|
+
const filePath = node_path.join(cacheDir, `${prefix}.${className}.${index}.css`);
|
|
766
|
+
let current;
|
|
146
767
|
try {
|
|
147
|
-
|
|
148
|
-
} catch {}
|
|
149
|
-
node_fs.writeFileSync(filePath, content);
|
|
150
|
-
onStylesheetWritten?.(filePath);
|
|
151
|
-
};
|
|
152
|
-
let scopedPath;
|
|
153
|
-
if (stylesheetFile) {
|
|
154
|
-
const relName = node_path.relative(basePath, stylesheetFile);
|
|
155
|
-
scopedPath = node_path.join(scopedCssCacheDir, `${relName.replace(/[/\\]/g, '__')}.__scoped_${scopeId}.css`);
|
|
156
|
-
} else {
|
|
157
|
-
const relDir = node_path.relative(basePath, node_path.dirname(containingFile));
|
|
158
|
-
scopedPath = node_path.join(scopedCssCacheDir, `${relDir.replace(/[/\\]/g, '__')}__inline_${resolvedClassName}_${order}.__scoped_${scopeId}.css`);
|
|
159
|
-
}
|
|
160
|
-
writeIfChanged(scopedPath, scopedCss);
|
|
161
|
-
if (previousPath) {
|
|
162
|
-
const idx = componentStyles.imports.indexOf(previousPath);
|
|
163
|
-
if (idx >= 0) componentStyles.imports[idx] = scopedPath;
|
|
164
|
-
else componentStyles.imports.push(scopedPath);
|
|
165
|
-
if (previousPath !== scopedPath) try {
|
|
166
|
-
node_fs.unlinkSync(previousPath);
|
|
768
|
+
current = node_fs.readFileSync(filePath, 'utf-8');
|
|
167
769
|
} catch {}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
770
|
+
if (current !== css) {
|
|
771
|
+
node_fs.writeFileSync(filePath, css);
|
|
772
|
+
onWritten?.(filePath);
|
|
773
|
+
}
|
|
774
|
+
imports.push(filePath);
|
|
775
|
+
});
|
|
776
|
+
if (scopeId) scopes.push({
|
|
777
|
+
className,
|
|
778
|
+
scopeId
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
return {
|
|
782
|
+
imports,
|
|
783
|
+
scopes
|
|
171
784
|
};
|
|
172
785
|
};
|
|
173
786
|
const isLynxUnknownElementMessage = (text)=>(text?.includes('is not a known element') || text?.includes("isn't a known property of")) ?? false;
|
|
787
|
+
const filterAngularDiagnostics = (diagnostics)=>({
|
|
788
|
+
errors: (diagnostics.errors ?? []).filter((message)=>!isLynxUnknownElementMessage(message.text)),
|
|
789
|
+
warnings: (diagnostics.warnings ?? []).filter((message)=>!isLynxUnknownElementMessage(message.text))
|
|
790
|
+
});
|
|
791
|
+
const formatLocation = ({ file, line, column })=>{
|
|
792
|
+
if (!file) return;
|
|
793
|
+
if (void 0 === line) return file;
|
|
794
|
+
return `${file}:${line}:${(column ?? 0) + 1}`;
|
|
795
|
+
};
|
|
796
|
+
const formatCodeFrame = ({ line, column, length, lineText })=>{
|
|
797
|
+
if (void 0 === line || void 0 === lineText) return;
|
|
798
|
+
const gutter = `${line} | `;
|
|
799
|
+
const caretIndent = ' '.repeat(gutter.length - 2) + '| ';
|
|
800
|
+
const caret = ' '.repeat(column ?? 0) + '^'.repeat(Math.max(1, length ?? 1));
|
|
801
|
+
return `${gutter}${lineText}\n${caretIndent}${caret}`;
|
|
802
|
+
};
|
|
803
|
+
const toAngularDiagnosticError = (message, severity)=>{
|
|
804
|
+
const sections = [
|
|
805
|
+
message.text ?? 'Unknown Angular compiler diagnostic'
|
|
806
|
+
];
|
|
807
|
+
const codeFrame = message.location && formatCodeFrame(message.location);
|
|
808
|
+
if (codeFrame) sections.push(codeFrame);
|
|
809
|
+
for (const note of message.notes ?? []){
|
|
810
|
+
const noteLocation = note.location && formatLocation(note.location);
|
|
811
|
+
sections.push([
|
|
812
|
+
noteLocation,
|
|
813
|
+
note.text
|
|
814
|
+
].filter((part)=>part).join(': '));
|
|
815
|
+
}
|
|
816
|
+
const error = new Error(sections.join('\n\n'));
|
|
817
|
+
error.name = 'error' === severity ? 'AngularCompilerError' : 'AngularCompilerWarning';
|
|
818
|
+
const file = message.location && formatLocation(message.location);
|
|
819
|
+
if (file) error.file = file;
|
|
820
|
+
error.hideStack = true;
|
|
821
|
+
return error;
|
|
822
|
+
};
|
|
823
|
+
const PURE_CONSTRUCTORS = new Set([
|
|
824
|
+
'Map',
|
|
825
|
+
'Set',
|
|
826
|
+
'WeakMap',
|
|
827
|
+
'WeakSet'
|
|
828
|
+
]);
|
|
829
|
+
/**
|
|
830
|
+
* Wraps each top-level class with private or static members in a pure IIFE,
|
|
831
|
+
* so a bundler can drop the classes nothing uses.
|
|
832
|
+
*
|
|
833
|
+
* The background layer compiles to ES2015 (layers.ts), so SWC lowers private
|
|
834
|
+
* and static class fields. A class declaration keeps its own statement, but the
|
|
835
|
+
* class expressions that bundled libraries are written in (`var X = class
|
|
836
|
+
* {…}`) become a sequence that assigns each private field's `WeakMap` to an
|
|
837
|
+
* outer variable: `var X = (_a = new WeakMap(), class {…})`. The assignment
|
|
838
|
+
* counts as a side effect, so rspack keeps every such class, and every import
|
|
839
|
+
* it uses, even when nothing uses the class. The runtime's own classes are
|
|
840
|
+
* like that (it uses `#private` fields throughout), which kept Angular's
|
|
841
|
+
* renderer and change detection in the background bundle.
|
|
842
|
+
*
|
|
843
|
+
* Angular's build already wraps a class whose static members are Angular's
|
|
844
|
+
* own (`ɵcmp`, `ɵfac` and so on) in `/*#__PURE__*\/ (() => {…})()`; this does
|
|
845
|
+
* the same for the rest. Inside the IIFE, the lowering's assignments are local
|
|
846
|
+
* and the call is marked pure. A class whose static members could have side
|
|
847
|
+
* effects of their own (anything but literals, functions and new collections)
|
|
848
|
+
* is left alone.
|
|
849
|
+
*
|
|
850
|
+
* @param code - The module's code, before SWC lowers it (and, for a `.ts`
|
|
851
|
+
* file, strips its types).
|
|
852
|
+
* @param filename - The module's path, for the parser.
|
|
853
|
+
* @returns The transformed code, or `code` itself when nothing applies.
|
|
854
|
+
*/ const wrapPureClasses = (code, filename)=>{
|
|
855
|
+
if (!code.includes('class')) return code;
|
|
856
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(filename, code, __rspack_external_typescript.ScriptTarget.Latest, true);
|
|
857
|
+
const edits = [];
|
|
858
|
+
const wrap = (classNode)=>{
|
|
859
|
+
edits.push({
|
|
860
|
+
start: classNode.getStart(sourceFile),
|
|
861
|
+
end: classNode.getStart(sourceFile),
|
|
862
|
+
text: '/*#__PURE__*/ (() => '
|
|
863
|
+
}, {
|
|
864
|
+
start: classNode.end,
|
|
865
|
+
end: classNode.end,
|
|
866
|
+
text: ')()'
|
|
867
|
+
});
|
|
868
|
+
};
|
|
869
|
+
for (const statement of sourceFile.statements){
|
|
870
|
+
if (__rspack_external_typescript.isVariableStatement(statement)) {
|
|
871
|
+
const [declaration, ...rest] = statement.declarationList.declarations;
|
|
872
|
+
const value = declaration?.initializer;
|
|
873
|
+
if (0 === rest.length && value && __rspack_external_typescript.isClassExpression(value) && isLoweredPureClass(value)) wrap(value);
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
if (__rspack_external_typescript.isClassDeclaration(statement) && statement.name && isLoweredPureClass(statement)) {
|
|
877
|
+
const modifiers = __rspack_external_typescript.getModifiers(statement) ?? [];
|
|
878
|
+
const isExport = modifiers.some((modifier)=>modifier.kind === __rspack_external_typescript.SyntaxKind.ExportKeyword);
|
|
879
|
+
const isDefault = modifiers.some((modifier)=>modifier.kind === __rspack_external_typescript.SyntaxKind.DefaultKeyword);
|
|
880
|
+
const name = statement.name.text;
|
|
881
|
+
const start = statement.getStart(sourceFile);
|
|
882
|
+
const classStart = statement.getChildren(sourceFile).find((child)=>child.kind === __rspack_external_typescript.SyntaxKind.ClassKeyword).getStart(sourceFile);
|
|
883
|
+
// `class X {}` becomes `let X = /*#__PURE__*/ (() => class X {})();`.
|
|
884
|
+
edits.push({
|
|
885
|
+
start,
|
|
886
|
+
end: classStart,
|
|
887
|
+
text: `${isExport && !isDefault ? 'export ' : ''}let ${name} = /*#__PURE__*/ (() => `
|
|
888
|
+
}, {
|
|
889
|
+
start: statement.end,
|
|
890
|
+
end: statement.end,
|
|
891
|
+
text: `)();${isDefault ? `\nexport { ${name} as default };` : ''}`
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
if (0 === edits.length) return code;
|
|
896
|
+
edits.sort((a, b)=>b.start - a.start);
|
|
897
|
+
let result = code;
|
|
898
|
+
for (const { start, end, text } of edits)result = result.slice(0, start) + text + result.slice(end);
|
|
899
|
+
return result;
|
|
900
|
+
};
|
|
901
|
+
const isLoweredPureClass = (node)=>{
|
|
902
|
+
if (__rspack_external_typescript.getDecorators(node)?.length) return false;
|
|
903
|
+
const heritage = node.heritageClauses?.find((clause)=>clause.token === __rspack_external_typescript.SyntaxKind.ExtendsKeyword);
|
|
904
|
+
const base = heritage?.types[0]?.expression;
|
|
905
|
+
if (base && !isPureReference(base)) return false;
|
|
906
|
+
let lowered = false;
|
|
907
|
+
for (const member of node.members){
|
|
908
|
+
if (__rspack_external_typescript.isClassStaticBlockDeclaration(member)) return false;
|
|
909
|
+
const isStatic = __rspack_external_typescript.getModifiers(member)?.some((modifier)=>modifier.kind === __rspack_external_typescript.SyntaxKind.StaticKeyword);
|
|
910
|
+
const isPrivate = member.name && __rspack_external_typescript.isPrivateIdentifier(member.name);
|
|
911
|
+
if (member.name && __rspack_external_typescript.isComputedPropertyName(member.name)) return false;
|
|
912
|
+
if (isStatic || isPrivate) lowered = true;
|
|
913
|
+
if (isStatic && __rspack_external_typescript.isPropertyDeclaration(member) && member.initializer && !isPure(member.initializer)) return false;
|
|
914
|
+
}
|
|
915
|
+
return lowered;
|
|
916
|
+
};
|
|
917
|
+
const isPureReference = (node)=>__rspack_external_typescript.isIdentifier(node) || __rspack_external_typescript.isPropertyAccessExpression(node) && isPureReference(node.expression);
|
|
918
|
+
const isPure = (node)=>{
|
|
919
|
+
if (__rspack_external_typescript.isLiteralExpression(node) || __rspack_external_typescript.isNoSubstitutionTemplateLiteral(node) || __rspack_external_typescript.isIdentifier(node) || __rspack_external_typescript.isArrowFunction(node) || __rspack_external_typescript.isFunctionExpression(node) || node.kind === __rspack_external_typescript.SyntaxKind.TrueKeyword || node.kind === __rspack_external_typescript.SyntaxKind.FalseKeyword || node.kind === __rspack_external_typescript.SyntaxKind.NullKeyword) return true;
|
|
920
|
+
if (__rspack_external_typescript.isVoidExpression(node)) return isPure(node.expression);
|
|
921
|
+
if (__rspack_external_typescript.isParenthesizedExpression(node)) return isPure(node.expression);
|
|
922
|
+
if (__rspack_external_typescript.isPrefixUnaryExpression(node)) return isPure(node.operand);
|
|
923
|
+
if (__rspack_external_typescript.isArrayLiteralExpression(node)) return node.elements.every((element)=>!__rspack_external_typescript.isSpreadElement(element) && isPure(element));
|
|
924
|
+
if (__rspack_external_typescript.isObjectLiteralExpression(node)) return node.properties.every((property)=>__rspack_external_typescript.isPropertyAssignment(property) && !__rspack_external_typescript.isComputedPropertyName(property.name) && isPure(property.initializer));
|
|
925
|
+
return __rspack_external_typescript.isNewExpression(node) && __rspack_external_typescript.isIdentifier(node.expression) && PURE_CONSTRUCTORS.has(node.expression.text) && (node.arguments ?? []).every(isPure);
|
|
926
|
+
};
|
|
174
927
|
const seedCompilationSourceFiles = (compilation, sourceFileCache)=>{
|
|
175
928
|
const { sourceFiles } = compilation;
|
|
176
929
|
if (!(sourceFiles instanceof Map)) return false;
|
|
177
930
|
for (const [fileName, sourceFile] of sourceFileCache)sourceFiles.set(fileName, sourceFile);
|
|
178
931
|
return true;
|
|
179
932
|
};
|
|
933
|
+
const IN_PLACE_FIELDS = new Set([
|
|
934
|
+
'template',
|
|
935
|
+
'templateUrl',
|
|
936
|
+
'styles',
|
|
937
|
+
'styleUrl',
|
|
938
|
+
'styleUrls'
|
|
939
|
+
]);
|
|
940
|
+
const hotUpdatesEnabled = (environment)=>'web' !== environment.name && 'development' === environment.config.mode && environment.config.dev?.hmr !== false;
|
|
941
|
+
const hot_updates_hash = (text)=>createHash('sha1').update(text).digest('hex').slice(0, 16);
|
|
942
|
+
const isComponentDecorator = (decorator)=>{
|
|
943
|
+
const call = decorator.expression;
|
|
944
|
+
if (!__rspack_external_typescript.isCallExpression(call)) return false;
|
|
945
|
+
const callee = call.expression;
|
|
946
|
+
const name = __rspack_external_typescript.isPropertyAccessExpression(callee) ? callee.name.text : __rspack_external_typescript.isIdentifier(callee) ? callee.text : void 0;
|
|
947
|
+
return 'Component' === name;
|
|
948
|
+
};
|
|
949
|
+
const hotUpdateSignature = (source, fileName)=>{
|
|
950
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(fileName, source, __rspack_external_typescript.ScriptTarget.Latest, true, __rspack_external_typescript.ScriptKind.TS);
|
|
951
|
+
const removals = [];
|
|
952
|
+
const visit = (node)=>{
|
|
953
|
+
if (__rspack_external_typescript.isDecorator(node) && isComponentDecorator(node)) {
|
|
954
|
+
const metadata = node.expression.arguments[0];
|
|
955
|
+
if (metadata && __rspack_external_typescript.isObjectLiteralExpression(metadata)) {
|
|
956
|
+
for (const property of metadata.properties)if (__rspack_external_typescript.isPropertyAssignment(property) && (__rspack_external_typescript.isIdentifier(property.name) || __rspack_external_typescript.isStringLiteral(property.name)) && IN_PLACE_FIELDS.has(property.name.text)) removals.push({
|
|
957
|
+
start: property.initializer.getStart(sourceFile),
|
|
958
|
+
end: property.initializer.end
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
__rspack_external_typescript.forEachChild(node, visit);
|
|
963
|
+
};
|
|
964
|
+
visit(sourceFile);
|
|
965
|
+
let rest = source;
|
|
966
|
+
for (const { start, end } of removals.reverse())rest = rest.slice(0, start) + rest.slice(end);
|
|
967
|
+
return hot_updates_hash(rest);
|
|
968
|
+
};
|
|
969
|
+
const componentClassNames = (code, fileName)=>{
|
|
970
|
+
if (!code.includes('ɵɵdefineComponent')) return [];
|
|
971
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(fileName, code, __rspack_external_typescript.ScriptTarget.Latest, true, __rspack_external_typescript.ScriptKind.JS);
|
|
972
|
+
const topLevelClasses = new Set(sourceFile.statements.filter(__rspack_external_typescript.isClassDeclaration).flatMap((statement)=>statement.name ? [
|
|
973
|
+
statement.name.text
|
|
974
|
+
] : []));
|
|
975
|
+
const names = [];
|
|
976
|
+
const visit = (node)=>{
|
|
977
|
+
if (__rspack_external_typescript.isCallExpression(node) && (__rspack_external_typescript.isPropertyAccessExpression(node.expression) ? node.expression.name.text : __rspack_external_typescript.isIdentifier(node.expression) ? node.expression.text : void 0) === 'ɵɵdefineComponent') {
|
|
978
|
+
const definition = node.arguments[0];
|
|
979
|
+
const type = definition && __rspack_external_typescript.isObjectLiteralExpression(definition) ? definition.properties.find((property)=>__rspack_external_typescript.isPropertyAssignment(property) && __rspack_external_typescript.isIdentifier(property.name) && 'type' === property.name.text)?.initializer : void 0;
|
|
980
|
+
if (type && __rspack_external_typescript.isIdentifier(type) && topLevelClasses.has(type.text) && !names.includes(type.text)) names.push(type.text);
|
|
981
|
+
}
|
|
982
|
+
__rspack_external_typescript.forEachChild(node, visit);
|
|
983
|
+
};
|
|
984
|
+
visit(sourceFile);
|
|
985
|
+
return names;
|
|
986
|
+
};
|
|
987
|
+
const ACCEPT = 'ɵɵangularLynxHmrAccept';
|
|
988
|
+
const addHotAccept = (code, { components, signature, compiled })=>{
|
|
989
|
+
const list = `[${components.join(', ')}]`;
|
|
990
|
+
return `${code}
|
|
991
|
+
import { ɵhmrAccept as ${ACCEPT} } from '@blotch/angular-lynx';
|
|
992
|
+
if (import.meta.webpackHot) {
|
|
993
|
+
${list} = ${ACCEPT}(import.meta.webpackHot, ${list}, ${JSON.stringify(signature)}, ${JSON.stringify(hot_updates_hash(compiled))});
|
|
994
|
+
}
|
|
995
|
+
`;
|
|
996
|
+
};
|
|
997
|
+
const addEntryHotAccept = (code)=>`${code}
|
|
998
|
+
if (import.meta.webpackHot) {
|
|
999
|
+
import.meta.webpackHot.accept();
|
|
1000
|
+
}
|
|
1001
|
+
`;
|
|
1002
|
+
const RUNTIME_MODULE = '@blotch/angular-lynx';
|
|
1003
|
+
const TAGGED_CALLS = new Set([
|
|
1004
|
+
'backgroundFn',
|
|
1005
|
+
'createMainThreadRef'
|
|
1006
|
+
]);
|
|
1007
|
+
const TAGGED_CLASSES = new Set([
|
|
1008
|
+
'MainThreadRef'
|
|
1009
|
+
]);
|
|
1010
|
+
const transformCrossThread = (code, filename, options)=>{
|
|
1011
|
+
const calls = findModuleLevelCalls(code, filename);
|
|
1012
|
+
if (0 === calls.length) return code;
|
|
1013
|
+
const fileKey = keyForFile(filename, options.root);
|
|
1014
|
+
const edits = [];
|
|
1015
|
+
calls.forEach((node, index)=>{
|
|
1016
|
+
const edit = tagEdit(node, JSON.stringify(`${fileKey}:${index}`), code);
|
|
1017
|
+
if (edit) edits.push(edit);
|
|
1018
|
+
});
|
|
1019
|
+
edits.sort((a, b)=>b.start - a.start);
|
|
1020
|
+
let result = code;
|
|
1021
|
+
for (const { start, end, text } of edits)result = result.slice(0, start) + text + result.slice(end);
|
|
1022
|
+
return result;
|
|
1023
|
+
};
|
|
1024
|
+
const definesCrossThreadValues = (code, filename)=>findModuleLevelCalls(code, filename).length > 0;
|
|
1025
|
+
const findModuleLevelCalls = (code, filename)=>{
|
|
1026
|
+
if (!code.includes(RUNTIME_MODULE) || !code.includes('backgroundFn') && !code.includes('MainThreadRef')) return [];
|
|
1027
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(filename, code, __rspack_external_typescript.ScriptTarget.Latest, true);
|
|
1028
|
+
const runtime = runtimeBindings(sourceFile);
|
|
1029
|
+
const calls = [];
|
|
1030
|
+
const visit = (node, topLevel)=>{
|
|
1031
|
+
if (topLevel && (__rspack_external_typescript.isCallExpression(node) && isRuntimeReference(node.expression, runtime, TAGGED_CALLS) || __rspack_external_typescript.isNewExpression(node) && isRuntimeReference(node.expression, runtime, TAGGED_CLASSES))) calls.push(node);
|
|
1032
|
+
const childTopLevel = topLevel && !__rspack_external_typescript.isFunctionLike(node) && !__rspack_external_typescript.isClassLike(node);
|
|
1033
|
+
__rspack_external_typescript.forEachChild(node, (child)=>visit(child, childTopLevel));
|
|
1034
|
+
};
|
|
1035
|
+
visit(sourceFile, true);
|
|
1036
|
+
return calls;
|
|
1037
|
+
};
|
|
1038
|
+
const tagEdit = (node, id, code)=>{
|
|
1039
|
+
const args = node.arguments ?? __rspack_external_typescript.factory.createNodeArray();
|
|
1040
|
+
if (args.length > 1 || args.some(__rspack_external_typescript.isSpreadElement)) return;
|
|
1041
|
+
if (1 === args.length) return {
|
|
1042
|
+
start: args[0].end,
|
|
1043
|
+
end: args[0].end,
|
|
1044
|
+
text: `, ${id}`
|
|
1045
|
+
};
|
|
1046
|
+
const close = node.getEnd() - 1;
|
|
1047
|
+
if (')' !== code[close]) return;
|
|
1048
|
+
return {
|
|
1049
|
+
start: close,
|
|
1050
|
+
end: close,
|
|
1051
|
+
text: `undefined, ${id}`
|
|
1052
|
+
};
|
|
1053
|
+
};
|
|
1054
|
+
const runtimeBindings = (sourceFile)=>{
|
|
1055
|
+
const named = new Map();
|
|
1056
|
+
const namespaces = new Set();
|
|
1057
|
+
for (const statement of sourceFile.statements){
|
|
1058
|
+
if (!__rspack_external_typescript.isImportDeclaration(statement) || !__rspack_external_typescript.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== RUNTIME_MODULE) continue;
|
|
1059
|
+
const bindings = statement.importClause?.namedBindings;
|
|
1060
|
+
if (bindings) {
|
|
1061
|
+
if (__rspack_external_typescript.isNamespaceImport(bindings)) {
|
|
1062
|
+
namespaces.add(bindings.name.text);
|
|
1063
|
+
continue;
|
|
1064
|
+
}
|
|
1065
|
+
for (const element of bindings.elements)named.set(element.name.text, (element.propertyName ?? element.name).text);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return {
|
|
1069
|
+
named,
|
|
1070
|
+
namespaces
|
|
1071
|
+
};
|
|
1072
|
+
};
|
|
1073
|
+
const isRuntimeReference = (expression, runtime, exports)=>{
|
|
1074
|
+
if (__rspack_external_typescript.isIdentifier(expression)) {
|
|
1075
|
+
const imported = runtime.named.get(expression.text);
|
|
1076
|
+
return void 0 !== imported && exports.has(imported);
|
|
1077
|
+
}
|
|
1078
|
+
return __rspack_external_typescript.isPropertyAccessExpression(expression) && __rspack_external_typescript.isIdentifier(expression.expression) && runtime.namespaces.has(expression.expression.text) && exports.has(expression.name.text);
|
|
1079
|
+
};
|
|
1080
|
+
const keyForFile = (filename, root)=>{
|
|
1081
|
+
const relative = node_path.relative(root, filename).split(node_path.sep).join('/');
|
|
1082
|
+
return createHash('sha1').update(relative).digest('hex').slice(0, 10);
|
|
1083
|
+
};
|
|
180
1084
|
const MAIN_THREAD_DIRECTIVE = 'main thread';
|
|
181
1085
|
const MAIN_THREAD_DIRECTIVE_ALT = 'main-thread';
|
|
182
1086
|
const transformWorklets = (code, filename)=>{
|
|
@@ -223,10 +1127,10 @@ const isAlreadyWrapped = (node)=>{
|
|
|
223
1127
|
return false;
|
|
224
1128
|
};
|
|
225
1129
|
const buildTransformedCode = (params)=>{
|
|
226
|
-
const { resourcePath,
|
|
1130
|
+
const { resourcePath, stylesheets, root, hot } = params;
|
|
227
1131
|
let code = params.code;
|
|
228
|
-
if (
|
|
229
|
-
const { imports } =
|
|
1132
|
+
if (stylesheets) {
|
|
1133
|
+
const { imports } = stylesheets;
|
|
230
1134
|
let importsString = '';
|
|
231
1135
|
for(let i = 0; i < imports.length; ++i){
|
|
232
1136
|
let relativeImport = node_path.relative(node_path.dirname(resourcePath), imports[i]);
|
|
@@ -235,8 +1139,19 @@ const buildTransformedCode = (params)=>{
|
|
|
235
1139
|
}
|
|
236
1140
|
code = importsString + code;
|
|
237
1141
|
}
|
|
238
|
-
|
|
239
|
-
|
|
1142
|
+
for (const { className, scopeId } of stylesheets?.scopes ?? [])code += `\n;${className}.ɵcmp.id = '${scopeId}';\n`;
|
|
1143
|
+
const transformed = transformCrossThread(transformWorklets(code, resourcePath), resourcePath, {
|
|
1144
|
+
root
|
|
1145
|
+
});
|
|
1146
|
+
if (!hot) return transformed;
|
|
1147
|
+
if (hot.entry) return addEntryHotAccept(transformed);
|
|
1148
|
+
const components = componentClassNames(params.code, resourcePath);
|
|
1149
|
+
if (0 === components.length) return transformed;
|
|
1150
|
+
return addHotAccept(transformed, {
|
|
1151
|
+
components,
|
|
1152
|
+
signature: hotUpdateSignature(hot.source(), resourcePath),
|
|
1153
|
+
compiled: params.code
|
|
1154
|
+
});
|
|
240
1155
|
};
|
|
241
1156
|
const applyAngularConfig = (api, buildOptions)=>{
|
|
242
1157
|
const __dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -253,9 +1168,9 @@ const applyAngularConfig = (api, buildOptions)=>{
|
|
|
253
1168
|
];
|
|
254
1169
|
else config.source.preEntry ??= [];
|
|
255
1170
|
config.source.preEntry.push(node_path.resolve(__dirname, './polyfills'));
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
1171
|
+
const polyfills = buildOptions.polyfills ?? [];
|
|
1172
|
+
if (buildOptions.i18n.hasDefinedSourceLocale && !polyfills.some((polyfill)=>polyfill.startsWith('@angular/localize'))) config.source.preEntry.push('@angular/localize/init');
|
|
1173
|
+
config.source.preEntry.push(...polyfills);
|
|
259
1174
|
config.source.preEntry.push(...buildOptions.styles);
|
|
260
1175
|
config.source.tsconfigPath = buildOptions.tsconfig;
|
|
261
1176
|
config.source.define ??= {};
|
|
@@ -264,12 +1179,85 @@ const applyAngularConfig = (api, buildOptions)=>{
|
|
|
264
1179
|
if (isProd) config.source.define.ngDevMode = false;
|
|
265
1180
|
});
|
|
266
1181
|
};
|
|
1182
|
+
const build_internals_require = createRequire(import.meta.url);
|
|
1183
|
+
const angularBuildRoot = node_path.dirname(build_internals_require.resolve('@angular/build/package.json'));
|
|
1184
|
+
const loadAngularBuildInternal = (subpath)=>build_internals_require(node_path.join(angularBuildRoot, subpath));
|
|
1185
|
+
const { createAngularCompilation: createAngularCompilation, DiagnosticModes: DiagnosticModes } = loadAngularBuildInternal('src/tools/angular/compilation');
|
|
1186
|
+
const { JavaScriptTransformer: JavaScriptTransformer } = loadAngularBuildInternal("src/tools/javascript-transformer");
|
|
1187
|
+
const { ComponentStylesheetBundler: ComponentStylesheetBundler } = loadAngularBuildInternal('src/tools/esbuild/angular/component-stylesheets');
|
|
267
1188
|
const isPresent = (variable)=>'string' == typeof variable && '' !== variable;
|
|
268
1189
|
const isDisabled = (variable)=>'0' === variable || 'false' === variable.toLowerCase();
|
|
269
1190
|
const maxWorkersVariable = process.env.NG_BUILD_MAX_WORKERS;
|
|
270
1191
|
const maxWorkers = isPresent(maxWorkersVariable) ? +maxWorkersVariable : Math.min(4, Math.max(availableParallelism() - 1, 1));
|
|
271
1192
|
const typeCheckingVariable = process.env.NG_BUILD_TYPE_CHECK;
|
|
272
1193
|
const useTypeChecking = !isPresent(typeCheckingVariable) || !isDisabled(typeCheckingVariable);
|
|
1194
|
+
/**
|
|
1195
|
+
* @license
|
|
1196
|
+
* Copyright Google LLC All Rights Reserved.
|
|
1197
|
+
*
|
|
1198
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
1199
|
+
* found in the LICENSE file at https://angular.dev/license
|
|
1200
|
+
*/ const findUp = (names, from)=>{
|
|
1201
|
+
const namesList = Array.isArray(names) ? names : [
|
|
1202
|
+
names
|
|
1203
|
+
];
|
|
1204
|
+
const root = __rspack_external_node_path_c5b9b54f.parse(from).root;
|
|
1205
|
+
let currentDir = from;
|
|
1206
|
+
while(currentDir && currentDir !== root){
|
|
1207
|
+
for (const name of namesList){
|
|
1208
|
+
const p = __rspack_external_node_path_c5b9b54f.join(currentDir, name);
|
|
1209
|
+
if (existsSync(p)) return p;
|
|
1210
|
+
}
|
|
1211
|
+
currentDir = __rspack_external_node_path_c5b9b54f.dirname(currentDir);
|
|
1212
|
+
}
|
|
1213
|
+
return null;
|
|
1214
|
+
};
|
|
1215
|
+
const configNames = [
|
|
1216
|
+
'angular.json',
|
|
1217
|
+
'.angular.json'
|
|
1218
|
+
];
|
|
1219
|
+
const getAngularWorkspace = async (from = process.cwd())=>{
|
|
1220
|
+
const host = workspaces.createWorkspaceHost(new NodeJsSyncHost());
|
|
1221
|
+
const workspaceFile = findUp(configNames, from);
|
|
1222
|
+
if (!workspaceFile) throw new Error("couldn't find workspace file");
|
|
1223
|
+
const { workspace } = await workspaces.readWorkspace(workspaceFile, host);
|
|
1224
|
+
return {
|
|
1225
|
+
basePath: node_path.dirname(workspaceFile),
|
|
1226
|
+
workspace
|
|
1227
|
+
};
|
|
1228
|
+
};
|
|
1229
|
+
const findProjectByPath = (workspace, location, basePath)=>{
|
|
1230
|
+
const isInside = (base, potential)=>{
|
|
1231
|
+
const absoluteBase = node_path.resolve(basePath, base);
|
|
1232
|
+
const absolutePotential = node_path.resolve(basePath, potential);
|
|
1233
|
+
const relativePotential = node_path.relative(absoluteBase, absolutePotential);
|
|
1234
|
+
if (!relativePotential.startsWith('..') && !node_path.isAbsolute(relativePotential)) return true;
|
|
1235
|
+
return false;
|
|
1236
|
+
};
|
|
1237
|
+
const projects = Array.from(workspace.projects).map(([name, project])=>[
|
|
1238
|
+
project.root,
|
|
1239
|
+
name
|
|
1240
|
+
]).filter((tuple)=>isInside(tuple[0], location)).sort((a, b)=>b[0].length - a[0].length);
|
|
1241
|
+
if (0 === projects.length) return null;
|
|
1242
|
+
if (projects.length > 1) {
|
|
1243
|
+
const found = new Set();
|
|
1244
|
+
const sameRoots = projects.filter((v)=>{
|
|
1245
|
+
if (!found.has(v[0])) {
|
|
1246
|
+
found.add(v[0]);
|
|
1247
|
+
return false;
|
|
1248
|
+
}
|
|
1249
|
+
return true;
|
|
1250
|
+
});
|
|
1251
|
+
if (sameRoots.length > 0) return null;
|
|
1252
|
+
}
|
|
1253
|
+
return projects[0][1];
|
|
1254
|
+
};
|
|
1255
|
+
const getProjectByCwd = (workspace, basePath)=>{
|
|
1256
|
+
if (1 === workspace.projects.size) return Array.from(workspace.projects.keys())[0];
|
|
1257
|
+
const project = findProjectByPath(workspace, process.cwd(), basePath);
|
|
1258
|
+
if (project) return project;
|
|
1259
|
+
return null;
|
|
1260
|
+
};
|
|
273
1261
|
/**
|
|
274
1262
|
* @license
|
|
275
1263
|
* Copyright Google LLC All Rights Reserved.
|
|
@@ -291,7 +1279,7 @@ const normalizeCacheOptions = (projectMetadata, workspaceRoot)=>{
|
|
|
291
1279
|
cacheEnabled = !isCI;
|
|
292
1280
|
break;
|
|
293
1281
|
}
|
|
294
|
-
const cacheBasePath =
|
|
1282
|
+
const cacheBasePath = external_node_path_resolve(workspaceRoot, path);
|
|
295
1283
|
return {
|
|
296
1284
|
enabled: cacheEnabled,
|
|
297
1285
|
basePath: cacheBasePath,
|
|
@@ -338,29 +1326,37 @@ const normalizeOptimization = (optimization = true)=>{
|
|
|
338
1326
|
};
|
|
339
1327
|
};
|
|
340
1328
|
const readTarget = (project, target = 'build')=>project.targets.get(target);
|
|
341
|
-
const
|
|
342
|
-
|
|
1329
|
+
const resolveIndexPath = (index, project, workspaceRoot)=>{
|
|
1330
|
+
if ('boolean' == typeof index) return;
|
|
1331
|
+
if ('string' == typeof index) return node_path.join(workspaceRoot, index);
|
|
1332
|
+
if (index && 'object' == typeof index) return node_path.join(workspaceRoot, index.input);
|
|
1333
|
+
const sourceRoot = project.sourceRoot ?? node_path.join(project.root ?? '', 'src');
|
|
1334
|
+
return node_path.join(workspaceRoot, sourceRoot, 'index.html');
|
|
1335
|
+
};
|
|
1336
|
+
const resolveOutputPath = (outputPath, workspaceRoot)=>{
|
|
1337
|
+
if ('string' == typeof outputPath) return node_path.join(workspaceRoot, outputPath);
|
|
1338
|
+
if (outputPath && 'object' == typeof outputPath) return node_path.join(workspaceRoot, outputPath.base);
|
|
1339
|
+
};
|
|
1340
|
+
const readBuildTargetOptions = (project, configurationName)=>{
|
|
343
1341
|
const target = readTarget(project);
|
|
344
1342
|
if (!target) throw new Error("couldn't find target");
|
|
345
1343
|
const resolvedConfigurationName = configurationName ?? target.defaultConfiguration;
|
|
346
|
-
const buildOptions = target
|
|
347
|
-
if (!buildOptions) throw new Error(`No build options found for the "${configurationName ?? 'build'}" target in angular.json. Make sure the target has an "options" section with at least "browser"
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
node_assert(!!buildOptions, 'build options is undefined');
|
|
1344
|
+
const buildOptions = target.options;
|
|
1345
|
+
if (!buildOptions) throw new Error(`No build options found for the "${configurationName ?? 'build'}" target in angular.json. Make sure the target has an "options" section with at least "browser" and "tsConfig" defined.`);
|
|
1346
|
+
return {
|
|
1347
|
+
...buildOptions,
|
|
1348
|
+
...resolvedConfigurationName ? target.configurations?.[resolvedConfigurationName] : void 0
|
|
1349
|
+
};
|
|
1350
|
+
};
|
|
1351
|
+
const readBuildOptions = async (project, basePath, configurationName)=>normalizeBuildOptions(readBuildTargetOptions(project, configurationName), project, basePath);
|
|
1352
|
+
const normalizeBuildOptions = async (buildOptions, project, basePath)=>{
|
|
1353
|
+
const workspaceRoot = basePath;
|
|
358
1354
|
const aot = buildOptions.aot ?? true;
|
|
359
1355
|
const tsconfig = node_path.join(workspaceRoot, buildOptions.tsConfig);
|
|
360
1356
|
const optimizationOptions = normalizeOptimization(buildOptions.optimization);
|
|
361
1357
|
const sourcemapOptions = normalizeSourceMaps(buildOptions.sourceMap ?? false);
|
|
362
1358
|
const browser = node_path.join(workspaceRoot, buildOptions.browser);
|
|
363
|
-
const index =
|
|
1359
|
+
const index = resolveIndexPath(buildOptions.index, project, workspaceRoot);
|
|
364
1360
|
let polyfills = buildOptions.polyfills;
|
|
365
1361
|
polyfills = void 0 === polyfills || Array.isArray(polyfills) ? polyfills : [
|
|
366
1362
|
polyfills
|
|
@@ -387,7 +1383,7 @@ const readBuildOptions = async (project, basePath, configurationName)=>{
|
|
|
387
1383
|
const cacheOptions = normalizeCacheOptions(buildOptions.projectMetadata, workspaceRoot);
|
|
388
1384
|
const inlineStyleLanguage = buildOptions.inlineStyleLanguage;
|
|
389
1385
|
const styles = (buildOptions.styles ?? []).map((stylePath)=>node_path.join(workspaceRoot, stylePath));
|
|
390
|
-
const outputPath =
|
|
1386
|
+
const outputPath = resolveOutputPath(buildOptions.outputPath, workspaceRoot);
|
|
391
1387
|
const i18n = normalizeI18nOptions(project.extensions['i18n']);
|
|
392
1388
|
const i18nMissingTranslation = buildOptions.i18nMissingTranslation ?? 'warning';
|
|
393
1389
|
const normalizedOptions = {
|
|
@@ -408,7 +1404,8 @@ const readBuildOptions = async (project, basePath, configurationName)=>{
|
|
|
408
1404
|
outputHashing,
|
|
409
1405
|
styles,
|
|
410
1406
|
i18n,
|
|
411
|
-
i18nMissingTranslation
|
|
1407
|
+
i18nMissingTranslation,
|
|
1408
|
+
budgets: buildOptions.budgets ?? []
|
|
412
1409
|
};
|
|
413
1410
|
return normalizedOptions;
|
|
414
1411
|
};
|
|
@@ -432,73 +1429,20 @@ const normalizeI18nOptions = (raw)=>{
|
|
|
432
1429
|
hasDefinedSourceLocale
|
|
433
1430
|
};
|
|
434
1431
|
};
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const root = __rspack_external_node_path_c5b9b54f.parse(from).root;
|
|
446
|
-
let currentDir = from;
|
|
447
|
-
while(currentDir && currentDir !== root){
|
|
448
|
-
for (const name of namesList){
|
|
449
|
-
const p = __rspack_external_node_path_c5b9b54f.join(currentDir, name);
|
|
450
|
-
if (existsSync(p)) return p;
|
|
451
|
-
}
|
|
452
|
-
currentDir = __rspack_external_node_path_c5b9b54f.dirname(currentDir);
|
|
453
|
-
}
|
|
454
|
-
return null;
|
|
455
|
-
};
|
|
456
|
-
const configNames = [
|
|
457
|
-
'angular.json',
|
|
458
|
-
'.angular.json'
|
|
459
|
-
];
|
|
460
|
-
const findWorkspaceFile = ()=>findUp(configNames, process.cwd());
|
|
461
|
-
const getAngularWorkspace = async ()=>{
|
|
462
|
-
const host = workspaces.createWorkspaceHost(new NodeJsSyncHost());
|
|
463
|
-
const workspaceFile = findWorkspaceFile();
|
|
464
|
-
if (!workspaceFile) throw new Error("couldn't find workspace file");
|
|
465
|
-
const { workspace } = await workspaces.readWorkspace(workspaceFile, host);
|
|
1432
|
+
const resolvePrimaryBuild = async ({ workspace, basePath, pages, cli })=>{
|
|
1433
|
+
let projectName;
|
|
1434
|
+
if (pages) {
|
|
1435
|
+
const candidates = 'all' === pages ? Array.from(workspace.projects.entries()).filter(([, project])=>'application' === project.extensions['projectType']).map(([name])=>name) : pages;
|
|
1436
|
+
projectName = cli && candidates.includes(cli.project) ? cli.project : candidates[0] ?? null;
|
|
1437
|
+
} else projectName = cli?.project ?? getProjectByCwd(workspace, basePath);
|
|
1438
|
+
if (!projectName) throw new Error("couldn't find the project");
|
|
1439
|
+
const project = workspace.projects.get(projectName);
|
|
1440
|
+
if (!project) throw new Error(`Project "${projectName}" not found in workspace`);
|
|
1441
|
+
const buildOptions = cli?.project === projectName ? await normalizeBuildOptions(cli.buildOptions, project, basePath) : await readBuildOptions(project, basePath);
|
|
466
1442
|
return {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
};
|
|
470
|
-
};
|
|
471
|
-
const findProjectByPath = (workspace, location, basePath)=>{
|
|
472
|
-
const isInside = (base, potential)=>{
|
|
473
|
-
const absoluteBase = node_path.resolve(basePath, base);
|
|
474
|
-
const absolutePotential = node_path.resolve(basePath, potential);
|
|
475
|
-
const relativePotential = node_path.relative(absoluteBase, absolutePotential);
|
|
476
|
-
if (!relativePotential.startsWith('..') && !node_path.isAbsolute(relativePotential)) return true;
|
|
477
|
-
return false;
|
|
478
|
-
};
|
|
479
|
-
const projects = Array.from(workspace.projects).map(([name, project])=>[
|
|
480
|
-
project.root,
|
|
481
|
-
name
|
|
482
|
-
]).filter((tuple)=>isInside(tuple[0], location)).sort((a, b)=>b[0].length - a[0].length);
|
|
483
|
-
if (0 === projects.length) return null;
|
|
484
|
-
if (projects.length > 1) {
|
|
485
|
-
const found = new Set();
|
|
486
|
-
const sameRoots = projects.filter((v)=>{
|
|
487
|
-
if (!found.has(v[0])) {
|
|
488
|
-
found.add(v[0]);
|
|
489
|
-
return false;
|
|
490
|
-
}
|
|
491
|
-
return true;
|
|
492
|
-
});
|
|
493
|
-
if (sameRoots.length > 0) return null;
|
|
494
|
-
}
|
|
495
|
-
return projects[0][1];
|
|
496
|
-
};
|
|
497
|
-
const getProjectByCwd = (workspace, basePath)=>{
|
|
498
|
-
if (1 === workspace.projects.size) return Array.from(workspace.projects.keys())[0];
|
|
499
|
-
const project = findProjectByPath(workspace, process.cwd(), basePath);
|
|
500
|
-
if (project) return project;
|
|
501
|
-
return null;
|
|
1443
|
+
projectName,
|
|
1444
|
+
buildOptions
|
|
1445
|
+
};
|
|
502
1446
|
};
|
|
503
1447
|
const resolvePages = (workspace, basePath, pages)=>{
|
|
504
1448
|
const projectNames = 'all' === pages ? Array.from(workspace.projects.entries()).filter(([, def])=>'application' === def.extensions['projectType']).map(([name])=>name) : pages;
|
|
@@ -744,8 +1688,9 @@ const reportLynxDiagnostics = (diagnostics)=>{
|
|
|
744
1688
|
for (const w of cssWarnings)console.warn(` ${w.message}`);
|
|
745
1689
|
}
|
|
746
1690
|
};
|
|
747
|
-
const applyAngularRules = async (api, pluginOptions)=>{
|
|
748
|
-
const
|
|
1691
|
+
const applyAngularRules = async (api, pluginOptions, backgroundEntries, appEntries)=>{
|
|
1692
|
+
const cli = getAngularCliContext(api);
|
|
1693
|
+
const { basePath, workspace } = await getAngularWorkspace(cli?.workspaceRoot);
|
|
749
1694
|
if (pluginOptions.pages) {
|
|
750
1695
|
const pages = resolvePages(workspace, basePath, pluginOptions.pages);
|
|
751
1696
|
api.modifyRsbuildConfig((config)=>{
|
|
@@ -756,12 +1701,19 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
756
1701
|
]));
|
|
757
1702
|
});
|
|
758
1703
|
}
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
1704
|
+
const { buildOptions } = await resolvePrimaryBuild({
|
|
1705
|
+
workspace,
|
|
1706
|
+
basePath,
|
|
1707
|
+
pages: pluginOptions.pages,
|
|
1708
|
+
cli
|
|
1709
|
+
});
|
|
764
1710
|
applyAngularConfig(api, buildOptions);
|
|
1711
|
+
const componentStyleSizes = new Map();
|
|
1712
|
+
applyBudgets(api, {
|
|
1713
|
+
budgets: buildOptions.budgets,
|
|
1714
|
+
componentStyleSizes,
|
|
1715
|
+
underAngularCli: void 0 !== cli
|
|
1716
|
+
});
|
|
765
1717
|
const sourcemap = !!(!!buildOptions.sourcemapOptions.scripts && (buildOptions.sourcemapOptions.hidden ? 'external' : true));
|
|
766
1718
|
const thirdPartySourcemaps = buildOptions.sourcemapOptions.vendor;
|
|
767
1719
|
const advancedOptimizations = buildOptions.advancedOptimizations;
|
|
@@ -776,21 +1728,23 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
776
1728
|
const tsconfig = buildOptions.tsconfig;
|
|
777
1729
|
const compilation = await createAngularCompilation(false, aot);
|
|
778
1730
|
const typeScriptFileCache = new Map();
|
|
779
|
-
const
|
|
780
|
-
node_fs.mkdirSync(
|
|
1731
|
+
const componentCssCacheDir = node_path.join(basePath, 'node_modules', '.cache', 'angular-lynx-css');
|
|
1732
|
+
node_fs.mkdirSync(componentCssCacheDir, {
|
|
781
1733
|
recursive: true
|
|
782
1734
|
});
|
|
783
|
-
const
|
|
784
|
-
const componentScopeIds = new Map();
|
|
1735
|
+
const moduleStylesheets = new Map();
|
|
785
1736
|
let componentResourceDependencies = new Map();
|
|
786
1737
|
const writtenStylesheets = new Set();
|
|
787
1738
|
let knownSourceFiles = new Set();
|
|
1739
|
+
const backgroundModules = new Set();
|
|
1740
|
+
let angularInputs = new Set();
|
|
1741
|
+
let angularDiagnostics = {
|
|
1742
|
+
errors: [],
|
|
1743
|
+
warnings: []
|
|
1744
|
+
};
|
|
788
1745
|
const transformStylesheet = createTransformStylesheet({
|
|
789
1746
|
basePath,
|
|
790
|
-
|
|
791
|
-
componentStylesCache,
|
|
792
|
-
componentScopeIds,
|
|
793
|
-
onStylesheetWritten: (filePath)=>writtenStylesheets.add(filePath)
|
|
1747
|
+
componentStyleSizes
|
|
794
1748
|
});
|
|
795
1749
|
const compileAngular = async (changedFiles)=>{
|
|
796
1750
|
const { sourceFileCache, fileNames } = buildLynxSchemaSourceFileCache(tsconfig, changedFiles && ((file)=>changedFiles.has(node_path.normalize(file)) || !knownSourceFiles.has(file)));
|
|
@@ -826,30 +1780,50 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
826
1780
|
try {
|
|
827
1781
|
for (const { filename, contents } of (await compilation.emitAffectedFiles())){
|
|
828
1782
|
const file = node_path.normalize(filename);
|
|
829
|
-
|
|
830
|
-
|
|
1783
|
+
const { code, components } = extractComponentStyles('string' == typeof contents ? contents : Buffer.from(contents).toString(), file);
|
|
1784
|
+
const stylesheets = writeModuleStylesheets({
|
|
1785
|
+
basePath,
|
|
1786
|
+
cacheDir: componentCssCacheDir,
|
|
1787
|
+
fileName: file,
|
|
1788
|
+
components,
|
|
1789
|
+
onWritten: (filePath)=>writtenStylesheets.add(filePath)
|
|
1790
|
+
});
|
|
1791
|
+
if (stylesheets) moduleStylesheets.set(file, stylesheets);
|
|
1792
|
+
else moduleStylesheets.delete(file);
|
|
1793
|
+
if (typeScriptFileCache.get(file) !== code) {
|
|
1794
|
+
changedOutputs.add(file);
|
|
1795
|
+
if (definesCrossThreadValues(code, file)) backgroundModules.add(file);
|
|
1796
|
+
else backgroundModules.delete(file);
|
|
1797
|
+
}
|
|
1798
|
+
typeScriptFileCache.set(file, code);
|
|
831
1799
|
}
|
|
832
1800
|
} catch (error) {
|
|
833
1801
|
throw new Error(`Angular failed to emit compiled output for "${tsconfig}". Original error: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
834
1802
|
}
|
|
835
1803
|
for (const file of writtenStylesheets)changedOutputs.add(file);
|
|
836
|
-
for (const file of changedFiles ?? [])if (!node_fs.existsSync(file))
|
|
1804
|
+
for (const file of changedFiles ?? [])if (!node_fs.existsSync(file)) {
|
|
1805
|
+
typeScriptFileCache.delete(file);
|
|
1806
|
+
backgroundModules.delete(file);
|
|
1807
|
+
moduleStylesheets.delete(file);
|
|
1808
|
+
forgetComponentStyleSizes(componentStyleSizes, file);
|
|
1809
|
+
}
|
|
837
1810
|
reportLynxDiagnostics([
|
|
838
1811
|
...scanCompiledOutputForHtmlElements(typeScriptFileCache),
|
|
839
1812
|
...scanCompiledOutputForStructuralIssues(typeScriptFileCache),
|
|
840
1813
|
...scanSourcesForUnsupportedPatterns(fileNames),
|
|
841
1814
|
...scanSourcesForUnsupportedCss(fileNames)
|
|
842
1815
|
]);
|
|
843
|
-
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1816
|
+
angularDiagnostics = filterAngularDiagnostics(await compilation.diagnoseFiles(useTypeChecking ? DiagnosticModes.All : DiagnosticModes.All & ~DiagnosticModes.Semantic));
|
|
1817
|
+
const inputFiles = result.referencedFiles.map((file)=>node_path.normalize(file));
|
|
1818
|
+
angularInputs = new Set([
|
|
1819
|
+
...inputFiles,
|
|
1820
|
+
...[
|
|
1821
|
+
...componentResourceDependencies.values()
|
|
1822
|
+
].flat()
|
|
1823
|
+
]);
|
|
850
1824
|
return {
|
|
851
1825
|
changedOutputs,
|
|
852
|
-
inputFiles
|
|
1826
|
+
inputFiles
|
|
853
1827
|
};
|
|
854
1828
|
};
|
|
855
1829
|
const coordinator = createAngularRebuildCoordinator({
|
|
@@ -861,425 +1835,293 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
861
1835
|
compiler
|
|
862
1836
|
];
|
|
863
1837
|
for (const environmentCompiler of compilers)if (environmentCompiler.name) compilersByEnvironment.set(environmentCompiler.name, environmentCompiler);
|
|
1838
|
+
compilers[0]?.hooks.thisCompilation.tap('lynx:angular:diagnostics', (rspackCompilation)=>{
|
|
1839
|
+
rspackCompilation.errors.push(...angularDiagnostics.errors.map((message)=>toAngularDiagnosticError(message, 'error')));
|
|
1840
|
+
rspackCompilation.warnings.push(...angularDiagnostics.warnings.map((message)=>toAngularDiagnosticError(message, 'warning')));
|
|
1841
|
+
});
|
|
864
1842
|
});
|
|
865
1843
|
let compilationClosed = false;
|
|
866
1844
|
api.onBeforeEnvironmentCompile(async ({ environment, isWatch })=>{
|
|
867
1845
|
const compiler = compilersByEnvironment.get(environment.name);
|
|
868
|
-
const
|
|
1846
|
+
const changedFiles = [
|
|
869
1847
|
...compiler?.modifiedFiles ?? [],
|
|
870
1848
|
...compiler?.removedFiles ?? []
|
|
871
|
-
]
|
|
872
|
-
|
|
1849
|
+
];
|
|
1850
|
+
const outdatedFiles = await coordinator.prepare(environment.name, changedFiles);
|
|
1851
|
+
const changedEntries = backgroundEntries.update(environment.name, {
|
|
1852
|
+
appModules: backgroundModules,
|
|
1853
|
+
watch: isWatch,
|
|
1854
|
+
rebuilt: outdatedFiles.size > 0 || changedFiles.some((file)=>!angularInputs.has(node_path.normalize(file)) && !backgroundEntries.isEntryFile(file))
|
|
1855
|
+
});
|
|
1856
|
+
if (compiler && outdatedFiles.size + changedEntries.length > 0) compiler.modifiedFiles = new Set([
|
|
873
1857
|
...compiler.modifiedFiles ?? [],
|
|
874
|
-
...outdatedFiles
|
|
1858
|
+
...outdatedFiles,
|
|
1859
|
+
...changedEntries
|
|
875
1860
|
]);
|
|
876
1861
|
if (!isWatch && !compilationClosed) {
|
|
877
1862
|
compilationClosed = true;
|
|
878
1863
|
await compilation.close?.();
|
|
879
1864
|
}
|
|
880
1865
|
});
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
code: transformWorklets(Buffer.from(contents).toString(), context.resourcePath)
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
const content = typeScriptFileCache.get(context.resourcePath);
|
|
895
|
-
if (!content) throw new Error(`No compiled output found for ${context.resourcePath}`);
|
|
896
|
-
for (const dependency of componentResourceDependencies.get(context.resourcePath) ?? [])context.addDependency(dependency);
|
|
897
|
-
const code = 'string' == typeof content ? content : Buffer.from(content).toString();
|
|
898
|
-
return {
|
|
899
|
-
code: buildTransformedCode({
|
|
900
|
-
code,
|
|
901
|
-
resourcePath: context.resourcePath,
|
|
902
|
-
componentStyles: componentStylesCache.get(context.resourcePath),
|
|
903
|
-
scopeInfo: componentScopeIds.get(context.resourcePath)
|
|
904
|
-
})
|
|
905
|
-
};
|
|
906
|
-
});
|
|
907
|
-
};
|
|
908
|
-
const LAYERS = {
|
|
909
|
-
BACKGROUND: 'background',
|
|
910
|
-
MAIN_THREAD: 'main'
|
|
911
|
-
};
|
|
912
|
-
const applyLayers = (api)=>{
|
|
913
|
-
api.modifyBundlerChain((chain)=>{
|
|
914
|
-
chain.module.rule("typescript").oneOf(LAYERS.BACKGROUND).layer(LAYERS.BACKGROUND).test(/\.[cm]?[jt]sx?$/).use('builtin:swc-loader').loader('builtin:swc-loader').options({
|
|
915
|
-
jsc: {
|
|
916
|
-
target: 'es2015',
|
|
917
|
-
parser: {
|
|
918
|
-
syntax: "typescript"
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
}).end();
|
|
922
|
-
chain.module.rule("typescript").oneOf(LAYERS.MAIN_THREAD).layer(LAYERS.MAIN_THREAD).test(/\.[cm]?[jt]sx?$/).use('builtin:swc-loader').loader('builtin:swc-loader').options({
|
|
923
|
-
jsc: {
|
|
924
|
-
target: 'es2019',
|
|
925
|
-
parser: {
|
|
926
|
-
syntax: "typescript"
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
}).end();
|
|
930
|
-
});
|
|
931
|
-
};
|
|
932
|
-
const applyCSS = (api, options)=>{
|
|
933
|
-
const { enableRemoveCSSScope, enableCSSSelector, enableCSSInvalidation, targetSdkVersion } = options;
|
|
934
|
-
api.modifyRsbuildConfig((config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
|
|
935
|
-
output: {
|
|
936
|
-
injectStyles: false
|
|
937
|
-
}
|
|
938
|
-
}));
|
|
939
|
-
const __dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
940
|
-
api.modifyBundlerChain(async (chain, { CHAIN_ID, environment })=>{
|
|
941
|
-
const { CssExtractRspackPlugin } = await import("@lynx-js/css-extract-webpack-plugin");
|
|
942
|
-
const removeLightningCSS = (rule)=>{
|
|
943
|
-
if (rule.uses.has(CHAIN_ID.USE.LIGHTNINGCSS) && 'lynx' === environment.name) rule.uses.delete(CHAIN_ID.USE.LIGHTNINGCSS);
|
|
944
|
-
};
|
|
945
|
-
const cssRules = [
|
|
946
|
-
CHAIN_ID.RULE.CSS,
|
|
947
|
-
CHAIN_ID.RULE.SASS,
|
|
948
|
-
CHAIN_ID.RULE.LESS,
|
|
949
|
-
CHAIN_ID.RULE.STYLUS
|
|
950
|
-
];
|
|
951
|
-
for (const ruleName of cssRules.filter((rule)=>chain.module.rules.has(rule))){
|
|
952
|
-
const rule = chain.module.rule(ruleName);
|
|
953
|
-
const mainRuleName = ruleName === CHAIN_ID.RULE.CSS ? CHAIN_ID.ONE_OF.CSS_MAIN : ruleName;
|
|
954
|
-
const mainRule = rule.oneOf(mainRuleName);
|
|
955
|
-
const parentRuleEntries = rule.entries();
|
|
956
|
-
removeLightningCSS(mainRule);
|
|
957
|
-
mainRule.issuerLayer(LAYERS.BACKGROUND).use(CHAIN_ID.USE.MINI_CSS_EXTRACT).loader(CssExtractRspackPlugin.loader).end();
|
|
958
|
-
const uses = mainRule.uses.entries() ?? {};
|
|
959
|
-
const ruleEntries = mainRule.entries();
|
|
960
|
-
const cssLoader = uses[CHAIN_ID.USE.CSS];
|
|
961
|
-
if (!cssLoader) continue;
|
|
962
|
-
const cssLoaderRule = cssLoader.entries();
|
|
963
|
-
const mainThreadLayerRule = chain.module.rule(`${ruleName}:${LAYERS.MAIN_THREAD}`).test(parentRuleEntries.test).merge(ruleEntries).issuerLayer(LAYERS.MAIN_THREAD);
|
|
964
|
-
if (void 0 !== parentRuleEntries.dependency) mainThreadLayerRule.merge({
|
|
965
|
-
dependency: parentRuleEntries.dependency
|
|
966
|
-
});
|
|
967
|
-
mainThreadLayerRule.use(CHAIN_ID.USE.IGNORE_CSS).loader(node_path.resolve(__dirname, './loaders/ignore-css-loader')).end().uses.merge(uses).delete(CHAIN_ID.USE.MINI_CSS_EXTRACT).delete(CHAIN_ID.USE.LIGHTNINGCSS).delete(CHAIN_ID.USE.CSS).end().use(CHAIN_ID.USE.CSS).after(CHAIN_ID.USE.IGNORE_CSS).merge(cssLoaderRule).options(normalizeCssLoaderOptions(cssLoaderRule.options, true)).end();
|
|
968
|
-
}
|
|
969
|
-
for (const ruleName of cssRules.filter((rule)=>chain.module.rules.has(rule))){
|
|
970
|
-
const inlineRuleName = ruleName === CHAIN_ID.RULE.CSS ? CHAIN_ID.ONE_OF.CSS_INLINE : `${ruleName}-inline`;
|
|
971
|
-
removeLightningCSS(chain.module.rule(ruleName).oneOf(inlineRuleName));
|
|
972
|
-
}
|
|
973
|
-
if ('lynx' === environment.name && chain.module.rules.has(CHAIN_ID.RULE.FONT)) {
|
|
974
|
-
const fontRule = chain.module.rule(CHAIN_ID.RULE.FONT);
|
|
975
|
-
fontRule.oneOfs.clear();
|
|
976
|
-
fontRule.type('asset/inline');
|
|
977
|
-
}
|
|
978
|
-
chain.plugin(CHAIN_ID.PLUGIN.MINI_CSS_EXTRACT).tap(([options])=>[
|
|
979
|
-
{
|
|
980
|
-
...options,
|
|
981
|
-
enableRemoveCSSScope,
|
|
982
|
-
enableCSSSelector,
|
|
983
|
-
enableCSSInvalidation,
|
|
984
|
-
targetSdkVersion,
|
|
985
|
-
cssPlugins: [
|
|
986
|
-
CSSPlugins.parserPlugins.removeFunctionWhiteSpace()
|
|
987
|
-
]
|
|
988
|
-
}
|
|
989
|
-
]).init((_, args)=>new CssExtractRspackPlugin(...args)).end().end();
|
|
990
|
-
chain.module.when(void 0 === enableRemoveCSSScope, (module)=>module.rule('lynx.css.scoped').test(/\.css$/).resourceQuery({
|
|
991
|
-
and: [
|
|
992
|
-
/cssId/,
|
|
993
|
-
{
|
|
994
|
-
not: /common/
|
|
995
|
-
}
|
|
996
|
-
]
|
|
997
|
-
}).sideEffects(false));
|
|
998
|
-
});
|
|
999
|
-
};
|
|
1000
|
-
const normalizeCssLoaderOptions = (options, exportOnlyLocals)=>{
|
|
1001
|
-
if (options.modules && exportOnlyLocals) {
|
|
1002
|
-
let { modules } = options;
|
|
1003
|
-
modules = true === modules ? {
|
|
1004
|
-
exportOnlyLocals: true
|
|
1005
|
-
} : 'string' == typeof modules ? {
|
|
1006
|
-
mode: modules,
|
|
1007
|
-
exportOnlyLocals: true
|
|
1008
|
-
} : {
|
|
1009
|
-
...modules,
|
|
1010
|
-
exportOnlyLocals: true
|
|
1011
|
-
};
|
|
1012
|
-
return {
|
|
1013
|
-
...options,
|
|
1014
|
-
modules
|
|
1015
|
-
};
|
|
1016
|
-
}
|
|
1017
|
-
return options;
|
|
1018
|
-
};
|
|
1019
|
-
const createLynxProcessEvalResultRuntimeModule = (webpack)=>class extends webpack.RuntimeModule {
|
|
1020
|
-
constructor(){
|
|
1021
|
-
super('Lynx process eval result', webpack.RuntimeModule.STAGE_ATTACH);
|
|
1022
|
-
}
|
|
1023
|
-
generate() {
|
|
1024
|
-
const chunk = this.chunk;
|
|
1025
|
-
const compilation = this.compilation;
|
|
1026
|
-
if (!chunk || !compilation) return '';
|
|
1027
|
-
const chunkGroup = chunk._groupsIterable?.[0];
|
|
1028
|
-
const modules = compilation.chunkGraph?.getChunkModules(chunk) ?? [];
|
|
1029
|
-
modules.sort((a, b)=>{
|
|
1030
|
-
const aIdx = chunkGroup?.getModulePreOrderIndex(a) ?? 0;
|
|
1031
|
-
const bIdx = chunkGroup?.getModulePreOrderIndex(b) ?? 0;
|
|
1032
|
-
return aIdx - bIdx;
|
|
1033
|
-
});
|
|
1034
|
-
const sortedIds = modules.map((m)=>compilation.chunkGraph.getModuleId(m)).filter((id)=>null != id);
|
|
1035
|
-
const moduleOrder = JSON.stringify(sortedIds);
|
|
1036
|
-
return `
|
|
1037
|
-
${RuntimeGlobals.lynxProcessEvalResult} = function (result, schema) {
|
|
1038
|
-
var chunk = result && result(schema);
|
|
1039
|
-
if (chunk && chunk.ids && chunk.modules) {
|
|
1040
|
-
${webpack.RuntimeGlobals.externalInstallChunk}(chunk);
|
|
1041
|
-
var moduleOrder = ${moduleOrder};
|
|
1042
|
-
for (var i = 0; i < moduleOrder.length; i++) {
|
|
1043
|
-
if (chunk.modules[moduleOrder[i]]) {
|
|
1044
|
-
${webpack.RuntimeGlobals.require}(moduleOrder[i]);
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
return chunk;
|
|
1048
|
-
}
|
|
1049
|
-
return chunk
|
|
1050
|
-
}
|
|
1051
|
-
`;
|
|
1052
|
-
}
|
|
1053
|
-
};
|
|
1054
|
-
class AngularWebpackPlugin {
|
|
1055
|
-
options;
|
|
1056
|
-
constructor(options){
|
|
1057
|
-
this.options = options;
|
|
1058
|
-
}
|
|
1059
|
-
static defaultOptions = Object.freeze({
|
|
1060
|
-
disableCreateSelectorQueryIncompatibleWarning: false,
|
|
1061
|
-
firstScreenSyncTiming: 'immediately',
|
|
1062
|
-
enableSSR: false,
|
|
1063
|
-
isWeb: false,
|
|
1064
|
-
mainThreadChunks: [],
|
|
1065
|
-
extractStr: false,
|
|
1066
|
-
experimental_isLazyBundle: false
|
|
1067
|
-
});
|
|
1068
|
-
apply(compiler) {
|
|
1069
|
-
const options = Object.assign({}, AngularWebpackPlugin.defaultOptions, this.options);
|
|
1070
|
-
if (options.enableSSR && 'jsReady' !== options.firstScreenSyncTiming) options.firstScreenSyncTiming = 'jsReady';
|
|
1071
|
-
const { DefinePlugin, EnvironmentPlugin } = compiler.webpack;
|
|
1072
|
-
new EnvironmentPlugin({
|
|
1073
|
-
DEBUG: null
|
|
1074
|
-
}).apply(compiler);
|
|
1075
|
-
new DefinePlugin({
|
|
1076
|
-
__DEV__: JSON.stringify('development' === compiler.options.mode),
|
|
1077
|
-
__PROFILE__: JSON.stringify('development' === compiler.options.mode),
|
|
1078
|
-
__EXTRACT_STR__: JSON.stringify(Boolean(options.extractStr)),
|
|
1079
|
-
__FIRST_SCREEN_SYNC_TIMING__: JSON.stringify(options.firstScreenSyncTiming),
|
|
1080
|
-
__ENABLE_SSR__: JSON.stringify(options.enableSSR),
|
|
1081
|
-
__WEB__: JSON.stringify(Boolean(options.isWeb)),
|
|
1082
|
-
__DISABLE_CREATE_SELECTOR_QUERY_INCOMPATIBLE_WARNING__: JSON.stringify(options.disableCreateSelectorQueryIncompatibleWarning)
|
|
1083
|
-
}).apply(compiler);
|
|
1084
|
-
compiler.hooks.thisCompilation.tap(this.constructor.name, (compilation)=>{
|
|
1085
|
-
const onceForChunkSet = new WeakSet();
|
|
1086
|
-
compilation.hooks.runtimeRequirementInTree.for(compiler.webpack.RuntimeGlobals.ensureChunkHandlers).tap('VanillaWebpackPlugin', (chunk, runtimeRequirements)=>{
|
|
1087
|
-
runtimeRequirements.add(RuntimeGlobals.lynxProcessEvalResult);
|
|
1088
|
-
});
|
|
1089
|
-
compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.lynxProcessEvalResult).tap('VanillaWebpackPlugin', (chunk)=>{
|
|
1090
|
-
if (onceForChunkSet.has(chunk)) return;
|
|
1091
|
-
onceForChunkSet.add(chunk);
|
|
1092
|
-
const LynxProcessEvalResultRuntimeModule = createLynxProcessEvalResultRuntimeModule(compiler.webpack);
|
|
1093
|
-
compilation.addRuntimeModule(chunk, new LynxProcessEvalResultRuntimeModule());
|
|
1094
|
-
});
|
|
1095
|
-
compilation.hooks.processAssets.tap({
|
|
1096
|
-
name: this.constructor.name,
|
|
1097
|
-
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
|
|
1098
|
-
}, ()=>{
|
|
1099
|
-
for (const name of options.mainThreadChunks ?? [])this.#updateMainThreadInfo(compilation, name);
|
|
1100
|
-
for (const cg of compilation.chunkGroups.filter((cg)=>!cg.isInitial()).filter((cg)=>cg.origins.every((origin)=>origin.module?.layer === LAYERS.MAIN_THREAD))){
|
|
1101
|
-
const files = cg.getFiles();
|
|
1102
|
-
for (const name of files.filter((name)=>name.endsWith('.js')))this.#updateMainThreadInfo(compilation, name);
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
{
|
|
1106
|
-
const { ConcatSource } = compiler.webpack.sources;
|
|
1107
|
-
const mainThreadChunkSet = new Set(options.mainThreadChunks ?? []);
|
|
1108
|
-
compilation.hooks.processAssets.tap({
|
|
1109
|
-
name: `${this.constructor.name}:threadGlobals`,
|
|
1110
|
-
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
|
1111
|
-
}, ()=>{
|
|
1112
|
-
for (const [name] of Object.entries(compilation.assets).filter(([n])=>n.endsWith('.js'))){
|
|
1113
|
-
const isMainThread = mainThreadChunkSet.has(name);
|
|
1114
|
-
const prefix = `globalThis["__MAIN_THREAD__"]=${isMainThread};`;
|
|
1115
|
-
compilation.updateAsset(name, (old)=>new ConcatSource(prefix, old));
|
|
1116
|
-
}
|
|
1117
|
-
if (!options.experimental_isLazyBundle) for (const name of options.mainThreadChunks ?? []){
|
|
1118
|
-
const asset = compilation.getAsset(name);
|
|
1119
|
-
if (!asset) continue;
|
|
1120
|
-
const source = asset.source.source().toString();
|
|
1121
|
-
const useStrictPrefix = /^(['"])use strict\1;?/.test(source) ? "'use strict';" : '';
|
|
1122
|
-
compilation.updateAsset(name, (old)=>new ConcatSource(`${useStrictPrefix}var globDynamicComponentEntry=globDynamicComponentEntry||'__Card__';`, old));
|
|
1123
|
-
}
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation);
|
|
1127
|
-
const { ConcatSource } = compiler.webpack.sources;
|
|
1128
|
-
hooks.beforeEncode.tap(this.constructor.name, (args)=>{
|
|
1129
|
-
const { encodeData } = args;
|
|
1130
|
-
encodeData.sourceContent.config = {
|
|
1131
|
-
...encodeData.sourceContent.config,
|
|
1132
|
-
enableCSSInlineVariables: true
|
|
1133
|
-
};
|
|
1134
|
-
if (!encodeData.lepusCode.root) return args;
|
|
1135
|
-
if ('card' === encodeData.sourceContent.appType) return args;
|
|
1136
|
-
compilation.updateAsset(encodeData.lepusCode.root.name, (old)=>new ConcatSource(`\
|
|
1137
|
-
(function (globDynamicComponentEntry) {
|
|
1138
|
-
const module = { exports: {} }
|
|
1139
|
-
const exports = module.exports
|
|
1140
|
-
`, old, `
|
|
1141
|
-
;return module.exports
|
|
1142
|
-
})`));
|
|
1143
|
-
return args;
|
|
1866
|
+
const transformModule = async (context, background)=>{
|
|
1867
|
+
const hot = hotUpdatesEnabled(context.environment);
|
|
1868
|
+
const isJs = /\.[cm]?js$/.test(context.resourcePath);
|
|
1869
|
+
if (isJs) {
|
|
1870
|
+
const contents = await javascriptTransformer.transformData(context.resourcePath, context.code, {
|
|
1871
|
+
skipLinker: false,
|
|
1872
|
+
sideEffects: ()=>Promise.resolve(false)
|
|
1873
|
+
});
|
|
1874
|
+
const code = transformCrossThread(transformWorklets(Buffer.from(contents).toString(), context.resourcePath), context.resourcePath, {
|
|
1875
|
+
root: api.context.rootPath
|
|
1144
1876
|
});
|
|
1877
|
+
if (!background) return {
|
|
1878
|
+
code
|
|
1879
|
+
};
|
|
1880
|
+
const wrapped = wrapPureClasses(code, context.resourcePath);
|
|
1881
|
+
return {
|
|
1882
|
+
code: hot && backgroundEntries.isEntryFile(context.resourcePath) ? addEntryHotAccept(wrapped) : wrapped
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1885
|
+
const content = typeScriptFileCache.get(context.resourcePath);
|
|
1886
|
+
if (!content) throw new Error(`No compiled output found for ${context.resourcePath}`);
|
|
1887
|
+
for (const dependency of componentResourceDependencies.get(context.resourcePath) ?? [])context.addDependency(dependency);
|
|
1888
|
+
const code = buildTransformedCode({
|
|
1889
|
+
code: 'string' == typeof content ? content : Buffer.from(content).toString(),
|
|
1890
|
+
resourcePath: context.resourcePath,
|
|
1891
|
+
stylesheets: moduleStylesheets.get(context.resourcePath),
|
|
1892
|
+
root: api.context.rootPath,
|
|
1893
|
+
hot: hot && !background ? {
|
|
1894
|
+
entry: appEntries.has(node_path.normalize(context.resourcePath)),
|
|
1895
|
+
source: ()=>node_fs.readFileSync(context.resourcePath, 'utf-8')
|
|
1896
|
+
} : void 0
|
|
1145
1897
|
});
|
|
1898
|
+
if (!background) return {
|
|
1899
|
+
code
|
|
1900
|
+
};
|
|
1901
|
+
return {
|
|
1902
|
+
code: wrapPureClasses(Buffer.from(await javascriptTransformer.transformData(context.resourcePath, code, {
|
|
1903
|
+
skipLinker: true,
|
|
1904
|
+
sideEffects: ()=>Promise.resolve(false)
|
|
1905
|
+
})).toString(), context.resourcePath)
|
|
1906
|
+
};
|
|
1907
|
+
};
|
|
1908
|
+
api.transform({
|
|
1909
|
+
test: /\.[cm]?[jt]sx?$/,
|
|
1910
|
+
issuerLayer: LAYERS.MAIN_THREAD
|
|
1911
|
+
}, (context)=>transformModule(context, false));
|
|
1912
|
+
api.transform({
|
|
1913
|
+
test: /\.[cm]?[jt]sx?$/,
|
|
1914
|
+
issuerLayer: LAYERS.BACKGROUND
|
|
1915
|
+
}, (context)=>transformModule(context, true));
|
|
1916
|
+
};
|
|
1917
|
+
const background_entry_RUNTIME_MODULE = '@blotch/angular-lynx';
|
|
1918
|
+
const createBackgroundEntries = ({ rootPath, findLibraryModules = findLibraryBackgroundModules })=>{
|
|
1919
|
+
const cacheDir = node_path.join(rootPath, 'node_modules', '.cache', 'angular-lynx', 'background-entries');
|
|
1920
|
+
const files = new Map();
|
|
1921
|
+
let libraryModules;
|
|
1922
|
+
const getLibraryModules = ()=>libraryModules ??= findLibraryModules(rootPath);
|
|
1923
|
+
let modules = new Set();
|
|
1924
|
+
const rebuilds = new Map();
|
|
1925
|
+
return {
|
|
1926
|
+
fileFor: (environmentName, entryName)=>{
|
|
1927
|
+
const file = node_path.join(cacheDir, environmentName, `${entryName}.js`);
|
|
1928
|
+
let environmentFiles = files.get(environmentName);
|
|
1929
|
+
if (!environmentFiles) {
|
|
1930
|
+
environmentFiles = new Set();
|
|
1931
|
+
files.set(environmentName, environmentFiles);
|
|
1932
|
+
}
|
|
1933
|
+
environmentFiles.add(file);
|
|
1934
|
+
if (!node_fs.existsSync(file)) writeIfChanged(file, renderBackgroundEntry({
|
|
1935
|
+
modules: []
|
|
1936
|
+
}));
|
|
1937
|
+
return file;
|
|
1938
|
+
},
|
|
1939
|
+
isBackgroundModule: (file)=>modules.has(file),
|
|
1940
|
+
isEntryFile: (file)=>[
|
|
1941
|
+
...files.values()
|
|
1942
|
+
].some((environmentFiles)=>environmentFiles.has(file)),
|
|
1943
|
+
update: (environmentName, { appModules, watch, rebuilt })=>{
|
|
1944
|
+
modules = new Set([
|
|
1945
|
+
...getLibraryModules(),
|
|
1946
|
+
...[
|
|
1947
|
+
...appModules
|
|
1948
|
+
].sort()
|
|
1949
|
+
]);
|
|
1950
|
+
const rebuild = (rebuilds.get(environmentName) ?? 0) + (watch && rebuilt ? 1 : 0);
|
|
1951
|
+
rebuilds.set(environmentName, rebuild);
|
|
1952
|
+
const contents = renderBackgroundEntry({
|
|
1953
|
+
modules: [
|
|
1954
|
+
...modules
|
|
1955
|
+
],
|
|
1956
|
+
rebuild: watch ? rebuild : void 0
|
|
1957
|
+
});
|
|
1958
|
+
return [
|
|
1959
|
+
...files.get(environmentName) ?? []
|
|
1960
|
+
].filter((file)=>writeIfChanged(file, contents));
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
};
|
|
1964
|
+
const renderBackgroundEntry = ({ modules, rebuild })=>{
|
|
1965
|
+
const lines = [
|
|
1966
|
+
"// The background thread's entry, generated by",
|
|
1967
|
+
'// @blotch/rsbuild-plugin-angular-lynx (see background-entry.ts there).',
|
|
1968
|
+
'// Angular runs on the main thread only, so the background thread loads the',
|
|
1969
|
+
'// runtime and the modules that call backgroundFn(), createMainThreadRef()',
|
|
1970
|
+
'// or new MainThreadRef() at module level.',
|
|
1971
|
+
`import { ɵstartBackgroundThread } from '${background_entry_RUNTIME_MODULE}';`,
|
|
1972
|
+
...modules.map((file)=>`import ${JSON.stringify(file)};`),
|
|
1973
|
+
'ɵstartBackgroundThread();'
|
|
1974
|
+
];
|
|
1975
|
+
if (void 0 !== rebuild) lines.push(`// Rebuild ${rebuild}`);
|
|
1976
|
+
return `${lines.join('\n')}\n`;
|
|
1977
|
+
};
|
|
1978
|
+
const writeIfChanged = (file, contents)=>{
|
|
1979
|
+
if (node_fs.existsSync(file) && node_fs.readFileSync(file, 'utf8') === contents) return false;
|
|
1980
|
+
node_fs.mkdirSync(node_path.dirname(file), {
|
|
1981
|
+
recursive: true
|
|
1982
|
+
});
|
|
1983
|
+
node_fs.writeFileSync(file, contents);
|
|
1984
|
+
return true;
|
|
1985
|
+
};
|
|
1986
|
+
const JS_FILE = /\.[cm]?js$/;
|
|
1987
|
+
const findLibraryBackgroundModules = (rootPath)=>{
|
|
1988
|
+
const found = new Set();
|
|
1989
|
+
const visited = new Set();
|
|
1990
|
+
const visit = (packageDir, isApp)=>{
|
|
1991
|
+
const manifest = readManifest(packageDir);
|
|
1992
|
+
if (!manifest) return;
|
|
1993
|
+
const names = new Set([
|
|
1994
|
+
...Object.keys(manifest.dependencies ?? {}),
|
|
1995
|
+
...Object.keys(manifest.optionalDependencies ?? {}),
|
|
1996
|
+
...Object.keys(manifest.peerDependencies ?? {}),
|
|
1997
|
+
...isApp ? Object.keys(manifest.devDependencies ?? {}) : []
|
|
1998
|
+
]);
|
|
1999
|
+
names.delete(background_entry_RUNTIME_MODULE);
|
|
2000
|
+
for (const name of names){
|
|
2001
|
+
const dependencyDir = resolvePackageDir(name, packageDir);
|
|
2002
|
+
if (!dependencyDir || visited.has(dependencyDir)) continue;
|
|
2003
|
+
visited.add(dependencyDir);
|
|
2004
|
+
const dependency = readManifest(dependencyDir);
|
|
2005
|
+
if (dependency && dependsOnRuntime(dependency)) {
|
|
2006
|
+
for (const file of listJsFiles(dependencyDir))if (definesCrossThreadValues(node_fs.readFileSync(file, 'utf8'), file)) found.add(file);
|
|
2007
|
+
}
|
|
2008
|
+
visit(dependencyDir, false);
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2011
|
+
visit(rootPath, true);
|
|
2012
|
+
return [
|
|
2013
|
+
...found
|
|
2014
|
+
].sort();
|
|
2015
|
+
};
|
|
2016
|
+
const readManifest = (packageDir)=>{
|
|
2017
|
+
try {
|
|
2018
|
+
return JSON.parse(node_fs.readFileSync(node_path.join(packageDir, 'package.json'), 'utf8'));
|
|
2019
|
+
} catch {
|
|
2020
|
+
return;
|
|
1146
2021
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
2022
|
+
};
|
|
2023
|
+
const dependsOnRuntime = (manifest)=>[
|
|
2024
|
+
manifest.dependencies,
|
|
2025
|
+
manifest.optionalDependencies,
|
|
2026
|
+
manifest.peerDependencies
|
|
2027
|
+
].some((dependencies)=>dependencies?.[background_entry_RUNTIME_MODULE] !== void 0);
|
|
2028
|
+
const resolvePackageDir = (name, fromDir)=>{
|
|
2029
|
+
for(let dir = fromDir;; dir = node_path.dirname(dir)){
|
|
2030
|
+
const candidate = node_path.join(dir, 'node_modules', name);
|
|
2031
|
+
if (node_fs.existsSync(node_path.join(candidate, 'package.json'))) return node_fs.realpathSync(candidate);
|
|
2032
|
+
if (node_path.dirname(dir) === dir) return;
|
|
1154
2033
|
}
|
|
1155
|
-
}
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
const
|
|
1161
|
-
const {
|
|
1162
|
-
api.
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
const
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
2034
|
+
};
|
|
2035
|
+
const listJsFiles = (packageDir)=>node_fs.readdirSync(packageDir, {
|
|
2036
|
+
recursive: true,
|
|
2037
|
+
encoding: 'utf8'
|
|
2038
|
+
}).filter((file)=>JS_FILE.test(file) && !file.split(node_path.sep).includes('node_modules')).map((file)=>node_path.join(packageDir, file));
|
|
2039
|
+
const applyCSS = (api, options)=>{
|
|
2040
|
+
const { enableRemoveCSSScope, enableCSSSelector, enableCSSInvalidation, targetSdkVersion } = options;
|
|
2041
|
+
api.modifyRsbuildConfig((config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
|
|
2042
|
+
output: {
|
|
2043
|
+
injectStyles: false
|
|
2044
|
+
}
|
|
2045
|
+
}));
|
|
2046
|
+
const __dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
2047
|
+
api.modifyBundlerChain(async (chain, { CHAIN_ID, environment })=>{
|
|
2048
|
+
const { CssExtractRspackPlugin } = await import("@lynx-js/css-extract-webpack-plugin");
|
|
2049
|
+
const removeLightningCSS = (rule)=>{
|
|
2050
|
+
if (rule.uses.has(CHAIN_ID.USE.LIGHTNINGCSS) && 'lynx' === environment.name) rule.uses.delete(CHAIN_ID.USE.LIGHTNINGCSS);
|
|
2051
|
+
};
|
|
2052
|
+
const cssRules = [
|
|
2053
|
+
CHAIN_ID.RULE.CSS,
|
|
2054
|
+
CHAIN_ID.RULE.SASS,
|
|
2055
|
+
CHAIN_ID.RULE.LESS,
|
|
2056
|
+
CHAIN_ID.RULE.STYLUS
|
|
2057
|
+
];
|
|
2058
|
+
for (const ruleName of cssRules.filter((rule)=>chain.module.rules.has(rule))){
|
|
2059
|
+
const rule = chain.module.rule(ruleName);
|
|
2060
|
+
const mainRuleName = ruleName === CHAIN_ID.RULE.CSS ? CHAIN_ID.ONE_OF.CSS_MAIN : ruleName;
|
|
2061
|
+
const mainRule = rule.oneOf(mainRuleName);
|
|
2062
|
+
const parentRuleEntries = rule.entries();
|
|
2063
|
+
removeLightningCSS(mainRule);
|
|
2064
|
+
mainRule.issuerLayer(LAYERS.MAIN_THREAD).use(CHAIN_ID.USE.MINI_CSS_EXTRACT).loader(CssExtractRspackPlugin.loader).end();
|
|
2065
|
+
const uses = mainRule.uses.entries() ?? {};
|
|
2066
|
+
const ruleEntries = mainRule.entries();
|
|
2067
|
+
const cssLoader = uses[CHAIN_ID.USE.CSS];
|
|
2068
|
+
if (!cssLoader) continue;
|
|
2069
|
+
const cssLoaderRule = cssLoader.entries();
|
|
2070
|
+
const backgroundLayerRule = chain.module.rule(`${ruleName}:${LAYERS.BACKGROUND}`).test(parentRuleEntries.test).merge(ruleEntries).issuerLayer(LAYERS.BACKGROUND);
|
|
2071
|
+
if (void 0 !== parentRuleEntries.dependency) backgroundLayerRule.merge({
|
|
2072
|
+
dependency: parentRuleEntries.dependency
|
|
1178
2073
|
});
|
|
1179
|
-
|
|
1180
|
-
const mainThreadName = node_path.posix.join(`${entryName}/main-thread.js`);
|
|
1181
|
-
const backgroundEntry = entryName;
|
|
1182
|
-
const backgroundThreadName = node_path.posix.join(`${entryName}/background-thread.js`);
|
|
1183
|
-
mainThreadChunks.push(mainThreadName);
|
|
1184
|
-
chain.entry(mainThreadEntry).add({
|
|
1185
|
-
layer: LAYERS.MAIN_THREAD,
|
|
1186
|
-
import: imports,
|
|
1187
|
-
filename: mainThreadName
|
|
1188
|
-
}).end();
|
|
1189
|
-
chain.entry(backgroundEntry).add({
|
|
1190
|
-
layer: LAYERS.BACKGROUND,
|
|
1191
|
-
import: imports,
|
|
1192
|
-
filename: backgroundThreadName
|
|
1193
|
-
}).when(enabledHMR, (entry)=>{
|
|
1194
|
-
entry.prepend({
|
|
1195
|
-
layer: LAYERS.BACKGROUND,
|
|
1196
|
-
import: '@rspack/core/hot/dev-server'
|
|
1197
|
-
});
|
|
1198
|
-
}).when(enabledHMR || enabledLiveReload, (entry)=>{
|
|
1199
|
-
entry.prepend({
|
|
1200
|
-
layer: LAYERS.BACKGROUND,
|
|
1201
|
-
import: '@lynx-js/webpack-dev-transport/client'
|
|
1202
|
-
});
|
|
1203
|
-
}).end();
|
|
1204
|
-
chain.plugin(`${PLUGIN_NAME_TEMPLATE}-${entryName}`).use(LynxTemplatePlugin, [
|
|
1205
|
-
{
|
|
1206
|
-
filename: templateFilename,
|
|
1207
|
-
intermediate: lynxConfig.resolveIntermediateDir({
|
|
1208
|
-
entryName
|
|
1209
|
-
}),
|
|
1210
|
-
chunks: [
|
|
1211
|
-
mainThreadEntry,
|
|
1212
|
-
backgroundEntry
|
|
1213
|
-
],
|
|
1214
|
-
cssPlugins: [
|
|
1215
|
-
CSSPlugins.parserPlugins.removeFunctionWhiteSpace()
|
|
1216
|
-
],
|
|
1217
|
-
customCSSInheritanceList,
|
|
1218
|
-
debugInfoOutside,
|
|
1219
|
-
defaultDisplayLinear,
|
|
1220
|
-
enableAccessibilityElement,
|
|
1221
|
-
enableCSSInheritance,
|
|
1222
|
-
enableCSSInvalidation,
|
|
1223
|
-
enableCSSSelector,
|
|
1224
|
-
enableNewGesture,
|
|
1225
|
-
enableRemoveCSSScope,
|
|
1226
|
-
removeDescendantSelectorScope,
|
|
1227
|
-
targetSdkVersion,
|
|
1228
|
-
enableA11y: true
|
|
1229
|
-
}
|
|
1230
|
-
]).end();
|
|
2074
|
+
backgroundLayerRule.use(CHAIN_ID.USE.IGNORE_CSS).loader(node_path.resolve(__dirname, './loaders/ignore-css-loader')).end().uses.merge(uses).delete(CHAIN_ID.USE.MINI_CSS_EXTRACT).delete(CHAIN_ID.USE.LIGHTNINGCSS).delete(CHAIN_ID.USE.CSS).end().use(CHAIN_ID.USE.CSS).after(CHAIN_ID.USE.IGNORE_CSS).merge(cssLoaderRule).options(normalizeCssLoaderOptions(cssLoaderRule.options, true)).end();
|
|
1231
2075
|
}
|
|
1232
|
-
|
|
1233
|
-
|
|
2076
|
+
for (const ruleName of cssRules.filter((rule)=>chain.module.rules.has(rule))){
|
|
2077
|
+
const inlineRuleName = ruleName === CHAIN_ID.RULE.CSS ? CHAIN_ID.ONE_OF.CSS_INLINE : `${ruleName}-inline`;
|
|
2078
|
+
removeLightningCSS(chain.module.rule(ruleName).oneOf(inlineRuleName));
|
|
2079
|
+
}
|
|
2080
|
+
if (chain.module.rules.has(CHAIN_ID.RULE.FONT)) {
|
|
2081
|
+
const fontRule = chain.module.rule(CHAIN_ID.RULE.FONT);
|
|
2082
|
+
fontRule.oneOfs.clear();
|
|
2083
|
+
fontRule.type('asset/inline');
|
|
2084
|
+
}
|
|
2085
|
+
chain.plugin(CHAIN_ID.PLUGIN.MINI_CSS_EXTRACT).tap(([options])=>[
|
|
1234
2086
|
{
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
});
|
|
1240
|
-
},
|
|
2087
|
+
...options,
|
|
2088
|
+
enableRemoveCSSScope,
|
|
2089
|
+
enableCSSSelector,
|
|
2090
|
+
enableCSSInvalidation,
|
|
1241
2091
|
targetSdkVersion,
|
|
1242
|
-
|
|
2092
|
+
cssPlugins: [
|
|
2093
|
+
CSSPlugins.parserPlugins.removeFunctionWhiteSpace()
|
|
2094
|
+
]
|
|
1243
2095
|
}
|
|
1244
|
-
]).end();
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
enableSSR: options.enableSSR,
|
|
1254
|
-
isWeb
|
|
1255
|
-
}
|
|
1256
|
-
]);
|
|
2096
|
+
]).init((_, args)=>new CssExtractRspackPlugin(...args)).end().end();
|
|
2097
|
+
chain.module.when(void 0 === enableRemoveCSSScope, (module)=>module.rule('lynx.css.scoped').test(/\.css$/).resourceQuery({
|
|
2098
|
+
and: [
|
|
2099
|
+
/cssId/,
|
|
2100
|
+
{
|
|
2101
|
+
not: /common/
|
|
2102
|
+
}
|
|
2103
|
+
]
|
|
2104
|
+
}).sideEffects(false));
|
|
1257
2105
|
});
|
|
1258
2106
|
};
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
else imports.push(item.import);
|
|
1276
|
-
if (dependOn) if ('string' == typeof dependOn) chunks.unshift(dependOn);
|
|
1277
|
-
else chunks.unshift(...dependOn);
|
|
2107
|
+
const normalizeCssLoaderOptions = (options, exportOnlyLocals)=>{
|
|
2108
|
+
if (options.modules && exportOnlyLocals) {
|
|
2109
|
+
let { modules } = options;
|
|
2110
|
+
modules = true === modules ? {
|
|
2111
|
+
exportOnlyLocals: true
|
|
2112
|
+
} : 'string' == typeof modules ? {
|
|
2113
|
+
mode: modules,
|
|
2114
|
+
exportOnlyLocals: true
|
|
2115
|
+
} : {
|
|
2116
|
+
...modules,
|
|
2117
|
+
exportOnlyLocals: true
|
|
2118
|
+
};
|
|
2119
|
+
return {
|
|
2120
|
+
...options,
|
|
2121
|
+
modules
|
|
2122
|
+
};
|
|
1278
2123
|
}
|
|
1279
|
-
return
|
|
1280
|
-
chunks,
|
|
1281
|
-
imports
|
|
1282
|
-
};
|
|
2124
|
+
return options;
|
|
1283
2125
|
};
|
|
1284
2126
|
const applyGenerator = (api)=>{
|
|
1285
2127
|
api.modifyBundlerChain({
|
|
@@ -1291,6 +2133,21 @@ const applyGenerator = (api)=>{
|
|
|
1291
2133
|
}
|
|
1292
2134
|
});
|
|
1293
2135
|
};
|
|
2136
|
+
const applyResolve = (api)=>{
|
|
2137
|
+
api.modifyRspackConfig((config)=>{
|
|
2138
|
+
const resolve = config.resolve ??= {};
|
|
2139
|
+
const conditions = (resolve.conditionNames ?? []).filter((condition)=>'require' !== condition);
|
|
2140
|
+
if (!conditions.includes('module')) conditions.splice(conditions.indexOf('import') + 1, 0, 'module');
|
|
2141
|
+
resolve.byDependency = {
|
|
2142
|
+
...resolve.byDependency,
|
|
2143
|
+
esm: {
|
|
2144
|
+
...resolve.byDependency?.['esm'],
|
|
2145
|
+
conditionNames: conditions
|
|
2146
|
+
}
|
|
2147
|
+
};
|
|
2148
|
+
});
|
|
2149
|
+
};
|
|
2150
|
+
const DEV_LOGS_PATH = '/__dev_logs';
|
|
1294
2151
|
const RESET = '\x1b[0m';
|
|
1295
2152
|
const GRAY = '\x1b[90m';
|
|
1296
2153
|
const RED = '\x1b[31m';
|
|
@@ -1325,7 +2182,9 @@ const formatArg = (arg)=>{
|
|
|
1325
2182
|
if ('string' == typeof arg) return arg;
|
|
1326
2183
|
if ('object' == typeof arg && 'Error' === arg.__type) {
|
|
1327
2184
|
const err = arg;
|
|
1328
|
-
|
|
2185
|
+
const header = err.message ? `${err.name}: ${err.message}` : err.name;
|
|
2186
|
+
if (!err.stack) return header;
|
|
2187
|
+
return err.stack.startsWith(header) ? err.stack : `${header}\n${err.stack}`;
|
|
1329
2188
|
}
|
|
1330
2189
|
try {
|
|
1331
2190
|
return JSON.stringify(arg, null, 2);
|
|
@@ -1333,28 +2192,19 @@ const formatArg = (arg)=>{
|
|
|
1333
2192
|
return String(arg);
|
|
1334
2193
|
}
|
|
1335
2194
|
};
|
|
1336
|
-
|
|
1337
|
-
let logFilePath = '';
|
|
1338
|
-
const getLogFilePath = ()=>logFilePath;
|
|
1339
|
-
const ensureLogFile = ()=>{
|
|
1340
|
-
if (!logFile) {
|
|
1341
|
-
logFilePath = node_path.resolve(process.cwd(), '.dev-logs');
|
|
1342
|
-
logFile = node_fs.createWriteStream(logFilePath, {
|
|
1343
|
-
flags: 'w'
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
return logFile;
|
|
1347
|
-
};
|
|
1348
|
-
const writeLog = (entry)=>{
|
|
1349
|
-
const stream = ensureLogFile();
|
|
2195
|
+
const writeLog = (stream, entry)=>{
|
|
1350
2196
|
const color = LEVEL_COLORS[entry.level] || WHITE;
|
|
1351
2197
|
const label = LEVEL_LABELS[entry.level] || entry.level.toUpperCase();
|
|
1352
2198
|
const time = formatTimestamp(entry.timestamp);
|
|
1353
2199
|
const args = entry.args.map(formatArg).join(' ');
|
|
1354
2200
|
stream.write(`${GRAY}${time}${RESET} ${color}${label}${RESET} ${args}\n`);
|
|
1355
2201
|
};
|
|
1356
|
-
const createDevLoggerMiddleware = ()=>
|
|
1357
|
-
|
|
2202
|
+
const createDevLoggerMiddleware = (logFilePath)=>{
|
|
2203
|
+
const logFile = node_fs.createWriteStream(logFilePath, {
|
|
2204
|
+
flags: 'w'
|
|
2205
|
+
});
|
|
2206
|
+
return (req, res, next)=>{
|
|
2207
|
+
if ('OPTIONS' === req.method && req.url === DEV_LOGS_PATH) {
|
|
1358
2208
|
res.writeHead(204, {
|
|
1359
2209
|
'Access-Control-Allow-Origin': '*',
|
|
1360
2210
|
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
@@ -1363,7 +2213,7 @@ const createDevLoggerMiddleware = ()=>(req, res, next)=>{
|
|
|
1363
2213
|
res.end();
|
|
1364
2214
|
return;
|
|
1365
2215
|
}
|
|
1366
|
-
if ('POST' !== req.method ||
|
|
2216
|
+
if ('POST' !== req.method || req.url !== DEV_LOGS_PATH) return void next();
|
|
1367
2217
|
let body = '';
|
|
1368
2218
|
req.on('data', (chunk)=>{
|
|
1369
2219
|
body += chunk.toString();
|
|
@@ -1375,22 +2225,21 @@ const createDevLoggerMiddleware = ()=>(req, res, next)=>{
|
|
|
1375
2225
|
res.end();
|
|
1376
2226
|
try {
|
|
1377
2227
|
const { logs } = JSON.parse(body);
|
|
1378
|
-
for (const entry of logs)writeLog(entry);
|
|
2228
|
+
for (const entry of logs)writeLog(logFile, entry);
|
|
1379
2229
|
} catch {}
|
|
1380
2230
|
});
|
|
1381
2231
|
};
|
|
1382
|
-
|
|
2232
|
+
};
|
|
2233
|
+
const FALLBACK_ORIGIN = 'http://localhost:3000';
|
|
1383
2234
|
const applyDevLogger = (api)=>{
|
|
1384
2235
|
api.modifyRspackConfig((rspackConfig)=>{
|
|
1385
2236
|
if ('development' !== rspackConfig.mode) return rspackConfig;
|
|
1386
2237
|
const publicPath = rspackConfig.output?.publicPath;
|
|
1387
|
-
let
|
|
2238
|
+
let origin = FALLBACK_ORIGIN;
|
|
1388
2239
|
if ('string' == typeof publicPath && publicPath.startsWith('http')) try {
|
|
1389
|
-
|
|
1390
|
-
const logPort = Number(parsed.port || 80) + LOG_PORT_OFFSET;
|
|
1391
|
-
logUrl = `${parsed.protocol}//${parsed.hostname}:${logPort}/__dev_logs`;
|
|
2240
|
+
origin = new URL(publicPath).origin;
|
|
1392
2241
|
} catch {}
|
|
1393
|
-
|
|
2242
|
+
const logUrl = `${origin}${DEV_LOGS_PATH}`;
|
|
1394
2243
|
rspackConfig.plugins = rspackConfig.plugins || [];
|
|
1395
2244
|
rspackConfig.plugins.push({
|
|
1396
2245
|
name: 'lynx:angular:dev-logger-define',
|
|
@@ -1403,22 +2252,12 @@ const applyDevLogger = (api)=>{
|
|
|
1403
2252
|
});
|
|
1404
2253
|
return rspackConfig;
|
|
1405
2254
|
});
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
res.end();
|
|
1413
|
-
});
|
|
1414
|
-
});
|
|
1415
|
-
server.listen(logPort, '0.0.0.0', ()=>{
|
|
1416
|
-
console.log(`[dev-logger] Log server on :${logPort} → tail -f ${getLogFilePath()}`);
|
|
1417
|
-
});
|
|
1418
|
-
server.on('error', (err)=>{
|
|
1419
|
-
if ('EADDRINUSE' === err.code) server.listen(logPort + 1, '0.0.0.0');
|
|
1420
|
-
else console.warn('[dev-logger] Failed to start log server:', err.message);
|
|
1421
|
-
});
|
|
2255
|
+
const logFilePath = node_path.resolve(process.cwd(), '.dev-logs');
|
|
2256
|
+
api.onBeforeStartDevServer(({ server })=>{
|
|
2257
|
+
server.middlewares.use(createDevLoggerMiddleware(logFilePath));
|
|
2258
|
+
});
|
|
2259
|
+
api.onAfterStartDevServer(()=>{
|
|
2260
|
+
console.log(`[dev-logger] LynxLogger output: tail -f ${logFilePath}`);
|
|
1422
2261
|
});
|
|
1423
2262
|
};
|
|
1424
2263
|
const applySplitChunksRule = (api, options)=>{
|
|
@@ -1432,8 +2271,7 @@ const applySplitChunksRule = (api, options)=>{
|
|
|
1432
2271
|
});
|
|
1433
2272
|
return config;
|
|
1434
2273
|
});
|
|
1435
|
-
api.modifyRspackConfig((rspackConfig
|
|
1436
|
-
if ('lynx' !== environment.name) return rspackConfig;
|
|
2274
|
+
api.modifyRspackConfig((rspackConfig)=>{
|
|
1437
2275
|
rspackConfig.output = rspackConfig.output ?? {};
|
|
1438
2276
|
if (!options.experimental_isLazyBundle) rspackConfig.output.asyncChunks = false;
|
|
1439
2277
|
if (!rspackConfig.optimization) return rspackConfig;
|
|
@@ -1455,16 +2293,28 @@ const TAILWIND_CONFIG_FILES = [
|
|
|
1455
2293
|
'tailwind.config.mjs',
|
|
1456
2294
|
'tailwind.config.cjs'
|
|
1457
2295
|
];
|
|
2296
|
+
const isTailwind = (plugin)=>'function' == typeof plugin ? 'tailwindcss' === plugin.name : plugin?.postcssPlugin === 'tailwindcss';
|
|
1458
2297
|
const applyTailwind = (api)=>{
|
|
1459
2298
|
const configFile = findUp(TAILWIND_CONFIG_FILES, process.cwd());
|
|
1460
2299
|
if (!configFile) return;
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
2300
|
+
api.modifyRsbuildConfig((config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
|
|
2301
|
+
tools: {
|
|
2302
|
+
postcss: ({ postcssOptions }, { addPlugins })=>{
|
|
2303
|
+
if ('object' == typeof postcssOptions && postcssOptions.plugins?.some(isTailwind)) return;
|
|
2304
|
+
const tailwindcss = createRequire(configFile)('tailwindcss');
|
|
2305
|
+
addPlugins(tailwindcss({
|
|
2306
|
+
config: configFile
|
|
2307
|
+
}));
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
}));
|
|
1467
2311
|
};
|
|
2312
|
+
const DEPRECATED_OPTIONS = [
|
|
2313
|
+
'enableICU',
|
|
2314
|
+
'enableParallelElement',
|
|
2315
|
+
'pipelineSchedulerConfig'
|
|
2316
|
+
];
|
|
2317
|
+
const deprecatedOptionsIn = (options)=>DEPRECATED_OPTIONS.filter((name)=>options?.[name] !== void 0);
|
|
1468
2318
|
const normalizeOptions = (options)=>{
|
|
1469
2319
|
const defaultOptions = {
|
|
1470
2320
|
customCSSInheritanceList: void 0,
|
|
@@ -1474,37 +2324,43 @@ const normalizeOptions = (options)=>{
|
|
|
1474
2324
|
enableCSSInheritance: false,
|
|
1475
2325
|
enableCSSInvalidation: false,
|
|
1476
2326
|
enableCSSSelector: true,
|
|
1477
|
-
enableICU: false,
|
|
1478
2327
|
enableNewGesture: true,
|
|
1479
|
-
enableParallelElement: true,
|
|
1480
2328
|
defaultDisplayLinear: true,
|
|
1481
2329
|
enableRemoveCSSScope: false,
|
|
1482
2330
|
enableSSR: false,
|
|
1483
2331
|
pages: void 0,
|
|
1484
|
-
pipelineSchedulerConfig: 0x00010000,
|
|
1485
2332
|
targetSdkVersion: '3.2',
|
|
1486
2333
|
defaultOverflowVisible: true,
|
|
1487
2334
|
removeDescendantSelectorScope: false,
|
|
1488
2335
|
experimental_isLazyBundle: false
|
|
1489
2336
|
};
|
|
1490
|
-
|
|
2337
|
+
const normalized = Object.assign(defaultOptions, options);
|
|
2338
|
+
for (const name of DEPRECATED_OPTIONS)delete normalized[name];
|
|
2339
|
+
return normalized;
|
|
1491
2340
|
};
|
|
1492
2341
|
const pluginAngularLynx = (options)=>({
|
|
1493
2342
|
name: 'lynx:angular',
|
|
1494
2343
|
pre: [
|
|
1495
|
-
'lynx:rsbuild:plugin-api'
|
|
2344
|
+
'lynx:rsbuild:plugin-api',
|
|
2345
|
+
ANGULAR_CLI_CONTEXT_PLUGIN_NAME
|
|
1496
2346
|
],
|
|
1497
2347
|
setup: async (api)=>{
|
|
2348
|
+
for (const name of deprecatedOptionsIn(options))api.logger.warn(`pluginAngularLynx(): the \`${name}\` option has no effect and will be removed in a future release. Remove it from your config.`);
|
|
1498
2349
|
const normalizedOptions = normalizeOptions(options);
|
|
2350
|
+
const backgroundEntries = createBackgroundEntries({
|
|
2351
|
+
rootPath: api.context.rootPath
|
|
2352
|
+
});
|
|
1499
2353
|
applyCSS(api, normalizedOptions);
|
|
1500
2354
|
applyTailwind(api);
|
|
1501
|
-
|
|
2355
|
+
const appEntries = new Set();
|
|
2356
|
+
applyEntry(api, normalizedOptions, backgroundEntries, appEntries);
|
|
1502
2357
|
applyLayers(api);
|
|
1503
|
-
|
|
2358
|
+
applyResolve(api);
|
|
2359
|
+
const angularRules = applyAngularRules(api, normalizedOptions, backgroundEntries, appEntries);
|
|
1504
2360
|
applyGenerator(api);
|
|
1505
2361
|
applySplitChunksRule(api, normalizedOptions);
|
|
1506
2362
|
applyDevLogger(api);
|
|
1507
2363
|
await angularRules;
|
|
1508
2364
|
}
|
|
1509
2365
|
});
|
|
1510
|
-
export { pluginAngularLynx };
|
|
2366
|
+
export { pluginAngularCliContext, pluginAngularLynx };
|