@angular-architects/native-federation-v4 21.1.7 → 21.1.9
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/collection.json +5 -0
- package/migration-collection.json +6 -0
- package/package.json +5 -5
- package/src/builders/build/builder.d.ts.map +1 -1
- package/src/builders/build/builder.js +45 -49
- package/src/builders/build/schema.d.ts +3 -5
- package/src/builders/build/schema.json +8 -29
- 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 +13 -0
- package/src/config/share-utils.d.ts +9 -0
- package/src/config/share-utils.d.ts.map +1 -0
- package/src/config/share-utils.js +32 -0
- package/src/config.d.ts +2 -2
- package/src/config.d.ts.map +1 -1
- package/src/config.js +2 -2
- package/src/schematics/init/files/federation.config.js__tmpl__ +19 -7
- package/src/schematics/init/schema.d.ts +0 -1
- package/src/schematics/init/schema.json +2 -6
- package/src/schematics/init/schematic.d.ts.map +1 -1
- package/src/schematics/init/schematic.js +50 -25
- package/src/schematics/update-v4/schema.d.ts +4 -0
- package/src/schematics/update-v4/schema.json +23 -0
- package/src/schematics/update-v4/schematic.d.ts +4 -0
- package/src/schematics/update-v4/schematic.d.ts.map +1 -0
- package/src/schematics/update-v4/schematic.js +225 -0
- package/src/utils/angular-bundler.d.ts +3 -8
- package/src/utils/angular-bundler.d.ts.map +1 -1
- package/src/utils/angular-bundler.js +10 -57
- package/src/utils/angular-esbuild-adapter.d.ts +5 -4
- package/src/utils/angular-esbuild-adapter.d.ts.map +1 -1
- package/src/utils/angular-esbuild-adapter.js +16 -19
- package/src/utils/angular-locales.d.ts.map +1 -1
- package/src/utils/create-federation-tsconfig.d.ts +6 -0
- package/src/utils/create-federation-tsconfig.d.ts.map +1 -0
- package/src/utils/create-federation-tsconfig.js +49 -0
- package/src/utils/get-fallback-platform.d.ts +3 -0
- package/src/utils/get-fallback-platform.d.ts.map +1 -0
- package/src/utils/get-fallback-platform.js +13 -0
- package/src/utils/node-modules-bundler.d.ts +3 -8
- package/src/utils/node-modules-bundler.d.ts.map +1 -1
- package/src/utils/node-modules-bundler.js +4 -8
- package/src/utils/normalize-context-options.d.ts +23 -0
- package/src/utils/normalize-context-options.d.ts.map +1 -0
- package/src/utils/normalize-context-options.js +18 -0
- package/src/utils/shared-mappings-plugin.d.ts +2 -2
- package/src/utils/shared-mappings-plugin.d.ts.map +1 -1
- package/src/utils/shared-mappings-plugin.js +4 -4
|
@@ -4,7 +4,7 @@ import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
|
|
4
4
|
import { patchAngularBuildPackageJson, privateEntrySrc } from '../../utils/patch-angular-build.js';
|
|
5
5
|
import { addPackageJsonDependency, getPackageJsonDependency, NodeDependencyType, } from '@schematics/angular/utility/dependencies';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
-
const SSR_VERSION = '
|
|
7
|
+
const SSR_VERSION = '4.0.0-RC9';
|
|
8
8
|
export function updatePackageJson(tree) {
|
|
9
9
|
const packageJson = tree.readJson('package.json') ?? {};
|
|
10
10
|
const scriptCall = 'node node_modules/@angular-architects/native-federation/src/patch-angular-build.js';
|
|
@@ -45,19 +45,7 @@ export default function config(options) {
|
|
|
45
45
|
: noop;
|
|
46
46
|
const ssr = isSsrProject(normalized);
|
|
47
47
|
const server = ssr ? getSsrFilePath(normalized) : '';
|
|
48
|
-
if (ssr) {
|
|
49
|
-
console.log('SSR detected ...');
|
|
50
|
-
console.log('Activating CORS ...');
|
|
51
|
-
addPackageJsonDependency(tree, {
|
|
52
|
-
name: 'cors',
|
|
53
|
-
type: NodeDependencyType.Default,
|
|
54
|
-
version: '^2.8.5',
|
|
55
|
-
overwrite: false,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
48
|
updateWorkspaceConfig(tree, normalized, workspace, workspaceFileName, ssr);
|
|
59
|
-
// updatePackageJson(tree);
|
|
60
|
-
// patchAngularBuild(tree);
|
|
61
49
|
addPackageJsonDependency(tree, {
|
|
62
50
|
name: '@angular/animations',
|
|
63
51
|
type: NodeDependencyType.Default,
|
|
@@ -77,12 +65,28 @@ export default function config(options) {
|
|
|
77
65
|
overwrite: false,
|
|
78
66
|
});
|
|
79
67
|
addPackageJsonDependency(tree, {
|
|
80
|
-
name: '@softarc/native-federation-
|
|
68
|
+
name: '@softarc/native-federation-orchestrator',
|
|
81
69
|
type: NodeDependencyType.Default,
|
|
82
|
-
version:
|
|
83
|
-
overwrite:
|
|
70
|
+
version: '4.0.0-RC4',
|
|
71
|
+
overwrite: false,
|
|
84
72
|
});
|
|
85
73
|
context.addTask(new NodePackageInstallTask());
|
|
74
|
+
if (ssr) {
|
|
75
|
+
console.log('SSR detected ...');
|
|
76
|
+
console.log('Activating CORS ...');
|
|
77
|
+
addPackageJsonDependency(tree, {
|
|
78
|
+
name: 'cors',
|
|
79
|
+
type: NodeDependencyType.Default,
|
|
80
|
+
version: '^2.8.5',
|
|
81
|
+
overwrite: false,
|
|
82
|
+
});
|
|
83
|
+
addPackageJsonDependency(tree, {
|
|
84
|
+
name: '@softarc/native-federation-node',
|
|
85
|
+
type: NodeDependencyType.Default,
|
|
86
|
+
version: SSR_VERSION,
|
|
87
|
+
overwrite: true,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
86
90
|
return chain([
|
|
87
91
|
generateRule,
|
|
88
92
|
makeMainAsync(main, options, remoteMap, manifestRelPath),
|
|
@@ -113,7 +117,8 @@ export function patchAngularBuild(tree) {
|
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
119
|
function updateWorkspaceConfig(tree, options, workspace, workspaceFileName, ssr) {
|
|
116
|
-
const { projectConfig, projectName, port } = options;
|
|
120
|
+
const { projectConfig, projectName, port, main, projectSourceRoot } = options;
|
|
121
|
+
const entryPoints = main ? [main] : [path.join(projectSourceRoot, 'main.ts')];
|
|
117
122
|
if (!projectConfig?.architect?.build || !projectConfig?.architect?.serve) {
|
|
118
123
|
throw new Error(`The project doesn't have a build or serve target in angular.json!`);
|
|
119
124
|
}
|
|
@@ -134,7 +139,11 @@ function updateWorkspaceConfig(tree, options, workspace, workspaceFileName, ssr)
|
|
|
134
139
|
projectConfig.architect.esbuild = originalBuild;
|
|
135
140
|
projectConfig.architect.build = {
|
|
136
141
|
builder: '@angular-architects/native-federation:build',
|
|
137
|
-
options: {
|
|
142
|
+
options: {
|
|
143
|
+
projectName,
|
|
144
|
+
cacheExternalArtifacts: true,
|
|
145
|
+
entryPoints,
|
|
146
|
+
},
|
|
138
147
|
configurations: {
|
|
139
148
|
production: {
|
|
140
149
|
target: `${projectName}:esbuild:production`,
|
|
@@ -168,11 +177,14 @@ function updateWorkspaceConfig(tree, options, workspace, workspaceFileName, ssr)
|
|
|
168
177
|
projectConfig.architect.serve = {
|
|
169
178
|
builder: '@angular-architects/native-federation:build',
|
|
170
179
|
options: {
|
|
180
|
+
projectName,
|
|
171
181
|
target: `${projectName}:serve-original:development`,
|
|
172
182
|
rebuildDelay: 500,
|
|
183
|
+
cacheExternalArtifacts: true,
|
|
173
184
|
dev: true,
|
|
174
|
-
|
|
185
|
+
devServer: true,
|
|
175
186
|
port: 0,
|
|
187
|
+
entryPoints,
|
|
176
188
|
},
|
|
177
189
|
};
|
|
178
190
|
const serveSsr = projectConfig.architect['serve-ssr'];
|
|
@@ -292,11 +304,24 @@ function makeMainAsync(main, options, remoteMap, manifestRelPath) {
|
|
|
292
304
|
const mainContent = tree.read(main);
|
|
293
305
|
if (mainContent)
|
|
294
306
|
tree.create(bootstrapName, mainContent);
|
|
307
|
+
const orchestratorImports = `import { initFederation } from '@softarc/native-federation-orchestrator';
|
|
308
|
+
import {
|
|
309
|
+
useShimImportMap,
|
|
310
|
+
consoleLogger,
|
|
311
|
+
globalThisStorageEntry,
|
|
312
|
+
} from '@softarc/native-federation-orchestrator/options';`;
|
|
313
|
+
const orchestratorOptions = `{
|
|
314
|
+
...useShimImportMap({ shimMode: true }),
|
|
315
|
+
logger: consoleLogger,
|
|
316
|
+
storage: globalThisStorageEntry,
|
|
317
|
+
hostRemoteEntry: './remoteEntry.json',
|
|
318
|
+
logLevel: 'debug',
|
|
319
|
+
}`;
|
|
295
320
|
let newMainContent = '';
|
|
296
321
|
if (options.type === 'dynamic-host') {
|
|
297
|
-
newMainContent =
|
|
322
|
+
newMainContent = `${orchestratorImports}
|
|
298
323
|
|
|
299
|
-
initFederation('${manifestRelPath}')
|
|
324
|
+
initFederation('${manifestRelPath}', ${orchestratorOptions})
|
|
300
325
|
.catch(err => console.error(err))
|
|
301
326
|
.then(_ => import('./bootstrap'))
|
|
302
327
|
.catch(err => console.error(err));
|
|
@@ -304,18 +329,18 @@ initFederation('${manifestRelPath}')
|
|
|
304
329
|
}
|
|
305
330
|
else if (options.type === 'host') {
|
|
306
331
|
const manifest = JSON.stringify(remoteMap, null, 2).replace(/"/g, "'");
|
|
307
|
-
newMainContent =
|
|
332
|
+
newMainContent = `${orchestratorImports}
|
|
308
333
|
|
|
309
|
-
initFederation(${manifest})
|
|
334
|
+
initFederation(${manifest}, ${orchestratorOptions})
|
|
310
335
|
.catch(err => console.error(err))
|
|
311
336
|
.then(_ => import('./bootstrap'))
|
|
312
337
|
.catch(err => console.error(err));
|
|
313
338
|
`;
|
|
314
339
|
}
|
|
315
340
|
else {
|
|
316
|
-
newMainContent =
|
|
341
|
+
newMainContent = `${orchestratorImports}
|
|
317
342
|
|
|
318
|
-
initFederation()
|
|
343
|
+
initFederation({ '${options.project}': './remoteEntry.json' }, ${orchestratorOptions})
|
|
319
344
|
.catch(err => console.error(err))
|
|
320
345
|
.then(_ => import('./bootstrap'))
|
|
321
346
|
.catch(err => console.error(err));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "update-v4",
|
|
4
|
+
"title": "",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"project": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "The project to migrate to v4",
|
|
10
|
+
"$default": {
|
|
11
|
+
"$source": "argv",
|
|
12
|
+
"index": 0
|
|
13
|
+
},
|
|
14
|
+
"x-prompt": "Project name (press enter for default project)"
|
|
15
|
+
},
|
|
16
|
+
"orchestrator": {
|
|
17
|
+
"type": "boolean",
|
|
18
|
+
"description": "Switch main.ts to use @softarc/native-federation-orchestrator instead of the legacy runtime",
|
|
19
|
+
"default": false,
|
|
20
|
+
"x-prompt": "Would you like to use the new orchestrator runtime? (recommended)"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schematic.d.ts","sourceRoot":"","sources":["../../../../src/schematics/update-v4/schematic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAQ,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAelD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAgB9D"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
|
2
|
+
import { getWorkspaceFileName } from '../init/schematic.js';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
const V3_PACKAGE = '@angular-architects/native-federation';
|
|
5
|
+
const V4_PACKAGE = '@angular-architects/native-federation-v4';
|
|
6
|
+
const V3_BUILDER = `${V3_PACKAGE}:build`;
|
|
7
|
+
const V4_BUILDER = `${V4_PACKAGE}:build`;
|
|
8
|
+
const V3_RUNTIME_IMPORT = `@angular-architects/native-federation`;
|
|
9
|
+
const V4_RUNTIME_IMPORT = `@softarc/native-federation-runtime`;
|
|
10
|
+
const ORCHESTRATOR_PACKAGE = `@softarc/native-federation-orchestrator`;
|
|
11
|
+
export default function updateV4(options) {
|
|
12
|
+
return async function (tree, context) {
|
|
13
|
+
const workspaceFileName = getWorkspaceFileName(tree);
|
|
14
|
+
const workspace = JSON.parse(tree.read(workspaceFileName)?.toString('utf8') ?? '{}');
|
|
15
|
+
enableEsmInPackageJson(tree);
|
|
16
|
+
updateBuilderReferences(tree, workspace, workspaceFileName);
|
|
17
|
+
migrateFederationConfigs(tree, workspace, options);
|
|
18
|
+
migrateMainTs(tree, workspace, options);
|
|
19
|
+
if (options.orchestrator) {
|
|
20
|
+
installOrchestratorPackage(tree);
|
|
21
|
+
migrateMainTsToOrchestrator(tree, workspace, options);
|
|
22
|
+
context.addTask(new NodePackageInstallTask());
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Step 1: Add "type": "module" to the root package.json
|
|
28
|
+
*/
|
|
29
|
+
function enableEsmInPackageJson(tree) {
|
|
30
|
+
const packageJson = JSON.parse(tree.read('package.json')?.toString('utf8') ?? '{}');
|
|
31
|
+
if (packageJson.type === 'module') {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
packageJson.type = 'module';
|
|
35
|
+
tree.overwrite('package.json', JSON.stringify(packageJson, null, 2));
|
|
36
|
+
console.log('Updated package.json: added "type": "module"');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Step 2: Update all builder references in angular.json / workspace.json
|
|
40
|
+
* from @angular-architects/native-federation:build to @angular-architects/native-federation-v4:build
|
|
41
|
+
*/
|
|
42
|
+
function updateBuilderReferences(tree, workspace, workspaceFileName) {
|
|
43
|
+
let modified = false;
|
|
44
|
+
for (const projectName of Object.keys(workspace.projects ?? {})) {
|
|
45
|
+
const project = workspace.projects[projectName];
|
|
46
|
+
const architect = project?.architect ?? {};
|
|
47
|
+
const sourceRoot = (project?.sourceRoot ?? '').replace(/\\/g, '/');
|
|
48
|
+
for (const targetName of Object.keys(architect)) {
|
|
49
|
+
const target = architect[targetName];
|
|
50
|
+
if (target?.builder === V3_BUILDER) {
|
|
51
|
+
target.builder = V4_BUILDER;
|
|
52
|
+
modified = true;
|
|
53
|
+
console.log(`Updated builder for "${projectName}:${targetName}" to ${V4_BUILDER}`);
|
|
54
|
+
}
|
|
55
|
+
// Add entryPoints and projectName to NF builder targets if not already set
|
|
56
|
+
if ((target?.builder === V3_BUILDER || target?.builder === V4_BUILDER) &&
|
|
57
|
+
!target?.options?.entryPoints) {
|
|
58
|
+
target.options ??= {};
|
|
59
|
+
target.options.entryPoints = [path.join(sourceRoot, 'main.ts')];
|
|
60
|
+
if (!target.options.projectName) {
|
|
61
|
+
target.options.projectName = projectName;
|
|
62
|
+
}
|
|
63
|
+
modified = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (modified) {
|
|
68
|
+
tree.overwrite(workspaceFileName, JSON.stringify(workspace, null, '\t'));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Step 3: Migrate federation.config.js files from CJS to ESM
|
|
73
|
+
* - require() → import
|
|
74
|
+
* - module.exports = → export default
|
|
75
|
+
* - Update package references from v3 to v4
|
|
76
|
+
*/
|
|
77
|
+
function migrateFederationConfigs(tree, workspace, options) {
|
|
78
|
+
const projects = resolveProjects(workspace, options);
|
|
79
|
+
for (const { projectRoot } of projects) {
|
|
80
|
+
const configPath = path.join(projectRoot, 'federation.config.js');
|
|
81
|
+
if (!tree.exists(configPath)) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
let content = tree.readText(configPath);
|
|
85
|
+
const originalContent = content;
|
|
86
|
+
// Convert CJS require to ESM import
|
|
87
|
+
// Matches: const { foo, bar } = require('...');
|
|
88
|
+
const requireRegex = /const\s+(\{[^}]+\})\s*=\s*require\(\s*['"]([^'"]+)['"]\s*\)\s*;?/g;
|
|
89
|
+
const imports = [];
|
|
90
|
+
content = content.replace(requireRegex, (_match, bindings, modulePath) => {
|
|
91
|
+
const updatedPath = modulePath.replace(V3_PACKAGE, V4_PACKAGE);
|
|
92
|
+
imports.push(`import ${bindings} from '${updatedPath}';`);
|
|
93
|
+
return ''; // Remove the require line; import will be prepended
|
|
94
|
+
});
|
|
95
|
+
// Prepend collected imports at the top (after removing old requires)
|
|
96
|
+
if (imports.length > 0) {
|
|
97
|
+
content = imports.join('\n') + '\n' + content.trimStart();
|
|
98
|
+
}
|
|
99
|
+
// Convert module.exports = to export default
|
|
100
|
+
content = content.replace(/module\.exports\s*=\s*/, 'export default ');
|
|
101
|
+
// Also update any remaining inline @angular-architects/native-federation references
|
|
102
|
+
// (e.g. in comments or other import paths) to the v4 package
|
|
103
|
+
content = content.replace(new RegExp(escapeRegExp(V3_PACKAGE + '/config'), 'g'), V4_PACKAGE + '/config');
|
|
104
|
+
content = content.replace(new RegExp(escapeRegExp(V3_PACKAGE) + '(?!/)', 'g'), V4_PACKAGE);
|
|
105
|
+
if (content !== originalContent) {
|
|
106
|
+
tree.overwrite(configPath, content);
|
|
107
|
+
console.log(`Migrated ${configPath} to ESM`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Step 4: Update main.ts imports from @angular-architects/native-federation
|
|
113
|
+
* to @softarc/native-federation-runtime
|
|
114
|
+
*/
|
|
115
|
+
function migrateMainTs(tree, workspace, options) {
|
|
116
|
+
const projects = resolveProjects(workspace, options);
|
|
117
|
+
for (const { projectConfig } of projects) {
|
|
118
|
+
const main = projectConfig?.architect?.build?.options?.browser ??
|
|
119
|
+
projectConfig?.architect?.build?.options?.main ??
|
|
120
|
+
projectConfig?.architect?.esbuild?.options?.browser ??
|
|
121
|
+
projectConfig?.architect?.esbuild?.options?.main;
|
|
122
|
+
if (!main || !tree.exists(main)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
let content = tree.readText(main);
|
|
126
|
+
const originalContent = content;
|
|
127
|
+
// Update initFederation import
|
|
128
|
+
content = content.replace(new RegExp(escapeRegExp(V3_RUNTIME_IMPORT), 'g'), V4_RUNTIME_IMPORT);
|
|
129
|
+
if (content !== originalContent) {
|
|
130
|
+
tree.overwrite(main, content);
|
|
131
|
+
console.log(`Updated initFederation import in ${main}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Optional Step 5: Add @softarc/native-federation-orchestrator to package.json dependencies
|
|
137
|
+
*/
|
|
138
|
+
function installOrchestratorPackage(tree) {
|
|
139
|
+
const packageJson = JSON.parse(tree.read('package.json')?.toString('utf8') ?? '{}');
|
|
140
|
+
if (!packageJson.dependencies) {
|
|
141
|
+
packageJson.dependencies = {};
|
|
142
|
+
}
|
|
143
|
+
if (!packageJson.dependencies[ORCHESTRATOR_PACKAGE]) {
|
|
144
|
+
packageJson.dependencies[ORCHESTRATOR_PACKAGE] = '^4.0.0-RC4';
|
|
145
|
+
tree.overwrite('package.json', JSON.stringify(packageJson, null, 2));
|
|
146
|
+
console.log(`Added ${ORCHESTRATOR_PACKAGE} to dependencies`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Optional Step 6: Surgically update main.ts to use the orchestrator.
|
|
151
|
+
*
|
|
152
|
+
* - Replaces the initFederation import source with @softarc/native-federation-orchestrator
|
|
153
|
+
* - Adds the orchestrator /options import
|
|
154
|
+
* - Rewrites the initFederation() call:
|
|
155
|
+
* - If it had a first argument, keeps it and appends the orchestrator options as second arg
|
|
156
|
+
* - If it had no arguments, uses {} as first arg and the orchestrator options as second arg
|
|
157
|
+
*/
|
|
158
|
+
function migrateMainTsToOrchestrator(tree, workspace, options) {
|
|
159
|
+
const projects = resolveProjects(workspace, options);
|
|
160
|
+
const orchestratorOptions = `{
|
|
161
|
+
...useShimImportMap({ shimMode: true }),
|
|
162
|
+
logger: consoleLogger,
|
|
163
|
+
storage: globalThisStorageEntry,
|
|
164
|
+
hostRemoteEntry: './remoteEntry.json',
|
|
165
|
+
logLevel: 'debug',
|
|
166
|
+
}`;
|
|
167
|
+
const optionsImport = `import {
|
|
168
|
+
useShimImportMap,
|
|
169
|
+
consoleLogger,
|
|
170
|
+
globalThisStorageEntry,
|
|
171
|
+
} from '${ORCHESTRATOR_PACKAGE}/options';`;
|
|
172
|
+
for (const { projectConfig } of projects) {
|
|
173
|
+
const main = projectConfig?.architect?.build?.options?.browser ??
|
|
174
|
+
projectConfig?.architect?.build?.options?.main ??
|
|
175
|
+
projectConfig?.architect?.esbuild?.options?.browser ??
|
|
176
|
+
projectConfig?.architect?.esbuild?.options?.main;
|
|
177
|
+
if (!main || !tree.exists(main)) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
let content = tree.readText(main);
|
|
181
|
+
// 1. Replace the import source to the orchestrator package
|
|
182
|
+
content = content.replace(new RegExp(`from\\s+['"](?:${escapeRegExp(V4_RUNTIME_IMPORT)}|${escapeRegExp(V3_RUNTIME_IMPORT)})['"]`, 'g'), `from '${ORCHESTRATOR_PACKAGE}'`);
|
|
183
|
+
// 2. Add the /options import after the orchestrator import line
|
|
184
|
+
if (!content.includes(`${ORCHESTRATOR_PACKAGE}/options`)) {
|
|
185
|
+
content = content.replace(new RegExp(`(import\\s+\\{[^}]*\\}\\s+from\\s+['"]${escapeRegExp(ORCHESTRATOR_PACKAGE)}['"];?)`), `$1\n${optionsImport}`);
|
|
186
|
+
}
|
|
187
|
+
// 3. Rewrite initFederation(...) call — extract existing first arg if present
|
|
188
|
+
const initMatch = content.match(/initFederation\s*\(([^)]*)\)/s);
|
|
189
|
+
if (initMatch) {
|
|
190
|
+
const existingArgs = initMatch[1].trim();
|
|
191
|
+
const firstArg = existingArgs.length > 0 ? existingArgs : '{}';
|
|
192
|
+
content = content.replace(initMatch[0], `initFederation(${firstArg}, ${orchestratorOptions})`);
|
|
193
|
+
}
|
|
194
|
+
tree.overwrite(main, content);
|
|
195
|
+
console.log(`Switched ${main} to use the orchestrator`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function resolveProjects(workspace, options) {
|
|
199
|
+
const projects = [];
|
|
200
|
+
if (options.project) {
|
|
201
|
+
const projectConfig = workspace.projects?.[options.project];
|
|
202
|
+
if (projectConfig) {
|
|
203
|
+
projects.push({
|
|
204
|
+
projectName: options.project,
|
|
205
|
+
projectRoot: projectConfig.root?.replace(/\\/g, '/') ?? '',
|
|
206
|
+
projectConfig,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// Migrate all projects
|
|
212
|
+
for (const projectName of Object.keys(workspace.projects ?? {})) {
|
|
213
|
+
const projectConfig = workspace.projects[projectName];
|
|
214
|
+
projects.push({
|
|
215
|
+
projectName,
|
|
216
|
+
projectRoot: projectConfig.root?.replace(/\\/g, '/') ?? '',
|
|
217
|
+
projectConfig,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return projects;
|
|
222
|
+
}
|
|
223
|
+
function escapeRegExp(str) {
|
|
224
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
225
|
+
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import type { ApplicationBuilderOptions } from '@angular/build';
|
|
5
|
-
import type { EntryPoint, FederationCache } from '@softarc/native-federation';
|
|
6
|
-
import type { MappedPath } from '@softarc/native-federation/internal';
|
|
7
|
-
export interface AngularBundleResult {
|
|
2
|
+
import type { NormalizedContextOptions } from './normalize-context-options.js';
|
|
3
|
+
export declare function createAngularEsbuildContext(options: NormalizedContextOptions): Promise<{
|
|
8
4
|
ctx: esbuild.BuildContext;
|
|
9
5
|
pluginDisposed: Promise<void>;
|
|
10
|
-
}
|
|
11
|
-
export declare function createAngularEsbuildContext(builderOptions: ApplicationBuilderOptions, context: BuilderContext, entryPoints: EntryPoint[], external: string[], outdir: string, tsConfigPath: string, mappedPaths: MappedPath[], cache: FederationCache<SourceFileCache>, dev?: boolean, hash?: boolean, chunks?: boolean, platform?: 'browser' | 'node', optimizedMappings?: boolean): Promise<AngularBundleResult>;
|
|
6
|
+
}>;
|
|
12
7
|
//# sourceMappingURL=angular-bundler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-bundler.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-bundler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"angular-bundler.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-bundler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAoBnC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAG/E,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC;IAC5F,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B,CAAC,CAkJD"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
3
|
import { createRequire } from 'node:module';
|
|
5
|
-
import { isDeepStrictEqual } from 'node:util';
|
|
6
|
-
import JSON5 from 'json5';
|
|
7
4
|
import { transformSupportedBrowsersToTargets, getSupportedBrowsers, generateSearchDirectories, findTailwindConfiguration, loadPostcssConfiguration, } from '@angular/build/private';
|
|
8
5
|
import { normalizeOptimization, normalizeSourceMaps, } from '@angular-devkit/build-angular/src/utils/index.js';
|
|
9
|
-
import { createSharedMappingsPlugin } from './shared-mappings-plugin.js';
|
|
10
6
|
import { createAwaitableCompilerPlugin } from './create-awaitable-compiler-plugin.js';
|
|
11
|
-
|
|
7
|
+
import { createFederationTsConfig } from './create-federation-tsconfig.js';
|
|
8
|
+
export async function createAngularEsbuildContext(options) {
|
|
9
|
+
const { builderOptions, context, entryPoints, external, outdir, cache, dev, hash, chunks, platform, optimizedMappings, } = options;
|
|
10
|
+
let tsConfigPath = options.tsConfigPath;
|
|
11
|
+
if (!tsConfigPath) {
|
|
12
|
+
throw new Error('tsConfigPath is required for Angular/esbuild context creation');
|
|
13
|
+
}
|
|
12
14
|
const workspaceRoot = context.workspaceRoot;
|
|
13
15
|
const projectMetadata = await context.getProjectMetadata(context.target.project);
|
|
14
16
|
const projectRoot = path.join(workspaceRoot, projectMetadata['root'] ?? '');
|
|
@@ -32,7 +34,7 @@ export async function createAngularEsbuildContext(builderOptions, context, entry
|
|
|
32
34
|
fileReplacements[path.join(workspaceRoot, replacement.replace)] = path.join(workspaceRoot, replacement.with);
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
|
-
tsConfigPath =
|
|
37
|
+
tsConfigPath = createFederationTsConfig(workspaceRoot, tsConfigPath, entryPoints, optimizedMappings);
|
|
36
38
|
const pluginOptions = {
|
|
37
39
|
sourcemap: !!sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
|
|
38
40
|
thirdPartySourcemaps: sourcemapOptions.vendor,
|
|
@@ -95,13 +97,9 @@ export async function createAngularEsbuildContext(builderOptions, context, entry
|
|
|
95
97
|
format: 'esm',
|
|
96
98
|
target: target,
|
|
97
99
|
logLimit: 0,
|
|
98
|
-
plugins: [
|
|
99
|
-
compilerPlugin,
|
|
100
|
-
...(mappedPaths && mappedPaths.length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []),
|
|
101
|
-
commonjsPlugin(),
|
|
102
|
-
],
|
|
100
|
+
plugins: [compilerPlugin, commonjsPlugin()],
|
|
103
101
|
define: {
|
|
104
|
-
|
|
102
|
+
ngDevMode: dev ? 'true' : 'false',
|
|
105
103
|
ngJitMode: 'false',
|
|
106
104
|
},
|
|
107
105
|
...(builderOptions.loader ? { loader: builderOptions.loader } : {}),
|
|
@@ -120,48 +118,3 @@ async function getTailwindConfig(searchDirectories) {
|
|
|
120
118
|
package: createRequire(tailwindConfigurationPath).resolve('tailwindcss'),
|
|
121
119
|
};
|
|
122
120
|
}
|
|
123
|
-
/**
|
|
124
|
-
* Creates a tsconfig.federation.json that includes the federation entry points.
|
|
125
|
-
*/
|
|
126
|
-
function createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints, optimizedMappings) {
|
|
127
|
-
const fullTsConfigPath = path.join(workspaceRoot, tsConfigPath);
|
|
128
|
-
const tsconfigDir = path.dirname(fullTsConfigPath);
|
|
129
|
-
const tsconfigAsString = fs.readFileSync(fullTsConfigPath, 'utf-8');
|
|
130
|
-
const tsconfig = JSON5.parse(tsconfigAsString);
|
|
131
|
-
tsconfig.files = entryPoints
|
|
132
|
-
.filter(ep => ep.fileName.startsWith('.'))
|
|
133
|
-
.map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
|
|
134
|
-
if (optimizedMappings) {
|
|
135
|
-
const filtered = entryPoints
|
|
136
|
-
.filter(ep => !ep.fileName.startsWith('.'))
|
|
137
|
-
.map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
|
|
138
|
-
if (!tsconfig.include) {
|
|
139
|
-
tsconfig.include = [];
|
|
140
|
-
}
|
|
141
|
-
for (const ep of filtered) {
|
|
142
|
-
if (!tsconfig.include.includes(ep)) {
|
|
143
|
-
tsconfig.include.push(ep);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const content = JSON5.stringify(tsconfig, null, 2);
|
|
148
|
-
const tsconfigFedPath = path.join(tsconfigDir, 'tsconfig.federation.json');
|
|
149
|
-
if (!doesFileExistAndJsonEqual(tsconfigFedPath, content)) {
|
|
150
|
-
fs.writeFileSync(tsconfigFedPath, JSON.stringify(tsconfig, null, 2));
|
|
151
|
-
}
|
|
152
|
-
return tsconfigFedPath;
|
|
153
|
-
}
|
|
154
|
-
function doesFileExistAndJsonEqual(filePath, content) {
|
|
155
|
-
if (!fs.existsSync(filePath)) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
try {
|
|
159
|
-
const currentContent = fs.readFileSync(filePath, 'utf-8');
|
|
160
|
-
const currentJson = JSON5.parse(currentContent);
|
|
161
|
-
const newJson = JSON5.parse(content);
|
|
162
|
-
return isDeepStrictEqual(currentJson, newJson);
|
|
163
|
-
}
|
|
164
|
-
catch {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { type NFBuildAdapter } from '@softarc/native-federation';
|
|
1
|
+
import { type NFBuildAdapter, type NFBuildAdapterContext, type FederationCache } from '@softarc/native-federation';
|
|
2
2
|
import * as esbuild from 'esbuild';
|
|
3
|
+
import type { SourceFileCache } from '@angular/build/private';
|
|
3
4
|
import type { BuilderContext } from '@angular-devkit/architect';
|
|
4
5
|
import type { ApplicationBuilderOptions } from '@angular/build';
|
|
5
|
-
export interface EsbuildContextResult {
|
|
6
|
-
ctx: esbuild.BuildContext;
|
|
6
|
+
export interface EsbuildContextResult extends NFBuildAdapterContext<esbuild.BuildContext> {
|
|
7
7
|
pluginDisposed: Promise<void>;
|
|
8
|
+
cache: FederationCache<SourceFileCache>;
|
|
8
9
|
}
|
|
9
|
-
export declare function createAngularBuildAdapter(
|
|
10
|
+
export declare function createAngularBuildAdapter(ngBuilderOptions: ApplicationBuilderOptions, context: BuilderContext): NFBuildAdapter;
|
|
10
11
|
//# sourceMappingURL=angular-esbuild-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-esbuild-adapter.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-esbuild-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"angular-esbuild-adapter.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-esbuild-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAKhE,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB,CAAC,OAAO,CAAC,YAAY,CAAC;IACvF,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,KAAK,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;CACzC;AAsCD,wBAAgB,yBAAyB,CACvC,gBAAgB,EAAE,yBAAyB,EAC3C,OAAO,EAAE,cAAc,GACtB,cAAc,CA8FhB"}
|
|
@@ -4,12 +4,7 @@ import { AbortedError } from '@softarc/native-federation/internal';
|
|
|
4
4
|
import * as esbuild from 'esbuild';
|
|
5
5
|
import { createAngularEsbuildContext } from './angular-bundler.js';
|
|
6
6
|
import { createNodeModulesEsbuildContext } from './node-modules-bundler.js';
|
|
7
|
-
|
|
8
|
-
if (isNodeModules) {
|
|
9
|
-
return createNodeModulesEsbuildContext(builderOptions, context, entryPoints, external, outdir, mappedPaths, cache, dev, hash, chunks, platform);
|
|
10
|
-
}
|
|
11
|
-
return createAngularEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, hash, chunks, platform, optimizedMappings);
|
|
12
|
-
}
|
|
7
|
+
import { normalizeContextOptions } from './normalize-context-options.js';
|
|
13
8
|
function writeResult(result, outdir) {
|
|
14
9
|
const writtenFiles = [];
|
|
15
10
|
for (const outFile of result.outputFiles ?? []) {
|
|
@@ -42,7 +37,7 @@ function setNgServerMode() {
|
|
|
42
37
|
console.error('Error patching file ', fileToPatch, '\nIs it write-protected?');
|
|
43
38
|
}
|
|
44
39
|
}
|
|
45
|
-
export function createAngularBuildAdapter(
|
|
40
|
+
export function createAngularBuildAdapter(ngBuilderOptions, context) {
|
|
46
41
|
const bundleContextCache = new Map();
|
|
47
42
|
const dispose = async (name) => {
|
|
48
43
|
if (name) {
|
|
@@ -65,21 +60,23 @@ export function createAngularBuildAdapter(builderOptions, context) {
|
|
|
65
60
|
await Promise.all(disposals);
|
|
66
61
|
await esbuild.stop();
|
|
67
62
|
};
|
|
68
|
-
const setup = async (
|
|
69
|
-
const { entryPoints, tsConfigPath, external, outdir, mappedPaths, bundleName, isNodeModules, dev, chunks, hash, platform, optimizedMappings, cache, } = options;
|
|
63
|
+
const setup = async (name, adapterOptions) => {
|
|
70
64
|
setNgServerMode();
|
|
71
|
-
if (bundleContextCache.has(
|
|
65
|
+
if (bundleContextCache.has(name)) {
|
|
72
66
|
return;
|
|
73
67
|
}
|
|
74
|
-
const
|
|
75
|
-
|
|
68
|
+
const normalizedOptions = normalizeContextOptions(ngBuilderOptions, context, adapterOptions);
|
|
69
|
+
const { ctx, pluginDisposed } = normalizedOptions.isMappingOrExposed
|
|
70
|
+
? await createAngularEsbuildContext(normalizedOptions)
|
|
71
|
+
: await createNodeModulesEsbuildContext(normalizedOptions);
|
|
72
|
+
bundleContextCache.set(name, {
|
|
76
73
|
ctx,
|
|
77
74
|
pluginDisposed,
|
|
78
|
-
outdir,
|
|
79
|
-
cache,
|
|
80
|
-
|
|
81
|
-
dev:
|
|
82
|
-
name
|
|
75
|
+
outdir: normalizedOptions.outdir,
|
|
76
|
+
cache: normalizedOptions.cache,
|
|
77
|
+
isMappingOrExposed: normalizedOptions.isMappingOrExposed,
|
|
78
|
+
dev: normalizedOptions.dev,
|
|
79
|
+
name,
|
|
83
80
|
});
|
|
84
81
|
};
|
|
85
82
|
const build = async (name, opts = {}) => {
|
|
@@ -91,8 +88,8 @@ export function createAngularBuildAdapter(builderOptions, context) {
|
|
|
91
88
|
throw new AbortedError('[build] Aborted before rebuild');
|
|
92
89
|
}
|
|
93
90
|
try {
|
|
94
|
-
if (opts.
|
|
95
|
-
bundleContext.cache.bundlerCache.invalidate(new Set(opts.
|
|
91
|
+
if (opts.modifiedFiles) {
|
|
92
|
+
bundleContext.cache.bundlerCache.invalidate(new Set(opts.modifiedFiles));
|
|
96
93
|
}
|
|
97
94
|
const result = await bundleContext.ctx.rebuild();
|
|
98
95
|
const writtenFiles = writeResult(result, bundleContext.outdir);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-locales.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-locales.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAE/E,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,
|
|
1
|
+
{"version":3,"file":"angular-locales.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-locales.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAE/E,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,qEA0BzD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EntryPoint } from '@softarc/native-federation';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a tsconfig.federation.json that includes the federation entry points.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createFederationTsConfig(workspaceRoot: string, tsConfigPath: string, entryPoints: EntryPoint[], optimizedMappings?: boolean): string;
|
|
6
|
+
//# sourceMappingURL=create-federation-tsconfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-federation-tsconfig.d.ts","sourceRoot":"","sources":["../../../src/utils/create-federation-tsconfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAM7D;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,UAAU,EAAE,EACzB,iBAAiB,CAAC,EAAE,OAAO,GAC1B,MAAM,CAoCR"}
|