@blotch/rsbuild-plugin-angular-lynx 22.2.2 → 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.
Files changed (47) hide show
  1. package/README.md +1 -1
  2. package/dist/544.js +21 -0
  3. package/dist/angular-rebuild-coordinator.d.ts +1 -1
  4. package/dist/angular.d.ts +3 -2
  5. package/dist/background-entry.d.ts +96 -0
  6. package/dist/client/background-hot-updates.d.ts +50 -0
  7. package/dist/client/background-hot-updates.js +77 -0
  8. package/dist/client/background-hot-updates.test.d.ts +1 -0
  9. package/dist/client/css-hot-update.cjs +9 -0
  10. package/dist/client/css-hot-update.d.ts +44 -0
  11. package/dist/client/css-hot-update.js +42 -0
  12. package/dist/client/css-hot-update.test.d.ts +1 -0
  13. package/dist/client/hmr-background.js +16 -0
  14. package/dist/client/hmr-main-thread.js +9 -0
  15. package/dist/client/hmr-protocol.d.ts +74 -0
  16. package/dist/client/main-thread-hot-updates.d.ts +40 -0
  17. package/dist/client/main-thread-hot-updates.js +78 -0
  18. package/dist/client/main-thread-hot-updates.test.d.ts +1 -0
  19. package/dist/client/testing/test-context.d.ts +16 -0
  20. package/dist/component-styles-cache.d.ts +5 -35
  21. package/dist/component-styles.d.ts +73 -0
  22. package/dist/component-styles.test.d.ts +1 -0
  23. package/dist/cross-thread-transform.d.ts +38 -0
  24. package/dist/cross-thread-transform.test.d.ts +1 -0
  25. package/dist/css.d.ts +2 -2
  26. package/dist/entry.d.ts +23 -2
  27. package/dist/hot-updates.d.ts +67 -0
  28. package/dist/hot-updates.test.d.ts +1 -0
  29. package/dist/index.js +718 -168
  30. package/dist/layers.d.ts +6 -4
  31. package/dist/logger/dev-logger-middleware.d.ts +13 -7
  32. package/dist/logger/dev-logger.d.ts +13 -0
  33. package/dist/polyfills.js +56 -0
  34. package/dist/polyfills.test.d.ts +1 -0
  35. package/dist/pure-classes.d.ts +27 -0
  36. package/dist/pure-classes.test.d.ts +1 -0
  37. package/dist/resolve.d.ts +19 -0
  38. package/dist/resolve.test.d.ts +1 -0
  39. package/dist/split-chunks.d.ts +2 -2
  40. package/dist/styles/blur-view.css +16 -0
  41. package/dist/transform-module.d.ts +43 -17
  42. package/dist/utils/angular/component-scope-id.d.ts +5 -3
  43. package/dist/utils/options.d.ts +40 -1
  44. package/package.json +1 -2
  45. package/dist/loaders/thread-globals-loader.d.ts +0 -8
  46. package/dist/loaders/thread-globals-loader.js +0 -6
  47. /package/dist/{loaders/thread-globals-loader.test.d.ts → background-entry.test.d.ts} +0 -0
package/dist/index.js CHANGED
@@ -1,19 +1,17 @@
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";
3
+ import node_path, { join, resolve as external_node_path_resolve } from "node:path";
4
4
  import { CSSPlugins, LynxEncodePlugin, LynxTemplatePlugin, WebEncodePlugin } from "@lynx-js/template-webpack-plugin";
5
+ import { createRequire } from "node:module";
6
+ import { fileURLToPath } from "node:url";
5
7
  import { RuntimeWrapperWebpackPlugin } from "@lynx-js/runtime-wrapper-webpack-plugin";
6
8
  import { RuntimeGlobals } from "@lynx-js/webpack-runtime-globals";
7
9
  import tiny_invariant from "tiny-invariant";
8
10
  import { createHash } from "node:crypto";
9
- import { fileURLToPath } from "node:url";
10
- import { createRequire } from "node:module";
11
11
  import { availableParallelism } from "node:os";
12
12
  import { workspaces } from "@angular-devkit/core";
13
13
  import { NodeJsSyncHost } from "@angular-devkit/core/node";
14
14
  import { access, constants } from "node:fs/promises";
15
- import node_http from "node:http";
16
- import { pluginTailwindCSS } from "rsbuild-plugin-tailwindcss";
17
15
  import * as __rspack_external_typescript from "typescript";
18
16
  import * as __rspack_external_node_path_c5b9b54f from "node:path";
19
17
  const ANGULAR_CLI_CONTEXT = Symbol.for('@blotch/rsbuild-plugin-angular-lynx:angular-cli-context');
@@ -90,19 +88,32 @@ const LAYERS = {
90
88
  };
