Skip to content

Commit

Permalink
refactor(@angular-devkit/build-angular): add experimental builder sel…
Browse files Browse the repository at this point in the history
…ector extension for dev-server

When using the experimental programmatic API for the development server, the choice of builder used
to execute the actual underlying build can now be chosen via a selector function extension option.
The returned string value must be one of the first-party esbuild-based builders for the Vite-based
development server to be used. All other returned values will cause the Webpack-based development
server to be used. The Vite-based development server currently requires one of those builders to
be used (either `@angular-devkit/build-angular:application` or `@angular-devkit/build-angular:browser-esbuild`).

(cherry picked from commit 18a11f5)
  • Loading branch information
clydin authored and dgp1130 committed Jan 9, 2024
1 parent ca0a836 commit b853d0e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 21 deletions.
1 change: 1 addition & 0 deletions goldens/public-api/angular_devkit/build_angular/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export function executeDevServerBuilder(options: DevServerBuilderOptions, contex
}, extensions?: {
buildPlugins?: Plugin_2[];
middleware?: ((req: http.IncomingMessage, res: http.ServerResponse, next: (err?: unknown) => void) => void)[];
builderSelector?: (info: BuilderSelectorInfo, logger: BuilderContext['logger']) => string;
}): Observable<DevServerBuilderOutput>;

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function execute(
res: http.ServerResponse,
next: (err?: unknown) => void,
) => void)[];
builderSelector?: (info: BuilderSelectorInfo, logger: BuilderContext['logger']) => string;
},
): Observable<DevServerBuilderOutput> {
// Determine project name from builder context target
Expand All @@ -58,28 +59,16 @@ export function execute(
return EMPTY;
}

return defer(() => initialize(options, projectName, context)).pipe(
return defer(() => initialize(options, projectName, context, extensions?.builderSelector)).pipe(
switchMap(({ builderName, normalizedOptions }) => {
// Use vite-based development server for esbuild-based builds
if (
builderName === '@angular-devkit/build-angular:application' ||
builderName === '@angular-devkit/build-angular:browser-esbuild' ||
normalizedOptions.forceEsbuild
) {
if (isEsbuildBased(builderName)) {
if (transforms?.logging || transforms?.webpackConfiguration) {
throw new Error(
'The `application` and `browser-esbuild` builders do not support Webpack transforms.',
);
}

if (
normalizedOptions.forceEsbuild &&
builderName === '@angular-devkit/build-angular:browser'
) {
// The compatibility builder should be used if esbuild is force enabled with the official Webpack-based builder.
builderName = '@angular-devkit/build-angular:browser-esbuild';
}

return defer(() => import('./vite-server')).pipe(
switchMap(({ serveWithVite }) =>
serveWithVite(normalizedOptions, builderName, context, transforms, extensions),
Expand Down Expand Up @@ -110,6 +99,7 @@ async function initialize(
initialOptions: DevServerBuilderOptions,
projectName: string,
context: BuilderContext,
builderSelector = defaultBuilderSelector,
) {
// Purge old build disk cache.
await purgeStaleBuildCache(context);
Expand Down Expand Up @@ -140,14 +130,56 @@ case.
);
}

if (normalizedOptions.forceEsbuild && !builderName.startsWith('@angular-devkit/build-angular:')) {
context.logger.warn(
'Warning: Forcing the use of the esbuild-based build system with third-party builders' +
' may cause unexpected behavior and/or build failures.',
);
normalizedOptions.port = await checkPort(normalizedOptions.port, normalizedOptions.host);

return {
builderName: builderSelector(
{ builderName, forceEsbuild: !!normalizedOptions.forceEsbuild },
context.logger,
),
normalizedOptions,
};
}

function isEsbuildBased(
builderName: string,
): builderName is
| '@angular-devkit/build-angular:application'
| '@angular-devkit/build-angular:browser-esbuild' {
if (
builderName === '@angular-devkit/build-angular:application' ||
builderName === '@angular-devkit/build-angular:browser-esbuild'
) {
return true;
}

normalizedOptions.port = await checkPort(normalizedOptions.port, normalizedOptions.host);
return false;
}

interface BuilderSelectorInfo {
builderName: string;
forceEsbuild: boolean;
}

function defaultBuilderSelector(
info: BuilderSelectorInfo,
logger: BuilderContext['logger'],
): string {
if (isEsbuildBased(info.builderName)) {
return info.builderName;
}

if (info.forceEsbuild) {
if (!info.builderName.startsWith('@angular-devkit/build-angular:')) {
logger.warn(
'Warning: Forcing the use of the esbuild-based build system with third-party builders' +
' may cause unexpected behavior and/or build failures.',
);
}

// The compatibility builder should be used if esbuild is force enabled.
return '@angular-devkit/build-angular:browser-esbuild';
}

return { builderName, normalizedOptions };
return info.builderName;
}

0 comments on commit b853d0e

Please sign in to comment.