From c81dd817dfd74a12ecfc51af612e91d4592ff000 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:16:59 -0500 Subject: [PATCH] fix(@angular/build): allow .json file replacements with application builds When using the `application` builder, the `fileReplacements` option will now work as it previous did with the `browser` builder when replacing JSON files. --- .../tests/options/file-replacements_spec.ts | 37 +++++++++++++++++++ .../tools/esbuild/angular/compiler-plugin.ts | 25 +++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 packages/angular/build/src/builders/application/tests/options/file-replacements_spec.ts diff --git a/packages/angular/build/src/builders/application/tests/options/file-replacements_spec.ts b/packages/angular/build/src/builders/application/tests/options/file-replacements_spec.ts new file mode 100644 index 0000000000..a937f0bc43 --- /dev/null +++ b/packages/angular/build/src/builders/application/tests/options/file-replacements_spec.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { buildApplication } from '../../index'; +import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setup'; + +describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { + describe('Option: "fileReplacements"', () => { + it('should replace JSON files', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + fileReplacements: [{ replace: './src/one.json', with: './src/two.json' }], + }); + + await harness.modifyFile('tsconfig.json', (content) => { + const tsconfig = JSON.parse(content); + tsconfig.compilerOptions.resolveJsonModule = true; + + return JSON.stringify(tsconfig); + }); + + await harness.writeFile('./src/one.json', '{ "x": 12345 }'); + await harness.writeFile('./src/two.json', '{ "x": 67890 }'); + await harness.writeFile('src/main.ts', 'import { x } from "./one.json";\n console.log(x);'); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBe(true); + harness.expectFile('dist/browser/main.js').content.not.toContain('12345'); + harness.expectFile('dist/browser/main.js').content.toContain('67890'); + }); + }); +}); diff --git a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts index 2bff4b4278..0e3e3fa8e0 100644 --- a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts +++ b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts @@ -512,6 +512,31 @@ export function createCompilerPlugin( }), ); + // Add a load handler if there are file replacement option entries for JSON files + if ( + pluginOptions.fileReplacements && + Object.keys(pluginOptions.fileReplacements).some((value) => value.endsWith('.json')) + ) { + build.onLoad( + { filter: /\.json$/ }, + createCachedLoad(pluginOptions.loadResultCache, async (args) => { + const replacement = pluginOptions.fileReplacements?.[path.normalize(args.path)]; + if (replacement) { + return { + contents: await import('fs/promises').then(({ readFile }) => + readFile(path.normalize(replacement)), + ), + loader: 'json' as const, + watchFiles: [replacement], + }; + } + + // If no replacement defined, let esbuild handle it directly + return null; + }), + ); + } + // Setup bundling of component templates and stylesheets when in JIT mode if (pluginOptions.jit) { setupJitPluginCallbacks(