Skip to content

Commit

Permalink
refactor(@angular-devkit/build-angular): add index HTML transformer t…
Browse files Browse the repository at this point in the history
…o 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 #26299
  • Loading branch information
clydin authored and alan-agius4 committed Dec 14, 2023
1 parent 68dfe3b commit 66edac4
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 25 deletions.
11 changes: 4 additions & 7 deletions goldens/public-api/angular_devkit/build_angular/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,10 @@ export interface Budget {
}

// @public
export function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, plugins?: Plugin_2[]): AsyncIterable<BuilderOutput & {
outputFiles?: BuildOutputFile[];
assetFiles?: {
source: string;
destination: string;
}[];
}>;
export function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, plugins?: Plugin_2[]): AsyncIterable<ApplicationBuilderOutput>;

// @public
export function buildApplication(options: ApplicationBuilderOptions, context: BuilderContext, extensions?: ApplicationBuilderExtensions): AsyncIterable<ApplicationBuilderOutput>;

// @public
export enum CrossOrigin {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import { purgeStaleBuildCache } from '../../utils/purge-cache';
import { assertCompatibleAngularVersion } from '../../utils/version';
import { runEsBuildBuildAction } from './build-action';
import { executeBuild } from './execute-build';
import { ApplicationBuilderInternalOptions, normalizeOptions } from './options';
import {
ApplicationBuilderExtensions,
ApplicationBuilderInternalOptions,
normalizeOptions,
} from './options';
import { Schema as ApplicationBuilderOptions } from './schema';

export { ApplicationBuilderOptions };
Expand All @@ -25,13 +29,8 @@ export async function* buildApplicationInternal(
infrastructureSettings?: {
write?: boolean;
},
plugins?: Plugin[],
): AsyncIterable<
BuilderOutput & {
outputFiles?: BuildOutputFile[];
assetFiles?: { source: string; destination: string }[];
}
> {
extensions?: ApplicationBuilderExtensions,
): AsyncIterable<ApplicationBuilderOutput> {
// Check Angular version.
assertCompatibleAngularVersion(context.workspaceRoot);

Expand All @@ -46,7 +45,7 @@ export async function* buildApplicationInternal(
return;
}

const normalizedOptions = await normalizeOptions(context, projectName, options, plugins);
const normalizedOptions = await normalizeOptions(context, projectName, options, extensions);

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

export interface ApplicationBuilderOutput extends BuilderOutput {
outputFiles?: BuildOutputFile[];
assetFiles?: { source: string; destination: string }[];
}

/**
* Builds an application using the `application` builder with the provided
* options.
Expand All @@ -112,13 +116,41 @@ export function buildApplication(
options: ApplicationBuilderOptions,
context: BuilderContext,
plugins?: Plugin[],
): AsyncIterable<
BuilderOutput & {
outputFiles?: BuildOutputFile[];
assetFiles?: { source: string; destination: string }[];
): AsyncIterable<ApplicationBuilderOutput>;

/**
* Builds an application using the `application` builder with the provided
* options.
*
* Usage of the `extensions` parameter is NOT supported and may cause unexpected
* build output or build failures.
*
* @experimental Direct usage of this function is considered experimental.
*
* @param options The options defined by the builder's schema to use.
* @param context An Architect builder context instance.
* @param extensions An object contain extension points for the build.
* @returns The build output results of the build.
*/
export function buildApplication(
options: ApplicationBuilderOptions,
context: BuilderContext,
extensions?: ApplicationBuilderExtensions,
): AsyncIterable<ApplicationBuilderOutput>;

export function buildApplication(
options: ApplicationBuilderOptions,
context: BuilderContext,
pluginsOrExtensions?: Plugin[] | ApplicationBuilderExtensions,
): AsyncIterable<ApplicationBuilderOutput> {
let extensions;
if (pluginsOrExtensions && Array.isArray(pluginsOrExtensions)) {
extensions = {
codePlugins: pluginsOrExtensions,
};
}
> {
return buildApplicationInternal(options, context, undefined, plugins);

return buildApplicationInternal(options, context, undefined, extensions);
}

export default createBuilder(buildApplication);
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '../../tools/webpack/utils/helpers';
import { normalizeAssetPatterns, normalizeOptimization, normalizeSourceMaps } from '../../utils';
import { I18nOptions, createI18nOptions } from '../../utils/i18n-options';
import { IndexHtmlTransform } from '../../utils/index-file/index-html-generator';
import { normalizeCacheOptions } from '../../utils/normalize-cache';
import { generateEntryPoints } from '../../utils/package-chunk-sort';
import { findTailwindConfigurationFile } from '../../utils/tailwind';
Expand All @@ -26,6 +27,11 @@ import { Schema as ApplicationBuilderOptions, I18NTranslation, OutputHashing } f

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

export interface ApplicationBuilderExtensions {
codePlugins?: Plugin[];
indexHtmlTransformer?: IndexHtmlTransform;
}

/** Internal options hidden from builder schema but available when invoked programmatically. */
interface InternalOptions {
/**
Expand Down Expand Up @@ -82,7 +88,7 @@ export async function normalizeOptions(
context: BuilderContext,
projectName: string,
options: ApplicationBuilderInternalOptions,
plugins?: Plugin[],
extensions?: ApplicationBuilderExtensions,
) {
// If not explicitly set, default to the Node.js process argument
const preserveSymlinks =
Expand Down Expand Up @@ -217,6 +223,7 @@ export async function normalizeOptions(
scripts: options.scripts ?? [],
styles: options.styles ?? [],
}),
transformer: extensions?.indexHtmlTransformer,
};
}

Expand Down Expand Up @@ -329,7 +336,7 @@ export async function normalizeOptions(
namedChunks,
budgets: budgets?.length ? budgets : undefined,
publicPath: deployUrl ? deployUrl : undefined,
plugins: plugins?.length ? plugins : undefined,
plugins: extensions?.codePlugins?.length ? extensions?.codePlugins : undefined,
loaderExtensions,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export async function* buildEsbuildBrowser(
{
write: false,
},
plugins,
plugins && { codePlugins: plugins },
)) {
if (infrastructureSettings?.write !== false && result.outputFiles) {
// Write output files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export async function generateIndexHtml(
},
crossOrigin: crossOrigin,
deployUrl: buildOptions.publicPath,
postTransform: indexHtmlOptions.transformer,
});

indexHtmlGenerator.readAsset = readAsset;
Expand Down Expand Up @@ -110,6 +111,7 @@ export async function generateIndexHtml(

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

Expand Down

0 comments on commit 66edac4

Please sign in to comment.