Skip to content

Commit 18a11f5

Browse files
clydindgp1130
authored andcommitted
refactor(@angular-devkit/build-angular): add experimental builder selector 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`).
1 parent 6e2bc80 commit 18a11f5

File tree

2 files changed

+54
-21
lines changed
  • goldens/public-api/angular_devkit/build_angular
  • packages/angular_devkit/build_angular/src/builders/dev-server

2 files changed

+54
-21
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ export function executeDevServerBuilder(options: DevServerBuilderOptions, contex
212212
}, extensions?: {
213213
buildPlugins?: Plugin_2[];
214214
middleware?: ((req: http.IncomingMessage, res: http.ServerResponse, next: (err?: unknown) => void) => void)[];
215+
builderSelector?: (info: BuilderSelectorInfo, logger: BuilderContext['logger']) => string;
215216
}): Observable<DevServerBuilderOutput>;
216217

217218
// @public

packages/angular_devkit/build_angular/src/builders/dev-server/builder.ts

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export function execute(
4848
res: http.ServerResponse,
4949
next: (err?: unknown) => void,
5050
) => void)[];
51+
builderSelector?: (info: BuilderSelectorInfo, logger: BuilderContext['logger']) => string;
5152
},
5253
): Observable<DevServerBuilderOutput> {
5354
// Determine project name from builder context target
@@ -58,28 +59,16 @@ export function execute(
5859
return EMPTY;
5960
}
6061

61-
return defer(() => initialize(options, projectName, context)).pipe(
62+
return defer(() => initialize(options, projectName, context, extensions?.builderSelector)).pipe(
6263
switchMap(({ builderName, normalizedOptions }) => {
6364
// Use vite-based development server for esbuild-based builds
64-
if (
65-
builderName === '@angular-devkit/build-angular:application' ||
66-
builderName === '@angular-devkit/build-angular:browser-esbuild' ||
67-
normalizedOptions.forceEsbuild
68-
) {
65+
if (isEsbuildBased(builderName)) {
6966
if (transforms?.logging || transforms?.webpackConfiguration) {
7067
throw new Error(
7168
'The `application` and `browser-esbuild` builders do not support Webpack transforms.',
7269
);
7370
}
7471

75-
if (
76-
normalizedOptions.forceEsbuild &&
77-
builderName === '@angular-devkit/build-angular:browser'
78-
) {
79-
// The compatibility builder should be used if esbuild is force enabled with the official Webpack-based builder.
80-
builderName = '@angular-devkit/build-angular:browser-esbuild';
81-
}
82-
8372
return defer(() => import('./vite-server')).pipe(
8473
switchMap(({ serveWithVite }) =>
8574
serveWithVite(normalizedOptions, builderName, context, transforms, extensions),
@@ -110,6 +99,7 @@ async function initialize(
11099
initialOptions: DevServerBuilderOptions,
111100
projectName: string,
112101
context: BuilderContext,
102+
builderSelector = defaultBuilderSelector,
113103
) {
114104
// Purge old build disk cache.
115105
await purgeStaleBuildCache(context);
@@ -140,14 +130,56 @@ case.
140130
);
141131
}
142132

143-
if (normalizedOptions.forceEsbuild && !builderName.startsWith('@angular-devkit/build-angular:')) {
144-
context.logger.warn(
145-
'Warning: Forcing the use of the esbuild-based build system with third-party builders' +
146-
' may cause unexpected behavior and/or build failures.',
147-
);
133+
normalizedOptions.port = await checkPort(normalizedOptions.port, normalizedOptions.host);
134+
135+
return {
136+
builderName: builderSelector(
137+
{ builderName, forceEsbuild: !!normalizedOptions.forceEsbuild },
138+
context.logger,
139+
),
140+
normalizedOptions,
141+
};
142+
}
143+
144+
function isEsbuildBased(
145+
builderName: string,
146+
): builderName is
147+
| '@angular-devkit/build-angular:application'
148+
| '@angular-devkit/build-angular:browser-esbuild' {
149+
if (
150+
builderName === '@angular-devkit/build-angular:application' ||
151+
builderName === '@angular-devkit/build-angular:browser-esbuild'
152+
) {
153+
return true;
148154
}
149155

150-
normalizedOptions.port = await checkPort(normalizedOptions.port, normalizedOptions.host);
156+
return false;
157+
}
158+
159+
interface BuilderSelectorInfo {
160+
builderName: string;
161+
forceEsbuild: boolean;
162+
}
163+
164+
function defaultBuilderSelector(
165+
info: BuilderSelectorInfo,
166+
logger: BuilderContext['logger'],
167+
): string {
168+
if (isEsbuildBased(info.builderName)) {
169+
return info.builderName;
170+
}
171+
172+
if (info.forceEsbuild) {
173+
if (!info.builderName.startsWith('@angular-devkit/build-angular:')) {
174+
logger.warn(
175+
'Warning: Forcing the use of the esbuild-based build system with third-party builders' +
176+
' may cause unexpected behavior and/or build failures.',
177+
);
178+
}
179+
180+
// The compatibility builder should be used if esbuild is force enabled.
181+
return '@angular-devkit/build-angular:browser-esbuild';
182+
}
151183

152-
return { builderName, normalizedOptions };
184+
return info.builderName;
153185
}

0 commit comments

Comments
 (0)