Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions migration-collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
"factory": "./src/schematics/update22/schematic",
"schema": "./src/schematics/update22/schema.json",
"description": "migrating native-federation to the v22 ESM standard and generating a tsconfig.federation.json per federated project"
},
"update22-2": {
"version": "22.2.0",
"factory": "./src/schematics/update22-2/schematic",
"schema": "./src/schematics/update22-2/schema.json",
"description": "removing the no longer used \"files\" from each tsconfig.federation.json"
}
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
"@angular-devkit/core": "~22.1.0",
"@angular-devkit/schematics": "~22.1.0",
"@chialab/esbuild-plugin-commonjs": "^0.19.0",
"@softarc/native-federation": "~4.6.0",
"@softarc/native-federation": "~4.7.0",
"@softarc/native-federation-orchestrator": "^4.6.0",
"es-module-shims": "^2.8.0",
"esbuild": "^0.28.0",
"jsonc-parser": "^3.3.1",
"mrmime": "^2.0.1",
"watchpack": "^2.5.2"
},
Expand Down Expand Up @@ -82,7 +83,6 @@
"eslint": "^10.8.0",
"globals": "^17.0.0",
"jiti": "^2.6.0",
"json5": "^2.2.3",
"knip": "^6.17.1",
"tslib": "^2.3.0",
"typescript": "~6.0.0",
Expand Down
18 changes: 10 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/builders/build/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,10 +526,10 @@ export async function* runBuilder(
process.exit(1);
}

// Dispose the finished federation context so its compiler-plugin onDispose resets
// Angular's shared TS compilation state before the app build (#47); watch reuses it.
// Each compiler plugin's onDispose resets Angular's shared TS compilation state before the
// app build (#47); watch reuses the contexts.
if (!watch) {
await adapter.dispose("mapping-or-exposed").catch(() => undefined);
await adapter.disposeFederationContexts();
}

syncFederationWatcher();
Expand Down
6 changes: 2 additions & 4 deletions src/builders/build/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ export type NfInternalOptions = {
instrumentForCoverage?: (filename: string) => boolean;

/**
* Whether the tsconfig the federation build resolved to is the builder's to rewrite (see
* tools/esbuild/update-federation-tsconfig.ts). True only when the NF target declares a
* `tsConfig` of its own; without one the build falls back to the Angular target's tsconfig,
* where `files` is Angular's — replacing it would drop main.ts from the app's own program.
* Whether each build context gets a generated tsconfig extending the resolved one. True only
* when the NF target declares a `tsConfig` of its own.
*/
manageTsConfig?: boolean;

Expand Down
12 changes: 1 addition & 11 deletions src/schematics/init/schematic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export default function config(options: NfSchematicSchema): Rule {
projectRoot,
projectSourceRoot,
manifestPath,
main,
} = normalized;

updatePolyfills(tree, polyfills);
Expand Down Expand Up @@ -82,16 +81,7 @@ export default function config(options: NfSchematicSchema): Rule {
const ssr = isSsrProject(normalized);
const server = ssr ? getSsrFilePath(normalized) : '';

// Seed the federation program with what the generated config exposes, so the first build
// finds the tsconfig already correct. Where the exposes are unknown (a host, a config we
// did not write, or a project without a recognisable app component) main.ts stands in —
// the same fallback the builder applies.
const exposesAppComponent =
!exists && options.type === 'remote' && appComponent !== 'update-this.ts';

const federationTsConfig = generateFederationTsConfig(tree, normalized, [
exposesAppComponent ? appComponent : main,
]);
const federationTsConfig = generateFederationTsConfig(tree, normalized);

updateWorkspaceConfig(tree, normalized, workspace, workspaceFileName, ssr, federationTsConfig);

Expand Down
37 changes: 10 additions & 27 deletions src/schematics/init/steps/generate-federation-tsconfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { EmptyTree, type Tree } from '@angular-devkit/schematics';
import { generateFederationTsConfig } from './generate-federation-tsconfig.js';
import type { NormalizedOptions } from './normalize-options.js';

const EXPOSED = ['projects/mfe1/src/app/app.ts'];

function makeOptions(overrides: Partial<NormalizedOptions> = {}): NormalizedOptions {
return {
polyfills: [] as unknown as string,
Expand Down Expand Up @@ -38,34 +36,22 @@ describe('generateFederationTsConfig', () => {
tree = new EmptyTree();
});

it('creates a federation tsconfig extending the app tsconfig', () => {
const result = generateFederationTsConfig(tree, makeOptions(), EXPOSED);
// Each build context supplies its own `files` (tools/esbuild/write-context-tsconfig.ts), so
// a seeded list would only go stale.
it('creates a federation tsconfig extending the app tsconfig, without files', () => {
const result = generateFederationTsConfig(tree, makeOptions());

expect(result).toBe('projects/mfe1/tsconfig.federation.json');
expect(read(tree, result)).toEqual({
extends: './tsconfig.app.json',
files: ['src/app/app.ts'],
include: ['src/**/*.d.ts'],
});
});

// An empty `files` list is a TypeScript error (TS18002) unless the config also extends
// another one, so neither key may be dropped from the generated shape.
it('always emits both extends and a non-empty files list', () => {
const result = generateFederationTsConfig(tree, makeOptions(), [
'projects/mfe1/src/main.ts',
]);

const tsconfig = read(tree, result);
expect(tsconfig.extends).toBeTruthy();
expect(tsconfig.files).toEqual(['src/main.ts']);
});

it('derives the include glob from the project source root', () => {
const result = generateFederationTsConfig(
tree,
makeOptions({ projectSourceRoot: 'projects/mfe1/app-src' }),
EXPOSED
makeOptions({ projectSourceRoot: 'projects/mfe1/app-src' })
);

expect(read(tree, result).include).toEqual(['app-src/**/*.d.ts']);
Expand All @@ -83,8 +69,7 @@ describe('generateFederationTsConfig', () => {
},
},
},
}),
EXPOSED
})
);

expect(read(tree, result).extends).toBe('../../tsconfig.app.json');
Expand All @@ -93,7 +78,7 @@ describe('generateFederationTsConfig', () => {
it('leaves an existing federation tsconfig untouched', () => {
tree.create('projects/mfe1/tsconfig.federation.json', '{ "files": ["src/bootstrap.ts"] }');

const result = generateFederationTsConfig(tree, makeOptions(), EXPOSED);
const result = generateFederationTsConfig(tree, makeOptions());

expect(read(tree, result)).toEqual({ files: ['src/bootstrap.ts'] });
});
Expand All @@ -102,7 +87,7 @@ describe('generateFederationTsConfig', () => {
const options = makeOptions();
options.projectConfig.architect.build.builder = '@angular-architects/native-federation:build';

const result = generateFederationTsConfig(tree, options, EXPOSED);
const result = generateFederationTsConfig(tree, options);

expect(tree.exists(result)).toBe(false);
});
Expand All @@ -118,8 +103,7 @@ describe('generateFederationTsConfig', () => {
esbuild: { options: { tsConfig: 'projects/mfe1/tsconfig.app.json' } },
},
},
}),
EXPOSED
})
);

