Skip to content

Commit 66edac4

Browse files
clydinalan-agius4
authored andcommitted
refactor(@angular-devkit/build-angular): add index HTML transformer to application programmatic usage
Similar to the `dev-server` builder, the `application` builder's programmatic usage can now transform the index HTML that is generated during a build. As is the case for the existing builder JavaScript exports from the package, the new export (`buildApplication`) is also considered experimental and does not provide the support nor semver guarantees that the builders have when used via `angular.json` configuration. The third parameter of the `buildApplication` function can now be an extensions object with one of the fields being `indexHtmlTransformer`. This newly introduced field allows adjusting the index HTML content. Closes angular#26299
1 parent 68dfe3b commit 66edac4

File tree

5 files changed

+63
-25
lines changed

5 files changed

+63
-25
lines changed

goldens/public-api/angular_devkit/build_angular/index.md

+4-7
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,10 @@ export interface Budget {
149149
}
150150

151151
// @public
152-
export function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, plugins?: Plugin_2[]): AsyncIterable<BuilderOutput & {
153-
outputFiles?: BuildOutputFile[];
154-
assetFiles?: {
155-
source: string;
156-
destination: string;
157-
}[];
158-
}>;
152+
export function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, plugins?: Plugin_2[]): AsyncIterable<ApplicationBuilderOutput>;
153+
154+
// @public
155+
export function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, extensions?: ApplicationBuilderExtensions): AsyncIterable<ApplicationBuilderOutput>;
159156

