From e7674eb9032237b6ce28ca90b4427443fc0f50c5 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:41:50 -0400 Subject: [PATCH] refactor(@angular/build): allow Bazel to inject a custom esbuild plugin Introduces a mechanism to dynamically load a custom esbuild plugin when the application builder is executed within a Bazel environment. This is enabled by a new `bazelEsbuildPluginPath` option, which is derived from the `NG_INTERNAL_ESBUILD_PLUGINS_DO_NOT_USE` environment variable. The path is only resolved if the `BAZEL_BINDIR` and `JS_BINARY__EXECROOT` environment variables are also present, ensuring the logic is only active during a Bazel build. The builder dynamically imports the plugin from the specified path and adds it to the esbuild pipeline, allowing for build-system-specific customizations. --- .../angular/build/src/builders/application/index.ts | 10 +++++++++- .../angular/build/src/utils/environment-options.ts | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/application/index.ts b/packages/angular/build/src/builders/application/index.ts index 8f11f2fd8001..b83e3b48f270 100644 --- a/packages/angular/build/src/builders/application/index.ts +++ b/packages/angular/build/src/builders/application/index.ts @@ -14,7 +14,7 @@ import { BuildOutputFileType } from '../../tools/esbuild/bundler-context'; import { createJsonBuildManifest, emitFilesToDisk } from '../../tools/esbuild/utils'; import { colors as ansiColors } from '../../utils/color'; import { deleteOutputDir } from '../../utils/delete-output-dir'; -import { useJSONBuildLogs } from '../../utils/environment-options'; +import { bazelEsbuildPluginPath, useJSONBuildLogs } from '../../utils/environment-options'; import { purgeStaleBuildCache } from '../../utils/purge-cache'; import { assertCompatibleAngularVersion } from '../../utils/version'; import { runEsBuildBuildAction } from './build-action'; @@ -56,6 +56,14 @@ export async function* buildApplicationInternal( return; } + if (bazelEsbuildPluginPath) { + extensions ??= {}; + extensions.codePlugins ??= []; + + const { default: bazelEsbuildPlugin } = await import(bazelEsbuildPluginPath); + extensions.codePlugins.push(bazelEsbuildPlugin); + } + const normalizedOptions = await normalizeOptions(context, projectName, options, extensions); if (!normalizedOptions.outputOptions.ignoreServer) { diff --git a/packages/angular/build/src/utils/environment-options.ts b/packages/angular/build/src/utils/environment-options.ts index a5649a33d7b5..80f71d56c119 100644 --- a/packages/angular/build/src/utils/environment-options.ts +++ b/packages/angular/build/src/utils/environment-options.ts @@ -165,3 +165,11 @@ export const useComponentTemplateHmr = parseTristate(process.env['NG_HMR_TEMPLAT * When `NG_BUILD_PARTIAL_SSR` is enabled, a partial server-side rendering build will be performed. */ export const usePartialSsrBuild = parseTristate(process.env['NG_BUILD_PARTIAL_SSR']) === true; + +const bazelBinDirectory = process.env['BAZEL_BINDIR']; +const bazelExecRoot = process.env['JS_BINARY__EXECROOT']; + +export const bazelEsbuildPluginPath = + bazelBinDirectory && bazelExecRoot + ? process.env['NG_INTERNAL_ESBUILD_PLUGINS_DO_NOT_USE'] + : undefined;