expect(read(tree, result).extends).toBe('./tsconfig.app.json');
Expand All @@ -133,8 +117,7 @@ describe('generateFederationTsConfig', () => {
projectConfig: {
architect: { build: { builder: '@angular/build:application', options: {} } },
},
}),
EXPOSED
})
)
).toThrow('has no tsConfig');
});
Expand Down
24 changes: 4 additions & 20 deletions src/schematics/init/steps/generate-federation-tsconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,12 @@ export interface FederationTsConfigOptions {
projectSourceRoot: string;
/** Workspace-relative path of the tsconfig to extend, usually the app's. */
appTsConfig: string;
/** Workspace-relative entry points seeding the program. */
entryPoints: string[];
}

/**
* Writes the tsconfig the federation build compiles against. It covers the exposes and shared
* mappings rather than the app entry, so `files` is a plain list of entry points that the
* builder rewrites per build (see tools/esbuild/update-federation-tsconfig.ts) and `include`
* only picks up ambient declarations. It extends the app tsconfig because it also drives
* esbuild's module resolution and so needs its paths.
*
* Both `extends` and `files` have to stay present: TypeScript reports an empty `files` list
* (TS18002) unless the config also extends another one.
*/
// No `files`: each build context supplies its own (tools/esbuild/write-context-tsconfig.ts).
// Extends the app tsconfig for its paths, which esbuild's module resolution also needs.
export function writeFederationTsConfig(tree: Tree, options: FederationTsConfigOptions): string {
const { projectRoot, projectSourceRoot, appTsConfig, entryPoints } = options;
const { projectRoot, projectSourceRoot, appTsConfig } = options;

const federationTsConfig = federationTsConfigPath(projectRoot);

Expand All @@ -44,7 +34,6 @@ export function writeFederationTsConfig(tree: Tree, options: FederationTsConfigO
JSON.stringify(
{
extends: extendsPath.startsWith('.') ? extendsPath : `./${extendsPath}`,
files: entryPoints.map(entry => toPosix(path.relative(projectRoot, entry))),
include: [`${sourceDir}/**/*.d.ts`],
},
null,
Expand All @@ -55,11 +44,7 @@ export function writeFederationTsConfig(tree: Tree, options: FederationTsConfigO
return federationTsConfig;
}

export function generateFederationTsConfig(
tree: Tree,
options: NormalizedOptions,
entryPoints: string[]
): string {
export function generateFederationTsConfig(tree: Tree, options: NormalizedOptions): string {
const { projectConfig, projectRoot, projectSourceRoot } = options;

const federationTsConfig = federationTsConfigPath(projectRoot);
Expand All @@ -80,6 +65,5 @@ export function generateFederationTsConfig(
projectRoot,
projectSourceRoot,
appTsConfig,
entryPoints,
});
}
7 changes: 7 additions & 0 deletions src/schematics/update22-2/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "update22-2",
"title": "",
"type": "object",
"properties": {}
}
Loading
Loading