91
89
  const applyLayers = (api)=>{
92
90
  api.modifyBundlerChain((chain)=>{
93
- chain.module.rule("typescript").oneOf(LAYERS.BACKGROUND).layer(LAYERS.BACKGROUND).test(/\.[cm]?[jt]sx?$/).use('builtin:swc-loader').loader('builtin:swc-loader').options({
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({
94
103
  jsc: {
95
- target: 'es2015',
96
- parser: {
97
- syntax: "typescript"
98
- }
99
- }
100
- }).end();
101
- 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({
102
- jsc: {
103
- target: 'es2019',
104
+ target,
104
105
  parser: {
105
106
  syntax: "typescript"
107
+ },
108
+ transform: {
109
+ optimizer: {
110
+ simplify: false,
111
+ globals: {
112
+ vars: {
113
+ __MAIN_THREAD__: String(isMainThread)
114
+ }
115
+ }
116
+ }
106
117
  }
107
118
  }
108
119
  }).end();
@@ -201,8 +212,9 @@ class AngularWebpackPlugin {
201
212
  name: `${this.constructor.name}:threadGlobals`,
202
213
  stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
203
214
  }, ()=>{
204
- for (const [name] of Object.entries(compilation.assets).filter(([n])=>n.endsWith('.js'))){
205
- const isMainThread = mainThreadChunkSet.has(name);
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;
206
218
  const prefix = `globalThis["__MAIN_THREAD__"]=${isMainThread};`;
207
219
  compilation.updateAsset(name, (old)=>new ConcatSource(prefix, old));
208
220
  }
@@ -236,6 +248,16 @@ class AngularWebpackPlugin {
236
248
  });
237
249
  });
238
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
+ }
239
261
  #updateMainThreadInfo(compilation, name) {
240
262
  const asset = compilation.getAsset(name);
241
263
  tiny_invariant(asset, `Should have main thread asset ${name}`);
@@ -249,9 +271,17 @@ const S_LYNX_CONFIG = Symbol.for('@lynx-js/rsbuild-plugin:config');
249
271
  const PLUGIN_NAME_TEMPLATE = 'lynx:template';
250
272
  const PLUGIN_NAME_RUNTIME_WRAPPER = 'lynx:runtime-wrapper';
251
273
  const PLUGIN_NAME_ANGULAR = 'lynx:angular';
252
- const applyEntry = (api, options)=>{
253
- const { customCSSInheritanceList, debugInfoOutside, defaultDisplayLinear, enableA11y, enableAccessibilityElement, enableCSSInheritance, enableCSSInvalidation, enableCSSSelector, enableNewGesture, enableRemoveCSSScope, removeDescendantSelectorScope, targetSdkVersion } = options;
254
- api.modifyBundlerChain((chain, { environment, isDev })=>{
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 })=>{
255
285
  const lynxConfig = api.useExposed(S_LYNX_CONFIG);
256
286
  if (!lynxConfig) throw new Error('No Lynx config exposed. `pluginLynx` has to be applied for the Lynx build engine to be configured.');
257
287
  const isLynx = 'lynx' === environment.name;
@@ -261,9 +291,19 @@ const applyEntry = (api, options)=>{
261
291
  const enabledLiveReload = isDev && !isWeb && false !== liveReload;
262
292
  const entries = chain.entryPoints.entries() ?? {};
263
293
  chain.entryPoints.clear();
294
+ const preEntry = new Set(environment.config.source.preEntry);
264
295
  const mainThreadChunks = [];
265
296
  for (const [entryName, entryPoint] of Object.entries(entries)){
266
- const { imports } = getChunks(entryName, entryPoint.values());
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));
267
307
  const templateFilename = lynxConfig.resolveBundleFilename({
268
308
  entryName,
269
309
  platform: environment.name
@@ -278,17 +318,22 @@ const applyEntry = (api, options)=>{
278
318
  mainThreadChunks.push(mainThreadName);
279
319
  chain.entry(mainThreadEntry).add({
280
320
  layer: LAYERS.MAIN_THREAD,
281
- import: imports,
321
+ import: mainThreadImports,
282
322
  filename: mainThreadName
323
+ }).when(enabledHMR, (entry)=>{
324
+ entry.prepend({
325
+ layer: LAYERS.MAIN_THREAD,
326
+ import: HMR_MAIN_THREAD_CLIENT
327
+ });
283
328
  }).end();
284
329
  chain.entry(backgroundEntry).add({
285
330
  layer: LAYERS.BACKGROUND,
286
- import: imports,
331
+ import: backgroundImports,
287
332
  filename: backgroundThreadName
288
333
  }).when(enabledHMR, (entry)=>{
289
334
  entry.prepend({
290
335
  layer: LAYERS.BACKGROUND,
291
- import: '@rspack/core/hot/dev-server'
336
+ import: HMR_BACKGROUND_CLIENT
292
337
  });
293
338
  }).when(enabledHMR || enabledLiveReload, (entry)=>{
294
339
  entry.prepend({
@@ -315,6 +360,7 @@ const applyEntry = (api, options)=>{
315
360
  customCSSInheritanceList,
316
361
  debugInfoOutside,
317
362
  defaultDisplayLinear,
363
+ defaultOverflowVisible,
318
364
  enableAccessibilityElement,
319
365
  enableCSSInheritance,
320
366
  enableCSSInvalidation,
@@ -327,6 +373,14 @@ const applyEntry = (api, options)=>{
327
373
  }
328
374
  ]).end();
329
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
+ }
330
384
  if (isLynx) {
331
385
  chain.plugin(PLUGIN_NAME_RUNTIME_WRAPPER).use(RuntimeWrapperWebpackPlugin, [
332
386
  {
@@ -622,68 +676,111 @@ const buildLynxSchemaSourceFileCache = (tsconfig, shouldInclude = ()=>true)=>{
622
676
  fileNames
623
677
  };
624
678
  };
625
- const generateComponentScopeId = (className, containingFile)=>{
626
- const hash = createHash('sha256').update(`${className}|${containingFile}`).digest('hex').slice(0, 10);
627
- return `l${hash}`;
628
- };
629
679
  const componentStyleSizeKey = (containingFile, stylesheetKey)=>`${containingFile}#${stylesheetKey}`;
630
680
  const forgetComponentStyleSizes = (componentStyleSizes, containingFile)=>{
631
681
  const prefix = componentStyleSizeKey(containingFile, '');
632
682
  for (const key of componentStyleSizes.keys())if (key.startsWith(prefix)) componentStyleSizes.delete(key);
633
683
  };
634
684
  const createTransformStylesheet = (params)=>{
635
- const { basePath, scopedCssCacheDir, componentStylesCache, componentScopeIds, onStylesheetWritten, componentStyleSizes } = params;
685
+ const { basePath, componentStyleSizes } = params;
636
686
  return async (data, containingFile, stylesheetFile, order, className)=>{
637
- const resolvedClassName = className ?? 'Component';
638
- const scopeId = generateComponentScopeId(resolvedClassName, containingFile);
639
- let componentStyles = componentStylesCache.get(containingFile);
640
- if (!componentStyles) {
641
- componentStyles = {
642
- imports: [],
643
- inlineStyles: [],
644
- scopeId,
645
- processedFiles: new Map()
646
- };
647
- componentStylesCache.set(containingFile, componentStyles);
648
- }
649
- const stylesheetKey = stylesheetFile ?? `__inline_${order}`;
650
- const previousPath = componentStyles.processedFiles.get(stylesheetKey);
651
- if (previousPath && !className) return '';
652
- componentStyleSizes?.set(componentStyleSizeKey(containingFile, stylesheetKey), {
687
+ const key = componentStyleSizeKey(containingFile, stylesheetFile ?? `__inline_${order}`);
688
+ if (componentStyleSizes && (className || !componentStyleSizes.has(key))) componentStyleSizes.set(key, {
653
689
  label: node_path.relative(basePath, stylesheetFile ?? containingFile).replace(/\\/g, '/'),
654
690
  size: Buffer.byteLength(data)
655
691
  });
656
- if (className || !componentScopeIds.has(containingFile)) componentScopeIds.set(containingFile, {
657
- className: resolvedClassName,
658
- scopeId
659
- });
660
- const scopedCss = data;
661
- const writeIfChanged = (filePath, content)=>{
662
- try {
663
- if (node_fs.readFileSync(filePath, 'utf-8') === content) return;
664
- } catch {}
665
- node_fs.writeFileSync(filePath, content);
666
- onStylesheetWritten?.(filePath);
667
- };
668
- let scopedPath;
669
- if (stylesheetFile) {
670
- const relName = node_path.relative(basePath, stylesheetFile);
671
- scopedPath = node_path.join(scopedCssCacheDir, `${relName.replace(/[/\\]/g, '__')}.__scoped_${scopeId}.css`);
672
- } else {
673
- const relDir = node_path.relative(basePath, node_path.dirname(containingFile));
674
- scopedPath = node_path.join(scopedCssCacheDir, `${relDir.replace(/[/\\]/g, '__')}__inline_${resolvedClassName}_${order}.__scoped_${scopeId}.css`);
692
+ return data;
693
+ };
694
+ };
695
+ const generateComponentScopeId = (className, containingFile)=>{
696
+ const hash = createHash('sha256').update(`${className}|${containingFile}`).digest('hex').slice(0, 10);
697
+ return `l${hash}`;
698
+ };
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
+ }
675
746
  }
676
- writeIfChanged(scopedPath, scopedCss);
677
- if (previousPath) {
678
- const idx = componentStyles.imports.indexOf(previousPath);
679
- if (idx >= 0) componentStyles.imports[idx] = scopedPath;
680
- else componentStyles.imports.push(scopedPath);
681
- if (previousPath !== scopedPath) try {
682
- node_fs.unlinkSync(previousPath);
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;
767
+ try {
768
+ current = node_fs.readFileSync(filePath, 'utf-8');
683
769
  } catch {}
684
- } else componentStyles.imports.push(scopedPath);
685
- componentStyles.processedFiles.set(stylesheetKey, scopedPath);
686
- return '';
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
687
784
  };
688
785
  };
689
786
  const isLynxUnknownElementMessage = (text)=>(text?.includes('is not a known element') || text?.includes("isn't a known property of")) ?? false;
@@ -723,12 +820,267 @@ const toAngularDiagnosticError = (message, severity)=>{
723
820
  error.hideStack = true;
724
821
  return error;
725
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
+ };
726
927
  const seedCompilationSourceFiles = (compilation, sourceFileCache)=>{
727
928
  const { sourceFiles } = compilation;
728
929
  if (!(sourceFiles instanceof Map)) return false;
729
930
  for (const [fileName, sourceFile] of sourceFileCache)sourceFiles.set(fileName, sourceFile);
730
931
  return true;
731
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
+ };
732
1084
  const MAIN_THREAD_DIRECTIVE = 'main thread';
733
1085
  const MAIN_THREAD_DIRECTIVE_ALT = 'main-thread';
734
1086
  const transformWorklets = (code, filename)=>{
@@ -775,10 +1127,10 @@ const isAlreadyWrapped = (node)=>{
775
1127
  return false;
776
1128
  };
777
1129
  const buildTransformedCode = (params)=>{
778
- const { resourcePath, componentStyles, scopeInfo } = params;
1130
+ const { resourcePath, stylesheets, root, hot } = params;
779
1131
  let code = params.code;
780
- if (componentStyles) {
781
- const { imports } = componentStyles;
1132
+ if (stylesheets) {
1133
+ const { imports } = stylesheets;
782
1134
  let importsString = '';
783
1135
  for(let i = 0; i < imports.length; ++i){
784
1136
  let relativeImport = node_path.relative(node_path.dirname(resourcePath), imports[i]);
@@ -787,8 +1139,19 @@ const buildTransformedCode = (params)=>{
787
1139
  }
788
1140
  code = importsString + code;
789
1141
  }
790
- if (scopeInfo) code += `\n;${scopeInfo.className}.ɵcmp.id = '${scopeInfo.scopeId}';\n`;
791
- return transformWorklets(code, resourcePath);
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
+ });
792
1155
  };
793
1156
  const applyAngularConfig = (api, buildOptions)=>{
794
1157
  const __dirname = node_path.dirname(fileURLToPath(import.meta.url));
@@ -805,9 +1168,9 @@ const applyAngularConfig = (api, buildOptions)=>{
805
1168
  ];
806
1169
  else config.source.preEntry ??= [];
807
1170
  config.source.preEntry.push(node_path.resolve(__dirname, './polyfills'));
808
- if (buildOptions.i18n.hasDefinedSourceLocale) config.source.preEntry.push('@angular/localize/init');
809
- const polyfills = buildOptions.polyfills;
810
- if (polyfills) config.source.preEntry.push(...polyfills);
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);
811
1174
  config.source.preEntry.push(...buildOptions.styles);
812
1175
  config.source.tsconfigPath = buildOptions.tsconfig;
813
1176
  config.source.define ??= {};
@@ -916,7 +1279,7 @@ const normalizeCacheOptions = (projectMetadata, workspaceRoot)=>{
916
1279
  cacheEnabled = !isCI;
917
1280
  break;
918
1281
  }
919
- const cacheBasePath = resolve(workspaceRoot, path);
1282
+ const cacheBasePath = external_node_path_resolve(workspaceRoot, path);
920
1283
  return {
921
1284
  enabled: cacheEnabled,
922
1285
  basePath: cacheBasePath,
@@ -1325,7 +1688,7 @@ const reportLynxDiagnostics = (diagnostics)=>{
1325
1688
  for (const w of cssWarnings)console.warn(` ${w.message}`);
1326
1689
  }
1327
1690
  };
1328
- const applyAngularRules = async (api, pluginOptions)=>{
1691
+ const applyAngularRules = async (api, pluginOptions, backgroundEntries, appEntries)=>{
1329
1692
  const cli = getAngularCliContext(api);
1330
1693
  const { basePath, workspace } = await getAngularWorkspace(cli?.workspaceRoot);
1331
1694
  if (pluginOptions.pages) {
@@ -1365,25 +1728,22 @@ const applyAngularRules = async (api, pluginOptions)=>{
1365
1728
  const tsconfig = buildOptions.tsconfig;
1366
1729
  const compilation = await createAngularCompilation(false, aot);
1367
1730
  const typeScriptFileCache = new Map();
1368
- const scopedCssCacheDir = node_path.join(basePath, 'node_modules', '.cache', 'angular-lynx-css');
1369
- node_fs.mkdirSync(scopedCssCacheDir, {
1731
+ const componentCssCacheDir = node_path.join(basePath, 'node_modules', '.cache', 'angular-lynx-css');
1732
+ node_fs.mkdirSync(componentCssCacheDir, {
1370
1733
  recursive: true
1371
1734
  });
1372
- const componentStylesCache = new Map();
1373
- const componentScopeIds = new Map();
1735
+ const moduleStylesheets = new Map();
1374
1736
  let componentResourceDependencies = new Map();
1375
1737
  const writtenStylesheets = new Set();
1376
1738
  let knownSourceFiles = new Set();
1739
+ const backgroundModules = new Set();
1740
+ let angularInputs = new Set();
1377
1741
  let angularDiagnostics = {
1378
1742
  errors: [],
1379
1743
  warnings: []
1380
1744
  };
1381
1745
  const transformStylesheet = createTransformStylesheet({
1382
1746
  basePath,
1383
- scopedCssCacheDir,
1384
- componentStylesCache,
1385
- componentScopeIds,
1386
- onStylesheetWritten: (filePath)=>writtenStylesheets.add(filePath),
1387
1747
  componentStyleSizes
1388
1748
  });
1389
1749
  const compileAngular = async (changedFiles)=>{
@@ -1420,8 +1780,22 @@ const applyAngularRules = async (api, pluginOptions)=>{
1420
1780
  try {
1421
1781
  for (const { filename, contents } of (await compilation.emitAffectedFiles())){
1422
1782
  const file = node_path.normalize(filename);
1423
- if (typeScriptFileCache.get(file) !== contents) changedOutputs.add(file);
1424
- typeScriptFileCache.set(file, contents);
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);
1425
1799
  }
1426
1800
  } catch (error) {
1427
1801
  throw new Error(`Angular failed to emit compiled output for "${tsconfig}". Original error: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
@@ -1429,6 +1803,8 @@ const applyAngularRules = async (api, pluginOptions)=>{
1429
1803
  for (const file of writtenStylesheets)changedOutputs.add(file);
1430
1804
  for (const file of changedFiles ?? [])if (!node_fs.existsSync(file)) {
1431
1805
  typeScriptFileCache.delete(file);
1806
+ backgroundModules.delete(file);
1807
+ moduleStylesheets.delete(file);
1432
1808
  forgetComponentStyleSizes(componentStyleSizes, file);
1433
1809
  }
1434
1810
  reportLynxDiagnostics([
@@ -1438,9 +1814,16 @@ const applyAngularRules = async (api, pluginOptions)=>{
1438
1814
  ...scanSourcesForUnsupportedCss(fileNames)
1439
1815
  ]);
1440
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
+ ]);
1441
1824
  return {
1442
1825
  changedOutputs,
1443
- inputFiles: result.referencedFiles.map((file)=>node_path.normalize(file))
1826
+ inputFiles
1444
1827
  };
1445
1828
  };
1446
1829
  const coordinator = createAngularRebuildCoordinator({
@@ -1460,46 +1843,199 @@ const applyAngularRules = async (api, pluginOptions)=>{
1460
1843
  let compilationClosed = false;
1461
1844
  api.onBeforeEnvironmentCompile(async ({ environment, isWatch })=>{
1462
1845
  const compiler = compilersByEnvironment.get(environment.name);
1463
- const outdatedFiles = await coordinator.prepare(environment.name, [
1846
+ const changedFiles = [
1464
1847
  ...compiler?.modifiedFiles ?? [],
1465
1848
  ...compiler?.removedFiles ?? []
1466
- ]);
1467
- if (compiler && outdatedFiles.size > 0) compiler.modifiedFiles = new Set([
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([
1468
1857
  ...compiler.modifiedFiles ?? [],
1469
- ...outdatedFiles
1858
+ ...outdatedFiles,
1859
+ ...changedEntries
1470
1860
  ]);
1471
1861
  if (!isWatch && !compilationClosed) {
1472
1862
  compilationClosed = true;
1473
1863
  await compilation.close?.();
1474
1864
  }
1475
1865
  });
1476
- api.transform({
1477
- test: /\.[cm]?[jt]sx?$/
1478
- }, async (context)=>{
1866
+ const transformModule = async (context, background)=>{
1867
+ const hot = hotUpdatesEnabled(context.environment);
1479
1868
  const isJs = /\.[cm]?js$/.test(context.resourcePath);
1480
1869
  if (isJs) {
1481
1870
  const contents = await javascriptTransformer.transformData(context.resourcePath, context.code, {
1482
1871
  skipLinker: false,
1483
1872
  sideEffects: ()=>Promise.resolve(false)
1484
1873
  });
1874
+ const code = transformCrossThread(transformWorklets(Buffer.from(contents).toString(), context.resourcePath), context.resourcePath, {
1875
+ root: api.context.rootPath
1876
+ });
1877
+ if (!background) return {
1878
+ code
1879
+ };
1880
+ const wrapped = wrapPureClasses(code, context.resourcePath);
1485
1881
  return {
1486
- code: transformWorklets(Buffer.from(contents).toString(), context.resourcePath)
1882
+ code: hot && backgroundEntries.isEntryFile(context.resourcePath) ? addEntryHotAccept(wrapped) : wrapped
1487
1883
  };
1488
1884
  }
1489
1885
  const content = typeScriptFileCache.get(context.resourcePath);
1490
1886
  if (!content) throw new Error(`No compiled output found for ${context.resourcePath}`);
1491
1887
  for (const dependency of componentResourceDependencies.get(context.resourcePath) ?? [])context.addDependency(dependency);
1492
- const code = 'string' == typeof content ? content : Buffer.from(content).toString();
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
1897
+ });
1898
+ if (!background) return {
1899
+ code
1900
+ };
1493
1901
  return {
1494
- code: buildTransformedCode({
1495
- code,
1496
- resourcePath: context.resourcePath,
1497
- componentStyles: componentStylesCache.get(context.resourcePath),
1498
- scopeInfo: componentScopeIds.get(context.resourcePath)
1499
- })
1902
+ code: wrapPureClasses(Buffer.from(await javascriptTransformer.transformData(context.resourcePath, code, {
1903
+ skipLinker: true,
1904
+ sideEffects: ()=>Promise.resolve(false)
1905
+ })).toString(), context.resourcePath)
1500
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
1501
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;
2021
+ }
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;
2033
+ }
1502
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));
1503
2039
  const applyCSS = (api, options)=>{
1504
2040
  const { enableRemoveCSSScope, enableCSSSelector, enableCSSInvalidation, targetSdkVersion } = options;
1505
2041
  api.modifyRsbuildConfig((config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
@@ -1525,23 +2061,23 @@ const applyCSS = (api, options)=>{
1525
2061
  const mainRule = rule.oneOf(mainRuleName);
1526
2062
  const parentRuleEntries = rule.entries();
1527
2063
  removeLightningCSS(mainRule);
1528
- mainRule.issuerLayer(LAYERS.BACKGROUND).use(CHAIN_ID.USE.MINI_CSS_EXTRACT).loader(CssExtractRspackPlugin.loader).end();
2064
+ mainRule.issuerLayer(LAYERS.MAIN_THREAD).use(CHAIN_ID.USE.MINI_CSS_EXTRACT).loader(CssExtractRspackPlugin.loader).end();
1529
2065
  const uses = mainRule.uses.entries() ?? {};
1530
2066
  const ruleEntries = mainRule.entries();
1531
2067
  const cssLoader = uses[CHAIN_ID.USE.CSS];
1532
2068
  if (!cssLoader) continue;
1533
2069
  const cssLoaderRule = cssLoader.entries();
1534
- const mainThreadLayerRule = chain.module.rule(`${ruleName}:${LAYERS.MAIN_THREAD}`).test(parentRuleEntries.test).merge(ruleEntries).issuerLayer(LAYERS.MAIN_THREAD);
1535
- if (void 0 !== parentRuleEntries.dependency) mainThreadLayerRule.merge({
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({
1536
2072
  dependency: parentRuleEntries.dependency
1537
2073
  });
1538
- 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();
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();
1539
2075
  }
1540
2076
  for (const ruleName of cssRules.filter((rule)=>chain.module.rules.has(rule))){
1541
2077
  const inlineRuleName = ruleName === CHAIN_ID.RULE.CSS ? CHAIN_ID.ONE_OF.CSS_INLINE : `${ruleName}-inline`;
1542
2078
  removeLightningCSS(chain.module.rule(ruleName).oneOf(inlineRuleName));
1543
2079
  }
1544
- if ('lynx' === environment.name && chain.module.rules.has(CHAIN_ID.RULE.FONT)) {
2080
+ if (chain.module.rules.has(CHAIN_ID.RULE.FONT)) {
1545
2081
  const fontRule = chain.module.rule(CHAIN_ID.RULE.FONT);
1546
2082
  fontRule.oneOfs.clear();
1547
2083
  fontRule.type('asset/inline');
@@ -1597,6 +2133,21 @@ const applyGenerator = (api)=>{
1597
2133
  }
1598
2134
  });
1599
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';
1600
2151
  const RESET = '\x1b[0m';
1601
2152
  const GRAY = '\x1b[90m';
1602
2153
  const RED = '\x1b[31m';
@@ -1631,7 +2182,9 @@ const formatArg = (arg)=>{
1631
2182
  if ('string' == typeof arg) return arg;
1632
2183
  if ('object' == typeof arg && 'Error' === arg.__type) {
1633
2184
  const err = arg;
1634
- return err.stack || `${err.name}: ${err.message}`;
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}`;
1635
2188
  }
1636
2189
  try {
1637
2190
  return JSON.stringify(arg, null, 2);
@@ -1639,28 +2192,19 @@ const formatArg = (arg)=>{
1639
2192
  return String(arg);
1640
2193
  }
1641
2194
  };
1642
- let logFile = null;
1643
- let logFilePath = '';
1644
- const getLogFilePath = ()=>logFilePath;
1645
- const ensureLogFile = ()=>{
1646
- if (!logFile) {
1647
- logFilePath = node_path.resolve(process.cwd(), '.dev-logs');
1648
- logFile = node_fs.createWriteStream(logFilePath, {
1649
- flags: 'w'
1650
- });
1651
- }
1652
- return logFile;
1653
- };
1654
- const writeLog = (entry)=>{
1655
- const stream = ensureLogFile();
2195
+ const writeLog = (stream, entry)=>{
1656
2196
  const color = LEVEL_COLORS[entry.level] || WHITE;
1657
2197
  const label = LEVEL_LABELS[entry.level] || entry.level.toUpperCase();
1658
2198
  const time = formatTimestamp(entry.timestamp);
1659
2199
  const args = entry.args.map(formatArg).join(' ');
1660
2200
  stream.write(`${GRAY}${time}${RESET} ${color}${label}${RESET} ${args}\n`);
1661
2201
  };
1662
- const createDevLoggerMiddleware = ()=>(req, res, next)=>{
1663
- if ('OPTIONS' === req.method && '/__dev_logs' === req.url) {
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) {
1664
2208
  res.writeHead(204, {
1665
2209
  'Access-Control-Allow-Origin': '*',
1666
2210
  'Access-Control-Allow-Methods': 'POST, OPTIONS',
@@ -1669,7 +2213,7 @@ const createDevLoggerMiddleware = ()=>(req, res, next)=>{
1669
2213
  res.end();
1670
2214
  return;
1671
2215
  }
1672
- if ('POST' !== req.method || '/__dev_logs' !== req.url) return void next();
2216
+ if ('POST' !== req.method || req.url !== DEV_LOGS_PATH) return void next();
1673
2217
  let body = '';
1674
2218
  req.on('data', (chunk)=>{
1675
2219
  body += chunk.toString();
@@ -1681,22 +2225,21 @@ const createDevLoggerMiddleware = ()=>(req, res, next)=>{
1681
2225
  res.end();
1682
2226
  try {
1683
2227
  const { logs } = JSON.parse(body);
1684
- for (const entry of logs)writeLog(entry);
2228
+ for (const entry of logs)writeLog(logFile, entry);
1685
2229
  } catch {}
1686
2230
  });
1687
2231
  };
1688
- const LOG_PORT_OFFSET = 1;
2232
+ };
2233
+ const FALLBACK_ORIGIN = 'http://localhost:3000';
1689
2234
  const applyDevLogger = (api)=>{
1690
2235
  api.modifyRspackConfig((rspackConfig)=>{
1691
2236
  if ('development' !== rspackConfig.mode) return rspackConfig;
1692
2237
  const publicPath = rspackConfig.output?.publicPath;
1693
- let logUrl = '';
2238
+ let origin = FALLBACK_ORIGIN;
1694
2239
  if ('string' == typeof publicPath && publicPath.startsWith('http')) try {
1695
- const parsed = new URL(publicPath);
1696
- const logPort = Number(parsed.port || 80) + LOG_PORT_OFFSET;
1697
- logUrl = `${parsed.protocol}//${parsed.hostname}:${logPort}/__dev_logs`;
2240
+ origin = new URL(publicPath).origin;
1698
2241
  } catch {}
1699
- if (!logUrl) logUrl = `http://localhost:${3000 + LOG_PORT_OFFSET}/__dev_logs`;
2242
+ const logUrl = `${origin}${DEV_LOGS_PATH}`;
1700
2243
  rspackConfig.plugins = rspackConfig.plugins || [];
1701
2244
  rspackConfig.plugins.push({
1702
2245
  name: 'lynx:angular:dev-logger-define',
@@ -1709,22 +2252,12 @@ const applyDevLogger = (api)=>{
1709
2252
  });
1710
2253
  return rspackConfig;
1711
2254
  });
1712
- api.onAfterStartDevServer(({ port })=>{
1713
- const logPort = port + LOG_PORT_OFFSET;
1714
- const middleware = createDevLoggerMiddleware();
1715
- const server = node_http.createServer((req, res)=>{
1716
- middleware(req, res, ()=>{
1717
- res.writeHead(404);
1718
- res.end();
1719
- });
1720
- });
1721
- server.listen(logPort, '0.0.0.0', ()=>{
1722
- console.log(`[dev-logger] Log server on :${logPort} → tail -f ${getLogFilePath()}`);
1723
- });
1724
- server.on('error', (err)=>{
1725
- if ('EADDRINUSE' === err.code) server.listen(logPort + 1, '0.0.0.0');
1726
- else console.warn('[dev-logger] Failed to start log server:', err.message);
1727
- });
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}`);
1728
2261
  });
1729
2262
  };
1730
2263
  const applySplitChunksRule = (api, options)=>{
@@ -1760,16 +2293,28 @@ const TAILWIND_CONFIG_FILES = [
1760
2293
  'tailwind.config.mjs',
1761
2294
  'tailwind.config.cjs'
1762
2295
  ];
2296
+ const isTailwind = (plugin)=>'function' == typeof plugin ? 'tailwindcss' === plugin.name : plugin?.postcssPlugin === 'tailwindcss';
1763
2297
  const applyTailwind = (api)=>{
1764
2298
  const configFile = findUp(TAILWIND_CONFIG_FILES, process.cwd());
1765
2299
  if (!configFile) return;
1766
- pluginTailwindCSS({
1767
- config: configFile,
1768
- exclude: [
1769
- /[\\/]node_modules[\\/]/
1770
- ]
1771
- }).setup(api);
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
+ }));
1772
2311
  };
2312
+ const DEPRECATED_OPTIONS = [
2313
+ 'enableICU',
2314
+ 'enableParallelElement',
2315
+ 'pipelineSchedulerConfig'
2316
+ ];
2317
+ const deprecatedOptionsIn = (options)=>DEPRECATED_OPTIONS.filter((name)=>options?.[name] !== void 0);
1773
2318
  const normalizeOptions = (options)=>{
1774
2319
  const defaultOptions = {
1775
2320
  customCSSInheritanceList: void 0,
@@ -1779,20 +2324,19 @@ const normalizeOptions = (options)=>{
1779
2324
  enableCSSInheritance: false,
1780
2325
  enableCSSInvalidation: false,
1781
2326
  enableCSSSelector: true,
1782
- enableICU: false,
1783
2327
  enableNewGesture: true,
1784
- enableParallelElement: true,
1785
2328
  defaultDisplayLinear: true,
1786
2329
  enableRemoveCSSScope: false,
1787
2330
  enableSSR: false,
1788
2331
  pages: void 0,
1789
- pipelineSchedulerConfig: 0x00010000,
1790
2332
  targetSdkVersion: '3.2',
1791
2333
  defaultOverflowVisible: true,
1792
2334
  removeDescendantSelectorScope: false,
1793
2335
  experimental_isLazyBundle: false
1794
2336
  };
1795
- return Object.assign(defaultOptions, options);
2337
+ const normalized = Object.assign(defaultOptions, options);
2338
+ for (const name of DEPRECATED_OPTIONS)delete normalized[name];
2339
+ return normalized;
1796
2340
  };
1797
2341
  const pluginAngularLynx = (options)=>({
1798
2342
  name: 'lynx:angular',
@@ -1801,12 +2345,18 @@ const pluginAngularLynx = (options)=>({
1801
2345
  ANGULAR_CLI_CONTEXT_PLUGIN_NAME
1802
2346
  ],
1803
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.`);
1804
2349
  const normalizedOptions = normalizeOptions(options);
2350
+ const backgroundEntries = createBackgroundEntries({
2351
+ rootPath: api.context.rootPath
2352
+ });
1805
2353
  applyCSS(api, normalizedOptions);
1806
2354
  applyTailwind(api);
1807
- applyEntry(api, normalizedOptions);
2355
+ const appEntries = new Set();
2356
+ applyEntry(api, normalizedOptions, backgroundEntries, appEntries);
1808
2357
  applyLayers(api);
1809
- const angularRules = applyAngularRules(api, normalizedOptions);
2358
+ applyResolve(api);
2359
+ const angularRules = applyAngularRules(api, normalizedOptions, backgroundEntries, appEntries);
1810
2360
  applyGenerator(api);
1811
2361
  applySplitChunksRule(api, normalizedOptions);
1812
2362
  applyDevLogger(api);