diff --git a/packages/angular_devkit/build_angular/src/builders/dev-server/builder.ts b/packages/angular_devkit/build_angular/src/builders/dev-server/builder.ts index d11908d6c8a0..e3af10c6e791 100644 --- a/packages/angular_devkit/build_angular/src/builders/dev-server/builder.ts +++ b/packages/angular_devkit/build_angular/src/builders/dev-server/builder.ts @@ -72,6 +72,14 @@ export function execute( ); } + 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), diff --git a/packages/angular_devkit/build_angular/src/builders/dev-server/tests/options/force-esbuild_spec.ts b/packages/angular_devkit/build_angular/src/builders/dev-server/tests/options/force-esbuild_spec.ts new file mode 100644 index 000000000000..45849bc6a6a8 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/builders/dev-server/tests/options/force-esbuild_spec.ts @@ -0,0 +1,79 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import { executeDevServer } from '../../index'; +import { executeOnceAndFetch } from '../execute-fetch'; +import { describeServeBuilder } from '../jasmine-helpers'; +import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup'; + +const ESBUILD_LOG_TEXT = 'Application bundle generation complete.'; +const WEBPACK_LOG_TEXT = 'Compiled successfully.'; + +describeServeBuilder( + executeDevServer, + DEV_SERVER_BUILDER_INFO, + (harness, setupTarget, isViteRun) => { + describe('option: "forceEsbuild"', () => { + beforeEach(async () => { + setupTarget(harness, {}); + + // Application code is not needed for these tests + await harness.writeFile('src/main.ts', 'console.log("foo");'); + }); + + it('should use build target specified build system when not present', async () => { + harness.useTarget('serve', { + ...BASE_OPTIONS, + forceEsbuild: undefined, + }); + + const { result, response, logs } = await executeOnceAndFetch(harness, '/main.js'); + + expect(result?.success).toBeTrue(); + expect(await response?.text()).toContain('console.log'); + expect(logs).toContain( + jasmine.objectContaining({ + message: jasmine.stringMatching(isViteRun ? ESBUILD_LOG_TEXT : WEBPACK_LOG_TEXT), + }), + ); + }); + + it('should use build target specified build system when false', async () => { + harness.useTarget('serve', { + ...BASE_OPTIONS, + forceEsbuild: false, + }); + + const { result, response, logs } = await executeOnceAndFetch(harness, '/main.js'); + + expect(result?.success).toBeTrue(); + expect(await response?.text()).toContain('console.log'); + expect(logs).toContain( + jasmine.objectContaining({ + message: jasmine.stringMatching(isViteRun ? ESBUILD_LOG_TEXT : WEBPACK_LOG_TEXT), + }), + ); + }); + + it('should always use the esbuild build system with Vite when true', async () => { + harness.useTarget('serve', { + ...BASE_OPTIONS, + forceEsbuild: true, + }); + + const { result, response, logs } = await executeOnceAndFetch(harness, '/main.js'); + + expect(result?.success).toBeTrue(); + expect(await response?.text()).toContain('console.log'); + expect(logs).toContain( + jasmine.objectContaining({ message: jasmine.stringMatching(ESBUILD_LOG_TEXT) }), + ); + }); + }); + }, +);