160157
// @public
161158
export enum CrossOrigin {

packages/angular_devkit/build_angular/src/builders/application/index.ts

+47-15
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import { purgeStaleBuildCache } from '../../utils/purge-cache';
1313
import { assertCompatibleAngularVersion } from '../../utils/version';
1414
import { runEsBuildBuildAction } from './build-action';
1515
import { executeBuild } from './execute-build';
16-
import { ApplicationBuilderInternalOptions, normalizeOptions } from './options';
16+
import {
17+
ApplicationBuilderExtensions,
18+
ApplicationBuilderInternalOptions,
19+
normalizeOptions,
20+
} from './options';
1721
import { Schema as ApplicationBuilderOptions } from './schema';
1822

1923
export { ApplicationBuilderOptions };
@@ -25,13 +29,8 @@ export async function* buildApplicationInternal(
2529
infrastructureSettings?: {
2630
write?: boolean;
2731
},
28-
plugins?: Plugin[],
29-
): AsyncIterable<
30-
BuilderOutput & {
31-
outputFiles?: BuildOutputFile[];
32-
assetFiles?: { source: string; destination: string }[];
33-
}
34-
> {
32+
extensions?: ApplicationBuilderExtensions,
33+
): AsyncIterable<ApplicationBuilderOutput> {
3534
// Check Angular version.
3635
assertCompatibleAngularVersion(context.workspaceRoot);
3736

@@ -46,7 +45,7 @@ export async function* buildApplicationInternal(
4645
return;
4746
}
4847

49-
const normalizedOptions = await normalizeOptions(context, projectName, options, plugins);
48+
const normalizedOptions = await normalizeOptions(context, projectName, options, extensions);
5049

5150
// Setup an abort controller with a builder teardown if no signal is present
5251
let signal = context.signal;
@@ -94,6 +93,11 @@ export async function* buildApplicationInternal(
9493
);
9594
}
9695

96+
export interface ApplicationBuilderOutput extends BuilderOutput {
97+
outputFiles?: BuildOutputFile[];
98+
assetFiles?: { source: string; destination: string }[];
99+
}
100+
97101
/**
98102
* Builds an application using the `application` builder with the provided
99103
* options.
@@ -112,13 +116,41 @@ export function buildApplication(
112116
options: ApplicationBuilderOptions,
113117
context: BuilderContext,
114118
plugins?: Plugin[],
115-
): AsyncIterable<
116-
BuilderOutput & {
117-
outputFiles?: BuildOutputFile[];
118-
assetFiles?: { source: string; destination: string }[];
119+
): AsyncIterable<ApplicationBuilderOutput>;
120+
121+
/**
122+
* Builds an application using the `application` builder with the provided
123+
* options.
124+
*
125+
* Usage of the `extensions` parameter is NOT supported and may cause unexpected
126+
* build output or build failures.
127+
*
128+
* @experimental Direct usage of this function is considered experimental.
129+
*
130+
* @param options The options defined by the builder's schema to use.
131+
* @param context An Architect builder context instance.
132+
* @param extensions An object contain extension points for the build.
133+
* @returns The build output results of the build.
134+
*/
135+
export function buildApplication(
136+
options: ApplicationBuilderOptions,
137+
context: BuilderContext,
138+
extensions?: ApplicationBuilderExtensions,
139+
): AsyncIterable<ApplicationBuilderOutput>;
140+
141+
export function buildApplication(
142+
options: ApplicationBuilderOptions,
143+
context: BuilderContext,
144+
pluginsOrExtensions?: Plugin[] | ApplicationBuilderExtensions,
145+
): AsyncIterable<ApplicationBuilderOutput> {
146+
let extensions;
147+
if (pluginsOrExtensions && Array.isArray(pluginsOrExtensions)) {
148+
extensions = {
149+
codePlugins: pluginsOrExtensions,
150+
};
119151
}
120-
> {
121-
return buildApplicationInternal(options, context, undefined, plugins);
152+
153+
return buildApplicationInternal(options, context, undefined, extensions);
122154
}
123155

124156
export default createBuilder(buildApplication);

packages/angular_devkit/build_angular/src/builders/application/options.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from '../../tools/webpack/utils/helpers';
1919
import { normalizeAssetPatterns, normalizeOptimization, normalizeSourceMaps } from '../../utils';
2020
import { I18nOptions, createI18nOptions } from '../../utils/i18n-options';
21+
import { IndexHtmlTransform } from '../../utils/index-file/index-html-generator';
2122
import { normalizeCacheOptions } from '../../utils/normalize-cache';
2223
import { generateEntryPoints } from '../../utils/package-chunk-sort';
2324
import { findTailwindConfigurationFile } from '../../utils/tailwind';
@@ -26,6 +27,11 @@ import { Schema as ApplicationBuilderOptions, I18NTranslation, OutputHashing } f
2627

2728
export type NormalizedApplicationBuildOptions = Awaited<ReturnType<typeof normalizeOptions>>;
2829

30+
export interface ApplicationBuilderExtensions {
31+
codePlugins?: Plugin[];
32+
indexHtmlTransformer?: IndexHtmlTransform;
33+
}
34+
2935
/** Internal options hidden from builder schema but available when invoked programmatically. */
3036
interface InternalOptions {
3137
/**
@@ -82,7 +88,7 @@ export async function normalizeOptions(
8288
context: BuilderContext,
8389
projectName: string,
8490
options: ApplicationBuilderInternalOptions,
85-
plugins?: Plugin[],
91+
extensions?: ApplicationBuilderExtensions,
8692
) {
8793
// If not explicitly set, default to the Node.js process argument
8894
const preserveSymlinks =
@@ -217,6 +223,7 @@ export async function normalizeOptions(
217223
scripts: options.scripts ?? [],
218224
styles: options.styles ?? [],
219225
}),
226+
transformer: extensions?.indexHtmlTransformer,
220227
};
221228
}
222229

@@ -329,7 +336,7 @@ export async function normalizeOptions(
329336
namedChunks,
330337
budgets: budgets?.length ? budgets : undefined,
331338
publicPath: deployUrl ? deployUrl : undefined,
332-
plugins: plugins?.length ? plugins : undefined,
339+
plugins: extensions?.codePlugins?.length ? extensions?.codePlugins : undefined,
333340
loaderExtensions,
334341
};
335342
}

packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export async function* buildEsbuildBrowser(
5656
{
5757
write: false,
5858
},
59-
plugins,
59+
plugins && { codePlugins: plugins },
6060
)) {
6161
if (infrastructureSettings?.write !== false && result.outputFiles) {
6262
// Write output files

packages/angular_devkit/build_angular/src/tools/esbuild/index-html-generator.ts

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export async function generateIndexHtml(
8282
},
8383
crossOrigin: crossOrigin,
8484
deployUrl: buildOptions.publicPath,
85+
postTransform: indexHtmlOptions.transformer,
8586
});
8687

8788
indexHtmlGenerator.readAsset = readAsset;
@@ -110,6 +111,7 @@ export async function generateIndexHtml(
110111

111112
const inlineCriticalCssProcessor = new InlineCriticalCssProcessor({
112113
minify: false, // CSS has already been minified during the build.
114+
deployUrl: buildOptions.publicPath,
113115
readAsset,
114116
});
115117

0 commit comments

Comments
 (0)