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.
- package/LICENSE +8 -0
- package/README.md +115 -0
- package/builders.json +15 -0
- package/collection.json +27 -0
- package/generators.json +12 -0
- package/migration-collection.json +6 -0
- package/package.json +69 -0
- package/src/builders/build/builder.d.ts +7 -0
- package/src/builders/build/builder.d.ts.map +1 -0
- package/src/builders/build/builder.js +413 -0
- package/src/builders/build/federation-build-notifier.d.ts +70 -0
- package/src/builders/build/federation-build-notifier.d.ts.map +1 -0
- package/src/builders/build/federation-build-notifier.js +186 -0
- package/src/builders/build/get-externals.d.ts +18 -0
- package/src/builders/build/get-externals.d.ts.map +1 -0
- package/src/builders/build/get-externals.js +19 -0
- package/src/builders/build/i18n.d.ts +21 -0
- package/src/builders/build/i18n.d.ts.map +1 -0
- package/src/builders/build/i18n.js +73 -0
- package/src/builders/build/schema.d.ts +35 -0
- package/src/builders/build/schema.json +93 -0
- package/src/builders/build/setup-builder-env-variables.d.ts +1 -0
- package/src/builders/build/setup-builder-env-variables.d.ts.map +1 -0
- package/src/builders/build/setup-builder-env-variables.js +9 -0
- package/src/builders/build/update-index-html.d.ts +5 -0
- package/src/builders/build/update-index-html.d.ts.map +1 -0
- package/src/builders/build/update-index-html.js +33 -0
- package/src/builders/remote/assets.d.ts +14 -0
- package/src/builders/remote/assets.d.ts.map +1 -0
- package/src/builders/remote/assets.js +49 -0
- package/src/builders/remote/builder.d.ts +13 -0
- package/src/builders/remote/builder.d.ts.map +1 -0
- package/src/builders/remote/builder.js +153 -0
- package/src/builders/remote/change-watcher.d.ts +10 -0
- package/src/builders/remote/change-watcher.d.ts.map +1 -0
- package/src/builders/remote/change-watcher.js +35 -0
- package/src/builders/remote/infer-config-path.d.ts +2 -0
- package/src/builders/remote/infer-config-path.d.ts.map +1 -0
- package/src/builders/remote/infer-config-path.js +10 -0
- package/src/builders/remote/resolve-ng-options.d.ts +24 -0
- package/src/builders/remote/resolve-ng-options.d.ts.map +1 -0
- package/src/builders/remote/resolve-ng-options.js +28 -0
- package/src/builders/remote/schema.d.ts +26 -0
- package/src/builders/remote/schema.json +116 -0
- package/src/config/angular-locales.d.ts +6 -0
- package/src/config/angular-locales.d.ts.map +1 -0
- package/src/config/angular-locales.js +23 -0
- package/src/config/angular-skip-list.d.ts +3 -0
- package/src/config/angular-skip-list.d.ts.map +1 -0
- package/src/config/angular-skip-list.js +23 -0
- package/src/config/with-module-federation.d.ts +72 -0
- package/src/config/with-module-federation.d.ts.map +1 -0
- package/src/config/with-module-federation.js +72 -0
- package/src/config.d.ts +4 -0
- package/src/config.d.ts.map +1 -0
- package/src/config.js +3 -0
- package/src/generators/native-federation/files/src/index.ts__template__ +1 -0
- package/src/generators/native-federation/generator.d.ts +4 -0
- package/src/generators/native-federation/generator.d.ts.map +1 -0
- package/src/generators/native-federation/generator.js +45 -0
- package/src/generators/native-federation/schema.d.ts +5 -0
- package/src/generators/native-federation/schema.json +29 -0
- package/src/index.d.ts +82 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +132 -0
- package/src/internal.d.ts +2 -0
- package/src/internal.d.ts.map +1 -0
- package/src/internal.js +1 -0
- package/src/schematics/appbuilder/schema.d.ts +3 -0
- package/src/schematics/appbuilder/schema.json +17 -0
- package/src/schematics/appbuilder/schematic.d.ts +5 -0
- package/src/schematics/appbuilder/schematic.d.ts.map +1 -0
- package/src/schematics/appbuilder/schematic.js +80 -0
- package/src/schematics/init/files/federation.config.mjs__tmpl__ +35 -0
- package/src/schematics/init/schema.d.ts +5 -0
- package/src/schematics/init/schema.json +30 -0
- package/src/schematics/init/schematic.d.ts +6 -0
- package/src/schematics/init/schematic.d.ts.map +1 -0
- package/src/schematics/init/schematic.js +38 -0
- package/src/schematics/init/steps/add-dependencies.d.ts +3 -0
- package/src/schematics/init/steps/add-dependencies.d.ts.map +1 -0
- package/src/schematics/init/steps/add-dependencies.js +25 -0
- package/src/schematics/init/steps/generate-federation-config.d.ts +4 -0
- package/src/schematics/init/steps/generate-federation-config.d.ts.map +1 -0
- package/src/schematics/init/steps/generate-federation-config.js +15 -0
- package/src/schematics/init/steps/generate-remote-map.d.ts +2 -0
- package/src/schematics/init/steps/generate-remote-map.d.ts.map +1 -0
- package/src/schematics/init/steps/generate-remote-map.js +20 -0
- package/src/schematics/init/steps/make-main-async.d.ts +4 -0
- package/src/schematics/init/steps/make-main-async.d.ts.map +1 -0
- package/src/schematics/init/steps/make-main-async.js +35 -0
- package/src/schematics/init/steps/normalize-options.d.ts +20 -0
- package/src/schematics/init/steps/normalize-options.d.ts.map +1 -0
- package/src/schematics/init/steps/normalize-options.js +64 -0
- package/src/schematics/init/steps/update-package-json.d.ts +3 -0
- package/src/schematics/init/steps/update-package-json.d.ts.map +1 -0
- package/src/schematics/init/steps/update-package-json.js +19 -0
- package/src/schematics/init/steps/update-polyfills.d.ts +3 -0
- package/src/schematics/init/steps/update-polyfills.d.ts.map +1 -0
- package/src/schematics/init/steps/update-polyfills.js +21 -0
- package/src/schematics/init/steps/update-workspace-config.d.ts +4 -0
- package/src/schematics/init/steps/update-workspace-config.d.ts.map +1 -0
- package/src/schematics/init/steps/update-workspace-config.js +76 -0
- package/src/schematics/remove/schema.d.ts +3 -0
- package/src/schematics/remove/schema.json +17 -0
- package/src/schematics/remove/schematic.d.ts +5 -0
- package/src/schematics/remove/schematic.d.ts.map +1 -0
- package/src/schematics/remove/schematic.js +106 -0
- package/src/tools/esbuild/angular-bundler.d.ts +10 -0
- package/src/tools/esbuild/angular-bundler.d.ts.map +1 -0
- package/src/tools/esbuild/angular-bundler.js +134 -0
- package/src/tools/esbuild/create-awaitable-compiler-plugin.d.ts +6 -0
- package/src/tools/esbuild/create-awaitable-compiler-plugin.d.ts.map +1 -0
- package/src/tools/esbuild/create-awaitable-compiler-plugin.js +29 -0
- package/src/tools/esbuild/create-federation-tsconfig.d.ts +7 -0
- package/src/tools/esbuild/create-federation-tsconfig.d.ts.map +1 -0
- package/src/tools/esbuild/create-federation-tsconfig.js +46 -0
- package/src/tools/esbuild/shared-mappings-plugin.d.ts +4 -0
- package/src/tools/esbuild/shared-mappings-plugin.d.ts.map +1 -0
- package/src/tools/esbuild/shared-mappings-plugin.js +33 -0
- package/src/tools/mf/build-for-federation.d.ts +70 -0
- package/src/tools/mf/build-for-federation.d.ts.map +1 -0
- package/src/tools/mf/build-for-federation.js +75 -0
- package/src/tools/mf/federation-entry-points.d.ts +23 -0
- package/src/tools/mf/federation-entry-points.d.ts.map +1 -0
- package/src/tools/mf/federation-entry-points.js +13 -0
- package/src/tools/mf/federation-plugin.d.ts +11 -0
- package/src/tools/mf/federation-plugin.d.ts.map +1 -0
- package/src/tools/mf/federation-plugin.js +12 -0
- package/src/tools/mf/federation-side-build.d.ts +21 -0
- package/src/tools/mf/federation-side-build.d.ts.map +1 -0
- package/src/tools/mf/federation-side-build.js +27 -0
- package/src/tools/mf/to-plugin-config.d.ts +37 -0
- package/src/tools/mf/to-plugin-config.d.ts.map +1 -0
- package/src/tools/mf/to-plugin-config.js +33 -0
- package/src/utils/check-for-invalid-imports.d.ts +2 -0
- package/src/utils/check-for-invalid-imports.d.ts.map +1 -0
- package/src/utils/check-for-invalid-imports.js +29 -0
- package/src/utils/normalize-build-options.d.ts +22 -0
- package/src/utils/normalize-build-options.d.ts.map +1 -0
- package/src/utils/normalize-build-options.js +45 -0
- package/src/utils/normalize-context-options.d.ts +24 -0
- package/src/utils/normalize-context-options.d.ts.map +1 -0
- 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 @@
|
|
|
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
|
+
}
|