Skip to content

Commit af52fb4

Browse files
clydinjkrems
authored andcommitted
fix(@angular/build): synchronize import/export conditions between bundler and TypeScript
To improve type-checking and reduce hard to diagnose errors when using the new `production`/`development` conditions, the set of conditions used by the bundler are now also synchronized with those used by TypeScript. This helps ensure that type mismatches are avoided by type-checking against the actual file that will be bundled into the output.
1 parent e448cf6 commit af52fb4

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

modules/testing/builder/src/dev_prod_mode.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,22 @@ export async function setupConditionImport(harness: BuilderHarness<unknown>) {
1616
// Files that can be used as targets for the conditional import.
1717
await harness.writeFile('src/good.ts', `export const VALUE = 'good-value';`);
1818
await harness.writeFile('src/bad.ts', `export const VALUE = 'bad-value';`);
19+
await harness.writeFile('src/wrong.ts', `export const VALUE = 1;`);
1920

2021
// Simple application file that accesses conditional code.
2122
await harness.writeFile(
2223
'src/main.ts',
2324
`import {VALUE} from '#target';
2425
console.log(VALUE);
26+
console.log(VALUE.length);
2527
export default 42 as any;
2628
`,
2729
);
2830

2931
// Ensure that good/bad can be resolved from tsconfig.
3032
const tsconfig = JSON.parse(harness.readFile('src/tsconfig.app.json')) as TypeScriptConfig;
3133
tsconfig.compilerOptions.moduleResolution = 'bundler';
32-
tsconfig.files.push('good.ts', 'bad.ts');
34+
tsconfig.files.push('good.ts', 'bad.ts', 'wrong.ts');
3335
await harness.writeFile('src/tsconfig.app.json', JSON.stringify(tsconfig));
3436
}
3537

packages/angular/build/src/builders/application/tests/behavior/build-conditions_spec.ts

+21
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,26 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
9191
});
9292
});
9393
}
94+
95+
it('fails type-checking when import contains differing type', async () => {
96+
await setTargetMapping(harness, {
97+
'development': './src/wrong.ts',
98+
'default': './src/good.ts',
99+
});
100+
101+
harness.useTarget('build', {
102+
...BASE_OPTIONS,
103+
optimization: false,
104+
});
105+
106+
const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false });
107+
108+
expect(result?.success).toBeFalse();
109+
expect(logs).toContain(
110+
jasmine.objectContaining({
111+
message: jasmine.stringMatching('TS2339'),
112+
}),
113+
);
114+
});
94115
});
95116
});

packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,12 @@ export function createCompilerPlugin(
286286
const initializationResult = await compilation.initialize(
287287
pluginOptions.tsconfig,
288288
hostOptions,
289-
createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks),
289+
createCompilerOptionsTransformer(
290+
setupWarnings,
291+
pluginOptions,
292+
preserveSymlinks,
293+
build.initialOptions.conditions,
294+
),
290295
);
291296
shouldTsIgnoreJs = !initializationResult.compilerOptions.allowJs;
292297
// Isolated modules option ensures safe non-TypeScript transpilation.
@@ -572,6 +577,7 @@ function createCompilerOptionsTransformer(
572577
setupWarnings: PartialMessage[] | undefined,
573578
pluginOptions: CompilerPluginOptions,
574579
preserveSymlinks: boolean | undefined,
580+
customConditions: string[] | undefined,
575581
): Parameters<AngularCompilation['initialize']>[2] {
576582
return (compilerOptions) => {
577583
// target of 9 is ES2022 (using the number avoids an expensive import of typescript just for an enum)
@@ -631,6 +637,12 @@ function createCompilerOptionsTransformer(
631637
});
632638
}
633639

640+
// Synchronize custom resolve conditions.
641+
// Set if using the supported bundler resolution mode (bundler is the default in new projects)
642+
if (compilerOptions.moduleResolution === 100 /* ModuleResolutionKind.Bundler */) {
643+
compilerOptions.customConditions = customConditions;
644+
}
645+
634646
return {
635647
...compilerOptions,
636648
noEmitOnError: false,

0 commit comments

Comments
 (0)