diff --git a/goldens/public-api/angular/build/index.md b/goldens/public-api/angular/build/index.md index cad7c7b3fbf1..c34649199d9e 100644 --- a/goldens/public-api/angular/build/index.md +++ b/goldens/public-api/angular/build/index.md @@ -110,12 +110,7 @@ export enum BuildOutputFileType { // @public export interface DevServerBuilderOptions { - allowedHosts?: string[]; - // @deprecated - browserTarget?: string; - buildTarget?: string; - disableHostCheck?: boolean; - forceEsbuild?: boolean; + buildTarget: string; headers?: { [key: string]: string; }; @@ -127,7 +122,6 @@ export interface DevServerBuilderOptions { port?: number; prebundle?: PrebundleUnion; proxyConfig?: string; - publicHost?: string; servePath?: string; ssl?: boolean; sslCert?: string; diff --git a/packages/angular/build/src/builders/dev-server/builder.ts b/packages/angular/build/src/builders/dev-server/builder.ts index 353e67b6a4ce..1840e59e4f0d 100644 --- a/packages/angular/build/src/builders/dev-server/builder.ts +++ b/packages/angular/build/src/builders/dev-server/builder.ts @@ -86,8 +86,8 @@ async function initialize( const builderName = await context.getBuilderNameForTarget(normalizedOptions.buildTarget); if ( - !normalizedOptions.disableHostCheck && !/^127\.\d+\.\d+\.\d+/g.test(normalizedOptions.host) && + normalizedOptions.host !== '::1' && normalizedOptions.host !== 'localhost' ) { context.logger.warn(` @@ -96,18 +96,10 @@ locally. It hasn't been reviewed for security issues. Binding this server to an open connection can result in compromising your application or computer. Using a different host than the one passed to the "--host" flag might result in -websocket connection issues. You might need to use "--disable-host-check" if that's the -case. +websocket connection issues. `); } - if (normalizedOptions.disableHostCheck) { - context.logger.warn( - 'Warning: Running a server with --disable-host-check is a security risk. ' + - 'See https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a for more information.', - ); - } - normalizedOptions.port = await checkPort(normalizedOptions.port, normalizedOptions.host); return { diff --git a/packages/angular/build/src/builders/dev-server/options.ts b/packages/angular/build/src/builders/dev-server/options.ts index fd3b384e1fc0..d08b783472b5 100644 --- a/packages/angular/build/src/builders/dev-server/options.ts +++ b/packages/angular/build/src/builders/dev-server/options.ts @@ -35,7 +35,7 @@ export async function normalizeOptions( const cacheOptions = normalizeCacheOptions(projectMetadata, workspaceRoot); // Target specifier defaults to the current project's build target using a development configuration - const buildTargetSpecifier = options.buildTarget ?? options.browserTarget ?? `::development`; + const buildTargetSpecifier = options.buildTarget ?? `::development`; const buildTarget = targetFromTargetString(buildTargetSpecifier, projectName, 'build'); // Initial options to keep @@ -46,18 +46,14 @@ export async function normalizeOptions( open, verbose, watch, - allowedHosts, - disableHostCheck, liveReload, hmr, headers, proxyConfig, servePath, - publicHost, ssl, sslCert, sslKey, - forceEsbuild, prebundle, } = options; @@ -76,15 +72,11 @@ export async function normalizeOptions( workspaceRoot, projectRoot, cacheOptions, - allowedHosts, - disableHostCheck, proxyConfig, servePath, - publicHost, ssl, sslCert, sslKey, - forceEsbuild, // Prebundling defaults to true but requires caching to function prebundle: cacheOptions.enabled && (prebundle ?? true), }; diff --git a/packages/angular/build/src/builders/dev-server/schema.json b/packages/angular/build/src/builders/dev-server/schema.json index f10deb2339a8..95ff1bbca18b 100644 --- a/packages/angular/build/src/builders/dev-server/schema.json +++ b/packages/angular/build/src/builders/dev-server/schema.json @@ -4,12 +4,6 @@ "description": "Dev Server target options for Build Facade.", "type": "object", "properties": { - "browserTarget": { - "type": "string", - "description": "A browser builder target to serve in the format of `project:target[:configuration]`. You can also pass in more than one configuration name as a comma-separated list. Example: `project:target:production,staging`.", - "pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$", - "x-deprecated": "Use 'buildTarget' instead." - }, "buildTarget": { "type": "string", "description": "A build builder target to serve in the format of `project:target[:configuration]`. You can also pass in more than one configuration name as a comma-separated list. Example: `project:target:production,staging`.", @@ -67,27 +61,10 @@ "description": "Whether to reload the page on change, using live-reload.", "default": true }, - "publicHost": { - "type": "string", - "description": "The URL that the browser client (or live-reload client, if enabled) should use to connect to the development server. Use for a complex dev server setup, such as one with reverse proxies. This option has no effect when using the 'application' or other esbuild-based builders." - }, - "allowedHosts": { - "type": "array", - "description": "List of hosts that are allowed to access the dev server. This option has no effect when using the 'application' or other esbuild-based builders.", - "default": [], - "items": { - "type": "string" - } - }, "servePath": { "type": "string", "description": "The pathname where the application will be served." }, - "disableHostCheck": { - "type": "boolean", - "description": "Don't verify connected clients are part of allowed hosts. This option has no effect when using the 'application' or other esbuild-based builders.", - "default": false - }, "hmr": { "type": "boolean", "description": "Enable hot module replacement.", @@ -102,13 +79,8 @@ "type": "number", "description": "Enable and define the file watching poll time period in milliseconds." }, - "forceEsbuild": { - "type": "boolean", - "description": "Force the development server to use the 'browser-esbuild' builder when building. This is a developer preview option for the esbuild-based build system.", - "default": false - }, "prebundle": { - "description": "Enable and control the Vite-based development server's prebundling capabilities. To enable prebundling, the Angular CLI cache must also be enabled. This option has no effect when using the 'browser' or other Webpack-based builders.", + "description": "Enable and control the Vite-based development server's prebundling capabilities. To enable prebundling, the Angular CLI cache must also be enabled.", "oneOf": [ { "type": "boolean" }, { @@ -127,5 +99,5 @@ } }, "additionalProperties": false, - "anyOf": [{ "required": ["buildTarget"] }, { "required": ["browserTarget"] }] + "required": ["buildTarget"] } diff --git a/packages/angular/build/src/builders/dev-server/tests/options/allowed-hosts_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/allowed-hosts_spec.ts deleted file mode 100644 index b28297fd6c3d..000000000000 --- a/packages/angular/build/src/builders/dev-server/tests/options/allowed-hosts_spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @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 FETCH_HEADERS = Object.freeze({ host: 'example.com' }); - -describeServeBuilder( - executeDevServer, - DEV_SERVER_BUILDER_INFO, - (harness, setupTarget, isViteRun) => { - // TODO(fix-vite): currently this is broken in vite. - (isViteRun ? xdescribe : xdescribe)('option: "allowedHosts"', () => { - beforeEach(async () => { - setupTarget(harness); - - // Application code is not needed for these tests - await harness.writeFile('src/main.ts', ''); - }); - - it('does not allow an invalid host when option is not present', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toBe('Invalid Host header'); - }); - - it('does not allow an invalid host when option is an empty array', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - allowedHosts: [], - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toBe('Invalid Host header'); - }); - - it('allows a host when specified in the option', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - allowedHosts: ['example.com'], - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toContain(''); - }); - }); - }, -); diff --git a/packages/angular/build/src/builders/dev-server/tests/options/disable-host-check_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/disable-host-check_spec.ts deleted file mode 100644 index 160f511d8026..000000000000 --- a/packages/angular/build/src/builders/dev-server/tests/options/disable-host-check_spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @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 FETCH_HEADERS = Object.freeze({ host: 'example.com' }); - -describeServeBuilder( - executeDevServer, - DEV_SERVER_BUILDER_INFO, - (harness, setupTarget, isViteRun) => { - // This option is not used when using vite. - (isViteRun ? xdescribe : xdescribe)('option: "disableHostCheck"', () => { - beforeEach(async () => { - setupTarget(harness); - - // Application code is not needed for these tests - await harness.writeFile('src/main.ts', ''); - }); - - it('does not allow an invalid host when option is not present', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toBe('Invalid Host header'); - }); - - it('does not allow an invalid host when option is false', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - disableHostCheck: false, - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toBe('Invalid Host header'); - }); - - it('allows a host when option is true', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - disableHostCheck: true, - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toContain('<title>'); - }); - }); - }, -); diff --git a/packages/angular/build/src/builders/dev-server/tests/options/force-esbuild_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/force-esbuild_spec.ts deleted file mode 100644 index 45849bc6a6a8..000000000000 --- a/packages/angular/build/src/builders/dev-server/tests/options/force-esbuild_spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @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) }), - ); - }); - }); - }, -); diff --git a/packages/angular/build/src/builders/dev-server/tests/options/public-host_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/public-host_spec.ts deleted file mode 100644 index bfc3c6a983c2..000000000000 --- a/packages/angular/build/src/builders/dev-server/tests/options/public-host_spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @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 FETCH_HEADERS = Object.freeze({ host: 'example.com' }); - -describeServeBuilder( - executeDevServer, - DEV_SERVER_BUILDER_INFO, - (harness, setupTarget, isViteRun) => { - // This option is not used when using vite. - (isViteRun ? xdescribe : xdescribe)('option: "publicHost"', () => { - beforeEach(async () => { - setupTarget(harness); - - // Application code is not needed for these tests - await harness.writeFile('src/main.ts', ''); - }); - - it('does not allow an invalid host when option is not present', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toBe('Invalid Host header'); - }); - - it('does not allow an invalid host when option is a different host', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - publicHost: 'example.net', - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toBe('Invalid Host header'); - }); - - it('allows a host when option is set to used host', async () => { - harness.useTarget('serve', { - ...BASE_OPTIONS, - publicHost: 'example.com', - }); - - const { result, response } = await executeOnceAndFetch(harness, '/', { - request: { headers: FETCH_HEADERS }, - }); - - expect(result?.success).toBeTrue(); - expect(await response?.text()).toContain('<title>'); - }); - }); - }, -);