module-federation-angular-adapter 0.2200.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +115 -0
  3. package/builders.json +15 -0
  4. package/collection.json +27 -0
  5. package/generators.json +12 -0
  6. package/migration-collection.json +6 -0
  7. package/package.json +69 -0
  8. package/src/builders/build/builder.d.ts +7 -0
  9. package/src/builders/build/builder.d.ts.map +1 -0
  10. package/src/builders/build/builder.js +413 -0
  11. package/src/builders/build/federation-build-notifier.d.ts +70 -0
  12. package/src/builders/build/federation-build-notifier.d.ts.map +1 -0
  13. package/src/builders/build/federation-build-notifier.js +186 -0
  14. package/src/builders/build/get-externals.d.ts +18 -0
  15. package/src/builders/build/get-externals.d.ts.map +1 -0
  16. package/src/builders/build/get-externals.js +19 -0
  17. package/src/builders/build/i18n.d.ts +21 -0
  18. package/src/builders/build/i18n.d.ts.map +1 -0
  19. package/src/builders/build/i18n.js +73 -0
  20. package/src/builders/build/schema.d.ts +35 -0
  21. package/src/builders/build/schema.json +93 -0
  22. package/src/builders/build/setup-builder-env-variables.d.ts +1 -0
  23. package/src/builders/build/setup-builder-env-variables.d.ts.map +1 -0
  24. package/src/builders/build/setup-builder-env-variables.js +9 -0
  25. package/src/builders/build/update-index-html.d.ts +5 -0
  26. package/src/builders/build/update-index-html.d.ts.map +1 -0
  27. package/src/builders/build/update-index-html.js +33 -0
  28. package/src/builders/remote/assets.d.ts +14 -0
  29. package/src/builders/remote/assets.d.ts.map +1 -0
  30. package/src/builders/remote/assets.js +49 -0
  31. package/src/builders/remote/builder.d.ts +13 -0
  32. package/src/builders/remote/builder.d.ts.map +1 -0
  33. package/src/builders/remote/builder.js +153 -0
  34. package/src/builders/remote/change-watcher.d.ts +10 -0
  35. package/src/builders/remote/change-watcher.d.ts.map +1 -0
  36. package/src/builders/remote/change-watcher.js +35 -0
  37. package/src/builders/remote/infer-config-path.d.ts +2 -0
  38. package/src/builders/remote/infer-config-path.d.ts.map +1 -0
  39. package/src/builders/remote/infer-config-path.js +10 -0
  40. package/src/builders/remote/resolve-ng-options.d.ts +24 -0
  41. package/src/builders/remote/resolve-ng-options.d.ts.map +1 -0
  42. package/src/builders/remote/resolve-ng-options.js +28 -0
  43. package/src/builders/remote/schema.d.ts +26 -0
  44. package/src/builders/remote/schema.json +116 -0
  45. package/src/config/angular-locales.d.ts +6 -0
  46. package/src/config/angular-locales.d.ts.map +1 -0
  47. package/src/config/angular-locales.js +23 -0
  48. package/src/config/angular-skip-list.d.ts +3 -0
  49. package/src/config/angular-skip-list.d.ts.map +1 -0
  50. package/src/config/angular-skip-list.js +23 -0
  51. package/src/config/with-module-federation.d.ts +72 -0
  52. package/src/config/with-module-federation.d.ts.map +1 -0
  53. package/src/config/with-module-federation.js +72 -0
  54. package/src/config.d.ts +4 -0
  55. package/src/config.d.ts.map +1 -0
  56. package/src/config.js +3 -0
  57. package/src/generators/native-federation/files/src/index.ts__template__ +1 -0
  58. package/src/generators/native-federation/generator.d.ts +4 -0
  59. package/src/generators/native-federation/generator.d.ts.map +1 -0
  60. package/src/generators/native-federation/generator.js +45 -0
  61. package/src/generators/native-federation/schema.d.ts +5 -0
  62. package/src/generators/native-federation/schema.json +29 -0
  63. package/src/index.d.ts +82 -0
  64. package/src/index.d.ts.map +1 -0
  65. package/src/index.js +132 -0
  66. package/src/internal.d.ts +2 -0
  67. package/src/internal.d.ts.map +1 -0
  68. package/src/internal.js +1 -0
  69. package/src/schematics/appbuilder/schema.d.ts +3 -0
  70. package/src/schematics/appbuilder/schema.json +17 -0
  71. package/src/schematics/appbuilder/schematic.d.ts +5 -0
  72. package/src/schematics/appbuilder/schematic.d.ts.map +1 -0
  73. package/src/schematics/appbuilder/schematic.js +80 -0
  74. package/src/schematics/init/files/federation.config.mjs__tmpl__ +35 -0
  75. package/src/schematics/init/schema.d.ts +5 -0
  76. package/src/schematics/init/schema.json +30 -0
  77. package/src/schematics/init/schematic.d.ts +6 -0
  78. package/src/schematics/init/schematic.d.ts.map +1 -0
  79. package/src/schematics/init/schematic.js +38 -0
  80. package/src/schematics/init/steps/add-dependencies.d.ts +3 -0
  81. package/src/schematics/init/steps/add-dependencies.d.ts.map +1 -0
  82. package/src/schematics/init/steps/add-dependencies.js +25 -0
  83. package/src/schematics/init/steps/generate-federation-config.d.ts +4 -0
  84. package/src/schematics/init/steps/generate-federation-config.d.ts.map +1 -0
  85. package/src/schematics/init/steps/generate-federation-config.js +15 -0
  86. package/src/schematics/init/steps/generate-remote-map.d.ts +2 -0
  87. package/src/schematics/init/steps/generate-remote-map.d.ts.map +1 -0
  88. package/src/schematics/init/steps/generate-remote-map.js +20 -0
  89. package/src/schematics/init/steps/make-main-async.d.ts +4 -0
  90. package/src/schematics/init/steps/make-main-async.d.ts.map +1 -0
  91. package/src/schematics/init/steps/make-main-async.js +35 -0
  92. package/src/schematics/init/steps/normalize-options.d.ts +20 -0
  93. package/src/schematics/init/steps/normalize-options.d.ts.map +1 -0
  94. package/src/schematics/init/steps/normalize-options.js +64 -0
  95. package/src/schematics/init/steps/update-package-json.d.ts +3 -0
  96. package/src/schematics/init/steps/update-package-json.d.ts.map +1 -0
  97. package/src/schematics/init/steps/update-package-json.js +19 -0
  98. package/src/schematics/init/steps/update-polyfills.d.ts +3 -0
  99. package/src/schematics/init/steps/update-polyfills.d.ts.map +1 -0
  100. package/src/schematics/init/steps/update-polyfills.js +21 -0
  101. package/src/schematics/init/steps/update-workspace-config.d.ts +4 -0
  102. package/src/schematics/init/steps/update-workspace-config.d.ts.map +1 -0
  103. package/src/schematics/init/steps/update-workspace-config.js +76 -0
  104. package/src/schematics/remove/schema.d.ts +3 -0
  105. package/src/schematics/remove/schema.json +17 -0
  106. package/src/schematics/remove/schematic.d.ts +5 -0
  107. package/src/schematics/remove/schematic.d.ts.map +1 -0
  108. package/src/schematics/remove/schematic.js +106 -0
  109. package/src/tools/esbuild/angular-bundler.d.ts +10 -0
  110. package/src/tools/esbuild/angular-bundler.d.ts.map +1 -0
  111. package/src/tools/esbuild/angular-bundler.js +134 -0
  112. package/src/tools/esbuild/create-awaitable-compiler-plugin.d.ts +6 -0
  113. package/src/tools/esbuild/create-awaitable-compiler-plugin.d.ts.map +1 -0
  114. package/src/tools/esbuild/create-awaitable-compiler-plugin.js +29 -0
  115. package/src/tools/esbuild/create-federation-tsconfig.d.ts +7 -0
  116. package/src/tools/esbuild/create-federation-tsconfig.d.ts.map +1 -0
  117. package/src/tools/esbuild/create-federation-tsconfig.js +46 -0
  118. package/src/tools/esbuild/shared-mappings-plugin.d.ts +4 -0
  119. package/src/tools/esbuild/shared-mappings-plugin.d.ts.map +1 -0
  120. package/src/tools/esbuild/shared-mappings-plugin.js +33 -0
  121. package/src/tools/mf/build-for-federation.d.ts +70 -0
  122. package/src/tools/mf/build-for-federation.d.ts.map +1 -0
  123. package/src/tools/mf/build-for-federation.js +75 -0
  124. package/src/tools/mf/federation-entry-points.d.ts +23 -0
  125. package/src/tools/mf/federation-entry-points.d.ts.map +1 -0
  126. package/src/tools/mf/federation-entry-points.js +13 -0
  127. package/src/tools/mf/federation-plugin.d.ts +11 -0
  128. package/src/tools/mf/federation-plugin.d.ts.map +1 -0
  129. package/src/tools/mf/federation-plugin.js +12 -0
  130. package/src/tools/mf/federation-side-build.d.ts +21 -0
  131. package/src/tools/mf/federation-side-build.d.ts.map +1 -0
  132. package/src/tools/mf/federation-side-build.js +27 -0
  133. package/src/tools/mf/to-plugin-config.d.ts +37 -0
  134. package/src/tools/mf/to-plugin-config.d.ts.map +1 -0
  135. package/src/tools/mf/to-plugin-config.js +33 -0
  136. package/src/utils/check-for-invalid-imports.d.ts +2 -0
  137. package/src/utils/check-for-invalid-imports.d.ts.map +1 -0
  138. package/src/utils/check-for-invalid-imports.js +29 -0
  139. package/src/utils/normalize-build-options.d.ts +22 -0
  140. package/src/utils/normalize-build-options.d.ts.map +1 -0
  141. package/src/utils/normalize-build-options.js +45 -0
  142. package/src/utils/normalize-context-options.d.ts +24 -0
  143. package/src/utils/normalize-context-options.d.ts.map +1 -0
  144. package/src/utils/normalize-context-options.js +18 -0
@@ -0,0 +1,18 @@
1
+ import { type SharedConfig } from '../../index.js';
2
+ /**
3
+ * MF equivalent of NF's `getExternals` (host path, M1.5): the packages the
4
+ * Angular app build must mark `external` so they resolve from the shared scope
5
+ * (es-module-shims import map, finding #6) instead of being bundled. For a pure
6
+ * host this is exactly the shared singleton set.
7
+ *
8
+ * Mirrors NF's trivial `[...Object.keys(shared), ...sharedMappings, ...externals]`,
9
+ * MF-shaped: the keys of the MF `shared` map (+ any extra explicit externals).
10
+ *
11
+ * ⚠️ The builder call-site swap (replacing `getExternals(normalized.config)` at
12
+ * `builder.ts:297`) is performed in **M2.1**, not here: that line and
13
+ * `buildForFederation` (`builder.ts:425`) consume the *same* `normalized.config`,
14
+ * so the externals source and the side-build's `shared` must switch to MF
15
+ * together — otherwise the host externalizes deps nothing provides.
16
+ */
17
+ export declare function getHostExternals(shared?: SharedConfig, extraExternals?: string[]): string[];
18
+ //# sourceMappingURL=get-externals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-externals.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/get-externals.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,GAAE,YAAqC,EAC7C,cAAc,GAAE,MAAM,EAAO,GAC5B,MAAM,EAAE,CAEV"}
@@ -0,0 +1,19 @@
1
+ import { DEFAULT_ANGULAR_SHARED } from '../../index.js';
2
+ /**
3
+ * MF equivalent of NF's `getExternals` (host path, M1.5): the packages the
4
+ * Angular app build must mark `external` so they resolve from the shared scope
5
+ * (es-module-shims import map, finding #6) instead of being bundled. For a pure
6
+ * host this is exactly the shared singleton set.
7
+ *
8
+ * Mirrors NF's trivial `[...Object.keys(shared), ...sharedMappings, ...externals]`,
9
+ * MF-shaped: the keys of the MF `shared` map (+ any extra explicit externals).
10
+ *
11
+ * ⚠️ The builder call-site swap (replacing `getExternals(normalized.config)` at
12
+ * `builder.ts:297`) is performed in **M2.1**, not here: that line and
13
+ * `buildForFederation` (`builder.ts:425`) consume the *same* `normalized.config`,
14
+ * so the externals source and the side-build's `shared` must switch to MF
15
+ * together — otherwise the host externalizes deps nothing provides.
16
+ */
17
+ export function getHostExternals(shared = DEFAULT_ANGULAR_SHARED, extraExternals = []) {
18
+ return [...new Set([...Object.keys(shared), ...extraExternals])];
19
+ }
@@ -0,0 +1,21 @@
1
+ import type { BuilderContext } from '@angular-devkit/architect';
2
+ import type { FederationInfo } from '@softarc/native-federation';
3
+ type LocaleTranslation = string | string[];
4
+ type LocaleObject = {
5
+ translation: LocaleTranslation;
6
+ baseHref?: string;
7
+ subPath?: string;
8
+ };
9
+ export type I18nConfig = {
10
+ sourceLocale: string | SourceLocaleObject;
11
+ locales: Record<string, LocaleTranslation | LocaleObject>;
12
+ };
13
+ type SourceLocaleObject = {
14
+ code: string;
15
+ baseHref?: string;
16
+ subPath?: string;
17
+ };
18
+ export declare function getI18nConfig(context: BuilderContext): Promise<I18nConfig | undefined>;
19
+ export declare function translateFederationArtifacts(i18n: I18nConfig, localize: boolean | string[], outputPath: string, federationResult: FederationInfo): Promise<void>;
20
+ export {};
21
+ //# sourceMappingURL=i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAKhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAMjE,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAE3C,KAAK,YAAY,GAAG;IAClB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,CAAC;CAC3D,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAO5F;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,EAC5B,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,cAAc,iBAiDjC"}
@@ -0,0 +1,73 @@
1
+ import { logger } from '@softarc/native-federation/internal';
2
+ import { execSync } from 'child_process';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+ export async function getI18nConfig(context) {
6
+ const workspaceConfig = (await context.getProjectMetadata(context.target?.project || ''));
7
+ const i18nConfig = workspaceConfig?.i18n;
8
+ return i18nConfig;
9
+ }
10
+ export async function translateFederationArtifacts(i18n, localize, outputPath, federationResult) {
11
+ const neededLocales = Array.isArray(localize) ? localize : Object.keys(i18n.locales);
12
+ const locales = Object.keys(i18n.locales).filter(locale => neededLocales.includes(locale));
13
+ if (locales.length === 0) {
14
+ return;
15
+ }
16
+ logger.info('Writing Translations');
17
+ const translationFiles = locales
18
+ .map(loc => i18n.locales[loc])
19
+ .map(config => typeof config === 'string' || Array.isArray(config) ? config : config.translation)
20
+ .map(files => JSON.stringify(files))
21
+ .join(' ');
22
+ const targetLocales = locales.join(' ');
23
+ const sourceLocale = typeof i18n.sourceLocale === 'string' ? i18n.sourceLocale : i18n.sourceLocale.code;
24
+ const translationOutPath = path.join(outputPath, 'browser', '{{LOCALE}}');
25
+ const federationFiles = [
26
+ ...federationResult.shared.map(s => s.outFileName),
27
+ ...federationResult.exposes.map(e => e.outFileName),
28
+ ...Object.values(federationResult.chunks ?? {}).flat(),
29
+ ];
30
+ // Here, we use a glob with an exhaustive list i/o `"*.js"`
31
+ // to improve performance
32
+ const sourcePattern = '{' + federationFiles.join(',') + '}';
33
+ const sourceLocalePath = path.join(outputPath, 'browser', sourceLocale);
34
+ const localizeTranslate = path.resolve('node_modules/.bin/localize-translate');
35
+ const cmd = `"${localizeTranslate}" -r "${sourceLocalePath}" -s "${sourcePattern}" -t ${translationFiles} -o "${translationOutPath}" --target-locales ${targetLocales} -l ${sourceLocale}`;
36
+ ensureDistFolders(locales, outputPath);
37
+ copyFederationArtifacts(locales, outputPath, sourceLocalePath);
38
+ logger.debug('Running: ' + cmd);
39
+ execCommand(cmd, 'Successfully translated');
40
+ }
41
+ function execCommand(cmd, defaultSuccessInfo) {
42
+ try {
43
+ const output = execSync(cmd);
44
+ logger.info(output.toString() || defaultSuccessInfo);
45
+ }
46
+ catch (error) {
47
+ logger.error(error.message);
48
+ }
49
+ }
50
+ /**
51
+ * Federation artifacts copied from the source locale into each target locale dir.
52
+ * M4.2: NF copied only `remoteEntry.json`; under MF the artifacts are the ESM
53
+ * container `remoteEntry.js` and the `mf-manifest.json` (both per-locale).
54
+ */
55
+ const FEDERATION_ARTIFACTS = ['remoteEntry.js', 'mf-manifest.json'];
56
+ function copyFederationArtifacts(locales, outputPath, sourceLocalePath) {
57
+ for (const artifact of FEDERATION_ARTIFACTS) {
58
+ const src = path.join(sourceLocalePath, artifact);
59
+ // A pure host has no `remoteEntry.js`; only copy artifacts that exist.
60
+ if (!fs.existsSync(src))
61
+ continue;
62
+ for (const locale of locales) {
63
+ const dest = path.join(outputPath, 'browser', locale, artifact);
64
+ fs.copyFileSync(src, dest);
65
+ }
66
+ }
67
+ }
68
+ function ensureDistFolders(locales, outputPath) {
69
+ for (const locale of locales) {
70
+ const localePath = path.join(outputPath, 'browser', locale);
71
+ fs.mkdirSync(localePath, { recursive: true });
72
+ }
73
+ }
@@ -0,0 +1,35 @@
1
+ import type { JsonObject } from "@angular-devkit/core";
2
+ import type { BuildNotificationOptions } from "@softarc/native-federation";
3
+ import type { ESMSInitOptions } from "es-module-shims";
4
+ import type { Plugin } from "esbuild";
5
+
6
+ export interface NfBuilderSchema extends JsonObject {
7
+ target: string;
8
+ dev: boolean;
9
+ port: number;
10
+ rebuildDelay: number;
11
+ buildNotifications?: BuildNotificationOptions;
12
+ federationConfigPath?: string;
13
+ watch?: boolean;
14
+ skipHtmlTransform: boolean;
15
+ esmsInitOptions: ESMSInitOptions;
16
+ baseHref?: string;
17
+ outputPath?: string;
18
+ projectName?: string;
19
+ ssr: boolean;
20
+ tsConfig?: string;
21
+ devServer?: boolean;
22
+ entryPoints?: string[];
23
+ cacheExternalArtifacts?: boolean;
24
+ }
25
+
26
+ export type NfInternalOptions = {
27
+ plugins?: Plugin[];
28
+
29
+ /**
30
+ * Enables instrumentation to collect code coverage data for specific files.
31
+ *
32
+ * Used exclusively for tests and shouldn't be used for other kinds of builds.
33
+ */
34
+ instrumentForCoverage?: (filename: string) => boolean;
35
+ };
@@ -0,0 +1,93 @@
1
+ {
2
+ "version": 2,
3
+ "outputCapture": "direct-nodejs",
4
+ "$schema": "http://json-schema.org/draft-07/schema",
5
+ "title": "native federation browser builder",
6
+ "description": "builder for native federation browser apps",
7
+ "type": "object",
8
+ "properties": {
9
+ "target": {
10
+ "type": "string",
11
+ "description": "target configured for the esbuild builder"
12
+ },
13
+ "dev": {
14
+ "type": "boolean",
15
+ "description": "Set this to true to start the builder in dev mode",
16
+ "default": false
17
+ },
18
+ "watch": {
19
+ "type": "boolean"
20
+ },
21
+ "port": {
22
+ "type": "number",
23
+ "default": 0
24
+ },
25
+ "entryPoints": {
26
+ "type": "array"
27
+ },
28
+ "rebuildDelay": {
29
+ "type": "number",
30
+ "default": 2000,
31
+ "description": "The delay for rebuilding federation artifacts. This allows to have more resources for refreshing your micro frontend in the browser."
32
+ },
33
+ "skipHtmlTransform": {
34
+ "type": "boolean",
35
+ "default": false
36
+ },
37
+ "baseHref": {
38
+ "type": "string"
39
+ },
40
+ "projectName": {
41
+ "type": "string"
42
+ },
43
+ "outputPath": {
44
+ "type": "string"
45
+ },
46
+ "esmsInitOptions": {
47
+ "type": "object",
48
+ "description": "Options for esms-module-shims https://github.com/guybedford/es-module-shims?tab=readme-ov-file#init-options",
49
+ "default": {
50
+ "shimMode": true
51
+ }
52
+ },
53
+ "ssr": {
54
+ "type": "boolean",
55
+ "description": "uses federation for ssr in ApplicationBuilder too",
56
+ "default": false
57
+ },
58
+ "devServer": {
59
+ "type": "boolean",
60
+ "description": "can be used to disable the dev server when dev=true"
61
+ },
62
+ "tsConfig": {
63
+ "type": "string",
64
+ "description": "A specific tsconfig file for the nf remotes and exposed modules."
65
+ },
66
+ "cacheExternalArtifacts": {
67
+ "type": "boolean",
68
+ "default": true,
69
+ "description": "Will cache the shared externals so they can be re-used between builds",
70
+ "alias": "cache"
71
+ },
72
+ "buildNotifications": {
73
+ "type": "object",
74
+ "properties": {
75
+ "enable": {
76
+ "type": "boolean",
77
+ "default": true,
78
+ "description": "Enable build completion notifications for local development. It will send events to notify when the federation build is complete."
79
+ },
80
+ "endpoint": {
81
+ "type": "string",
82
+ "default": "/@angular-architects/native-federation:build-notifications",
83
+ "description": "You can override the default endpoint to send build completion events to."
84
+ }
85
+ }
86
+ },
87
+ "federationConfigPath": {
88
+ "type": "string",
89
+ "description": "The path to the federation config file. If not provided, the default path will be used.",
90
+ "default": "federation.config.mjs"
91
+ }
92
+ }
93
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=setup-builder-env-variables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-builder-env-variables.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/setup-builder-env-variables.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * Disables Angular's parallel caching and allows for
4
+ * a shared cache between the compilation steps which
5
+ * improves performance dramatically.
6
+ */
7
+ if (!process.env['NG_BUILD_PARALLEL_TS']) {
8
+ process.env['NG_BUILD_PARALLEL_TS'] = '0';
9
+ }
@@ -0,0 +1,5 @@
1
+ import type { FederationOptions } from "@softarc/native-federation";
2
+ import type { NfBuilderSchema } from "./schema.js";
3
+ export declare function updateIndexHtml(fedOptions: FederationOptions, nfOptions: NfBuilderSchema): void;
4
+ export declare function updateScriptTags(indexContent: string, nfOptions: NfBuilderSchema): string;
5
+ //# sourceMappingURL=update-index-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-index-html.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/update-index-html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,wBAAgB,eAAe,CAC7B,UAAU,EAAE,iBAAiB,EAC7B,SAAS,EAAE,eAAe,QAsB3B;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,eAAe,UA6B3B"}
@@ -0,0 +1,33 @@
1
+ import * as path from "path";
2
+ import * as fs from "fs";
3
+ export function updateIndexHtml(fedOptions, nfOptions) {
4
+ const outputPath = path.join(fedOptions.workspaceRoot, fedOptions.outputPath);
5
+ const indexPathCands = [
6
+ path.join(outputPath, "../server/index.server.html"),
7
+ path.join(outputPath, "index.html"),
8
+ ];
9
+ const indexPath = indexPathCands.find((c) => fs.existsSync(c));
10
+ if (!indexPath) {
11
+ console.error("No index.html found! Searched locations: ", indexPathCands.join(", "));
12
+ return;
13
+ }
14
+ let indexContent = fs.readFileSync(indexPath, "utf-8");
15
+ indexContent = updateScriptTags(indexContent, nfOptions);
16
+ fs.writeFileSync(indexPath, indexContent, "utf-8");
17
+ }
18
+ export function updateScriptTags(indexContent, nfOptions) {
19
+ const esmsOptions = {
20
+ shimMode: true,
21
+ ...nfOptions.esmsInitOptions,
22
+ };
23
+ const mainScriptType = esmsOptions.shimMode === false ? "module" : "module-shim";
24
+ const htmlFragment = `<script type="esms-options">${JSON.stringify(esmsOptions)}</script>`;
25
+ indexContent = indexContent.replace(/<script\b(?=[^>]*\bsrc="[^"]*polyfills[^"]*")[^>]*>/, (tag) => /\btype\s*=/.test(tag)
26
+ ? tag.replace(/\btype\s*=\s*"[^"]*"/, 'type="module"')
27
+ : tag.replace(/<script\b/, '<script type="module"'));
28
+ indexContent = indexContent.replace(/<script\b(?=[^>]*\bsrc="[^"]*main[^"]*")[^>]*>/, (tag) => /\btype\s*=/.test(tag)
29
+ ? tag.replace(/\btype\s*=\s*"[^"]*"/, `type="${mainScriptType}"`)
30
+ : tag.replace(/<script\b/, `<script type="${mainScriptType}"`));
31
+ indexContent = indexContent.replace(/(<body.*?>)/, `$1\n\t\t${htmlFragment}`);
32
+ return indexContent;
33
+ }
@@ -0,0 +1,14 @@
1
+ import type { ApplicationBuilderOptions } from '@angular/build';
2
+ export type NormalizedAssetEntry = {
3
+ glob: string;
4
+ input: string;
5
+ output: string;
6
+ ignore?: string[];
7
+ followSymlinks?: boolean;
8
+ flatten?: boolean;
9
+ };
10
+ export declare function normalizeRemoteAssetEntries(assets: ApplicationBuilderOptions['assets'] | undefined, workspaceRoot: string, projectRoot: string, projectSourceRoot: string | undefined): NormalizedAssetEntry[];
11
+ export declare function copyAllAssets(entries: NormalizedAssetEntry[], outputDir: string, workspaceRoot: string): Promise<void>;
12
+ export declare function copyChangedAssets(entries: NormalizedAssetEntry[], outputDir: string, workspaceRoot: string, changedFiles: Iterable<string>): Promise<void>;
13
+ export declare function getAssetWatchDirs(entries: NormalizedAssetEntry[], workspaceRoot: string): string[];
14
+ //# sourceMappingURL=assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../../src/builders/remote/assets.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAEhE,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,yBAAyB,CAAC,QAAQ,CAAC,GAAG,SAAS,EACvD,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,GAAG,SAAS,GACpC,oBAAoB,EAAE,CASxB;AA6BD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,EAAE,EAC/B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,oBAAoB,EAAE,EAC/B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,oBAAoB,EAAE,EAC/B,aAAa,EAAE,MAAM,GACpB,MAAM,EAAE,CAEV"}
@@ -0,0 +1,49 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
4
+ // @ts-ignore - not re-exported from package root
5
+ import { normalizeAssetPatterns } from '@angular/build/src/utils/normalize-asset-patterns.js';
6
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
7
+ // @ts-ignore - not re-exported from package root
8
+ import { resolveAssets } from '@angular/build/src/utils/resolve-assets.js';
9
+ export function normalizeRemoteAssetEntries(assets, workspaceRoot, projectRoot, projectSourceRoot) {
10
+ if (!assets || assets.length === 0)
11
+ return [];
12
+ return normalizeAssetPatterns(
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ assets, workspaceRoot, projectRoot, projectSourceRoot);
15
+ }
16
+ async function writeAssets(entries, outputDir, workspaceRoot, changed) {
17
+ if (entries.length === 0)
18
+ return;
19
+ const resolved = (await resolveAssets(entries, workspaceRoot));
20
+ const createdDirs = new Set();
21
+ for (const { source, destination } of resolved) {
22
+ if (changed && !changed.has(source))
23
+ continue;
24
+ const dest = path.join(outputDir, destination);
25
+ const dir = path.dirname(dest);
26
+ if (!createdDirs.has(dir)) {
27
+ fs.mkdirSync(dir, { recursive: true });
28
+ createdDirs.add(dir);
29
+ }
30
+ fs.copyFileSync(source, dest, fs.constants.COPYFILE_FICLONE);
31
+ }
32
+ }
33
+ export function copyAllAssets(entries, outputDir, workspaceRoot) {
34
+ return writeAssets(entries, outputDir, workspaceRoot);
35
+ }
36
+ export function copyChangedAssets(entries, outputDir, workspaceRoot, changedFiles) {
37
+ if (entries.length === 0)
38
+ return Promise.resolve();
39
+ const changed = new Set();
40
+ for (const file of changedFiles) {
41
+ changed.add(path.isAbsolute(file) ? file : path.resolve(workspaceRoot, file));
42
+ }
43
+ if (changed.size === 0)
44
+ return Promise.resolve();
45
+ return writeAssets(entries, outputDir, workspaceRoot, changed);
46
+ }
47
+ export function getAssetWatchDirs(entries, workspaceRoot) {
48
+ return entries.map(entry => path.resolve(workspaceRoot, entry.input));
49
+ }
@@ -0,0 +1,13 @@
1
+ import '../build/setup-builder-env-variables.js';
2
+ import { type BuilderContext, type BuilderOutput } from '@angular-devkit/architect';
3
+ import type { NfRemoteBuilderSchema, NfRemoteInternalOptions } from './schema.js';
4
+ /**
5
+ * THIS BUILDER IS EXPERIMENTAL AND MIGHT CHANGE OVER TIME
6
+ *
7
+ * @param nfBuilderOptions
8
+ * @param context
9
+ */
10
+ export declare function runRemoteBuilder(nfBuilderOptions: NfRemoteBuilderSchema & NfRemoteInternalOptions, context: BuilderContext): AsyncIterable<BuilderOutput>;
11
+ declare const _default: any;
12
+ export default _default;
13
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../../src/builders/remote/builder.ts"],"names":[],"mappings":"AAAA,OAAO,yCAAyC,CAAC;AAOjD,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAiB,MAAM,2BAA2B,CAAC;AAmBnG,OAAO,KAAK,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAWlF;;;;;GAKG;AAEH,wBAAuB,gBAAgB,CACrC,gBAAgB,EAAE,qBAAqB,GAAG,uBAAuB,EACjE,OAAO,EAAE,cAAc,GACtB,aAAa,CAAC,aAAa,CAAC,CAmL9B;wBAGiD,GAAG;AAArD,wBAAsD"}
@@ -0,0 +1,153 @@
1
+ import '../build/setup-builder-env-variables.js';
2
+ import * as path from 'path';
3
+ import { existsSync, mkdirSync, rmSync } from 'fs';
4
+ import { SourceFileCache } from '@angular/build/private';
5
+ import { createBuilder } from '@angular-devkit/architect';
6
+ import { getExternals, normalizeFederationOptions, createFederationCache, } from '@softarc/native-federation';
7
+ import { logger, setLogLevel, RebuildQueue, AbortedError, getDefaultCachePath, syncNfFileWatcher, } from '@softarc/native-federation/internal';
8
+ import { createMfFederationBuilder } from '../../tools/mf/build-for-federation.js';
9
+ import { checkForInvalidImports } from '../../utils/check-for-invalid-imports.js';
10
+ import { resolveNgBuilderOptions } from './resolve-ng-options.js';
11
+ import { inferFederationConfigPath } from './infer-config-path.js';
12
+ import { createDebouncedChangeWatcher } from './change-watcher.js';
13
+ import { copyAllAssets, copyChangedAssets, getAssetWatchDirs, normalizeRemoteAssetEntries, } from './assets.js';
14
+ /**
15
+ * THIS BUILDER IS EXPERIMENTAL AND MIGHT CHANGE OVER TIME
16
+ *
17
+ * @param nfBuilderOptions
18
+ * @param context
19
+ */
20
+ export async function* runRemoteBuilder(nfBuilderOptions, context) {
21
+ const federationTsConfig = nfBuilderOptions.tsConfig;
22
+ const outputBase = nfBuilderOptions.outputPath ?? `dist/${context.target.project}`;
23
+ const browserOutputPath = path.join(outputBase, 'browser');
24
+ const absoluteBrowserOutput = path.resolve(context.workspaceRoot, browserOutputPath);
25
+ const { ngBuilderOptions, projectRoot, projectSourceRoot } = await resolveNgBuilderOptions(nfBuilderOptions, context);
26
+ setLogLevel(nfBuilderOptions.verbose ? 'verbose' : 'info');
27
+ // Unlike the regular build builder, remote never bundles a main.ts / polyfills.
28
+ // Entry points come from the schema override or, when omitted, from the
29
+ // `exposes` map in federation.config.{mjs,js} (resolved by normalizeFederationOptions).
30
+ const entryPoints = nfBuilderOptions.entryPoints?.length
31
+ ? nfBuilderOptions.entryPoints
32
+ : undefined;
33
+ const cachePath = getDefaultCachePath(context.workspaceRoot);
34
+ const normalized = await normalizeFederationOptions({
35
+ projectName: nfBuilderOptions.projectName,
36
+ workspaceRoot: context.workspaceRoot,
37
+ outputPath: browserOutputPath,
38
+ federationConfig: inferFederationConfigPath(federationTsConfig, context.workspaceRoot),
39
+ tsConfig: federationTsConfig,
40
+ verbose: nfBuilderOptions.verbose,
41
+ watch: nfBuilderOptions.watch,
42
+ dev: !!nfBuilderOptions.dev,
43
+ entryPoints,
44
+ cacheExternalArtifacts: nfBuilderOptions.cacheExternalArtifacts !== false,
45
+ }, createFederationCache(cachePath, new SourceFileCache(cachePath)));
46
+ checkForInvalidImports(Object.values(normalized.config.sharedMappings), 'shared mappings');
47
+ checkForInvalidImports(Object.keys(normalized.config.shared), 'externals');
48
+ const start = process.hrtime();
49
+ logger.measure(start, 'To load the federation config.');
50
+ const externals = getExternals(normalized.config);
51
+ // MF side builder (M2.1) — replaces NF's adapter + buildForFederation/rebuildForFederation.
52
+ // Holds one esbuild context (Angular compiler + moduleFederationPlugin) for build + rebuilds.
53
+ const mfBuilder = await createMfFederationBuilder(normalized.config, normalized.options, externals, { builderOptions: ngBuilderOptions, context });
54
+ const assetEntries = normalizeRemoteAssetEntries(nfBuilderOptions.assets, context.workspaceRoot, projectRoot, projectSourceRoot);
55
+ const changeWatcher = nfBuilderOptions.watch
56
+ ? createDebouncedChangeWatcher(nfBuilderOptions.rebuildDelay)
57
+ : undefined;
58
+ if (changeWatcher) {
59
+ changeWatcher.watcher.addPaths(path.dirname(path.resolve(context.workspaceRoot, federationTsConfig)));
60
+ for (const assetDir of getAssetWatchDirs(assetEntries, context.workspaceRoot)) {
61
+ changeWatcher.watcher.addPaths(assetDir);
62
+ }
63
+ }
64
+ if (existsSync(normalized.options.outputPath)) {
65
+ rmSync(normalized.options.outputPath, { recursive: true });
66
+ }
67
+ mkdirSync(normalized.options.outputPath, { recursive: true });
68
+ try {
69
+ await mfBuilder.build();
70
+ }
71
+ catch (e) {
72
+ logger.error(e?.message ?? 'Building the artifacts failed');
73
+ process.exit(1);
74
+ }
75
+ await copyAllAssets(assetEntries, absoluteBrowserOutput, context.workspaceRoot);
76
+ if (changeWatcher) {
77
+ syncNfFileWatcher(changeWatcher.watcher, normalized.options.federationCache.bundlerCache);
78
+ }
79
+ const rebuildQueue = new RebuildQueue();
80
+ try {
81
+ yield { success: true };
82
+ while (nfBuilderOptions.watch && changeWatcher) {
83
+ await changeWatcher.waitForChange();
84
+ changeWatcher.resetChangePromise();
85
+ // fs.watch fires multiple events per save (write+rename, plus overlapping
86
+ // directory and per-file watchers). Redundant events arriving during a
87
+ // rebuild resolve the next promise, so without this guard the loop runs a
88
+ // second phantom build with an empty snapshot once the first one finishes.
89
+ if (changeWatcher.pendingPaths.size === 0)
90
+ continue;
91
+ // The freshly-reset change promise doubles as the interrupt signal: if a
92
+ // newer (debounced) change lands while this rebuild is in flight, abort it
93
+ // and loop to fold the new paths in — mirroring how the `build` builder
94
+ // passes Angular's next output as the interrupt to RebuildQueue.track.
95
+ // Without this, RebuildQueue's AbortSignal is never triggered and a stale
96
+ // rebuild must finish before a fresh save is picked up.
97
+ const interruptPromise = changeWatcher.waitForChange();
98
+ const trackResult = await rebuildQueue.track(async (signal) => {
99
+ try {
100
+ if (signal?.aborted) {
101
+ throw new AbortedError('Build canceled before starting');
102
+ }
103
+ // Snapshot but don't clear — unlike the build builder (which clears its
104
+ // buffer eagerly and relies on Angular's iterator to re-trigger), this
105
+ // builder owns its watcher, so if the build is aborted or fails the paths
106
+ // stay in pendingPaths and are retried on the next cycle.
107
+ const changedFiles = [...changeWatcher.pendingPaths];
108
+ // NF's rebuild took an AbortSignal for mid-build cancellation; the MF
109
+ // builder reuses its esbuild context (fast incremental rebuild), and the
110
+ // RebuildQueue still wraps it with `signal` for queue-level interruption.
111
+ await mfBuilder.rebuild(changedFiles);
112
+ await copyChangedAssets(assetEntries, absoluteBrowserOutput, context.workspaceRoot, changedFiles);
113
+ // Clear only what we consumed. Any paths pushed during the build
114
+ // remain in pendingPaths and will drive the next iteration.
115
+ for (const p of changedFiles)
116
+ changeWatcher.pendingPaths.delete(p);
117
+ syncNfFileWatcher(changeWatcher.watcher, normalized.options.federationCache.bundlerCache);
118
+ if (signal?.aborted) {
119
+ throw new AbortedError('[remote-builder] After federation build.');
120
+ }
121
+ logger.info('Done!');
122
+ return { success: true };
123
+ }
124
+ catch (error) {
125
+ if (error instanceof AbortedError) {
126
+ logger.verbose('Rebuild was canceled. Cancellation point: ' + error?.message);
127
+ return { success: false, cancelled: true };
128
+ }
129
+ logger.error('Federation rebuild failed!');
130
+ if (nfBuilderOptions.verbose)
131
+ console.error(error);
132
+ return { success: false };
133
+ }
134
+ }, interruptPromise);
135
+ // Mirrors the build builder's trackResult handling, minus the iterator pump:
136
+ // there the 'interrupted' branch feeds Angular's next output back into the
137
+ // loop, whereas here the new change has already resolved the current change
138
+ // promise, so the next loop iteration picks it up immediately. The aborted
139
+ // build left its paths in pendingPaths, so nothing is lost.
140
+ if (trackResult.type === 'completed' && !trackResult.result.cancelled) {
141
+ yield { success: trackResult.result.success };
142
+ }
143
+ }
144
+ }
145
+ finally {
146
+ changeWatcher?.dispose();
147
+ rebuildQueue.dispose();
148
+ await mfBuilder.dispose();
149
+ await changeWatcher?.watcher.close();
150
+ }
151
+ }
152
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
153
+ export default createBuilder(runRemoteBuilder);
@@ -0,0 +1,10 @@
1
+ import { type NfFileWatcher } from '@softarc/native-federation/internal';
2
+ export interface DebouncedChangeWatcher {
3
+ watcher: NfFileWatcher;
4
+ pendingPaths: Set<string>;
5
+ waitForChange: () => Promise<void>;
6
+ resetChangePromise: () => void;
7
+ dispose: () => void;
8
+ }
9
+ export declare function createDebouncedChangeWatcher(rebuildDelay: number): DebouncedChangeWatcher;
10
+ //# sourceMappingURL=change-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-watcher.d.ts","sourceRoot":"","sources":["../../../../src/builders/remote/change-watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAE1F,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,sBAAsB,CAoCzF"}
@@ -0,0 +1,35 @@
1
+ import { createNfWatcher } from '@softarc/native-federation/internal';
2
+ export function createDebouncedChangeWatcher(rebuildDelay) {
3
+ const pendingPaths = new Set();
4
+ let notifyChange = () => { };
5
+ let changePromise = new Promise(r => (notifyChange = r));
6
+ const resetChangePromise = () => {
7
+ changePromise = new Promise(r => (notifyChange = r));
8
+ };
9
+ const debounceMs = Math.max(10, rebuildDelay);
10
+ let debounceTimer;
11
+ const scheduleNotify = () => {
12
+ if (debounceTimer)
13
+ clearTimeout(debounceTimer);
14
+ debounceTimer = setTimeout(() => {
15
+ debounceTimer = undefined;
16
+ notifyChange();
17
+ }, debounceMs);
18
+ };
19
+ const watcher = createNfWatcher({
20
+ onChange: p => {
21
+ pendingPaths.add(p);
22
+ scheduleNotify();
23
+ },
24
+ });
25
+ return {
26
+ watcher,
27
+ pendingPaths,
28
+ waitForChange: () => changePromise,
29
+ resetChangePromise,
30
+ dispose: () => {
31
+ if (debounceTimer)
32
+ clearTimeout(debounceTimer);
33
+ },
34
+ };
35
+ }
@@ -0,0 +1,2 @@
1
+ export declare function inferFederationConfigPath(tsConfig: string, workspaceRoot: string): string;
2
+ //# sourceMappingURL=infer-config-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer-config-path.d.ts","sourceRoot":"","sources":["../../../../src/builders/remote/infer-config-path.ts"],"names":[],"mappings":"AAGA,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CASzF"}
@@ -0,0 +1,10 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ export function inferFederationConfigPath(tsConfig, workspaceRoot) {
4
+ const relProjectPath = path.dirname(tsConfig);
5
+ const mjsRelPath = path.join(relProjectPath, 'federation.config.mjs');
6
+ if (fs.existsSync(path.resolve(workspaceRoot, mjsRelPath))) {
7
+ return mjsRelPath;
8
+ }
9
+ return path.join(relProjectPath, 'federation.config.js');
10
+ }