From 09ce57b77f77adf89d89149e77b121bbde19de06 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Mon, 23 Feb 2026 19:26:07 +0000 Subject: [PATCH 1/2] [C3/wrangler] Fix Angular localhost SSR blocking in development mode Recent Angular versions block SSR on localhost by default. Instead of modifying angular.json, this passes allowedHosts: ["localhost"] to the AngularAppEngine constructor conditionally based on process.env.NODE_ENV, which wrangler statically replaces with "development" during wrangler dev and "production" during wrangler deploy. This ensures localhost is only allowed during local development and is dead-code eliminated in production. Also unquarantines the Angular C3 e2e tests. --- .changeset/fix-angular-localhost-ssr.md | 10 ++++++++++ .../e2e/tests/frameworks/test-config.ts | 9 --------- .../templates/angular/pages/templates/src/server.ts | 8 +++++++- .../templates/angular/workers/templates/src/server.ts | 8 +++++++- packages/wrangler/src/autoconfig/frameworks/angular.ts | 8 +++++++- 5 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 .changeset/fix-angular-localhost-ssr.md diff --git a/.changeset/fix-angular-localhost-ssr.md b/.changeset/fix-angular-localhost-ssr.md new file mode 100644 index 0000000000..9d191b5365 --- /dev/null +++ b/.changeset/fix-angular-localhost-ssr.md @@ -0,0 +1,10 @@ +--- +"create-cloudflare": patch +"wrangler": patch +--- + +Fix Angular scaffolding to allow localhost SSR in development mode + +Recent versions of Angular's `AngularAppEngine` block serving SSR on `localhost` by default. This caused `wrangler dev` / `wrangler pages dev` to fail with `URL with hostname "localhost" is not allowed.` + +The fix passes `allowedHosts: ["localhost"]` to the `AngularAppEngine` constructor in `server.ts`, conditionally based on `process.env.NODE_ENV`. Wrangler statically replaces `process.env.NODE_ENV` with `"development"` during `wrangler dev` and `"production"` during `wrangler deploy`, so the localhost allowlist is only active during local development and is dead-code eliminated from production builds. diff --git a/packages/create-cloudflare/e2e/tests/frameworks/test-config.ts b/packages/create-cloudflare/e2e/tests/frameworks/test-config.ts index 7dd3c7d980..62c9144213 100644 --- a/packages/create-cloudflare/e2e/tests/frameworks/test-config.ts +++ b/packages/create-cloudflare/e2e/tests/frameworks/test-config.ts @@ -167,9 +167,6 @@ function getFrameworkTestConfig(pm: string): NamedFrameworkTestConfig[] { }, nodeCompat: false, flags: ["--style", "sass"], - // TODO: currently the Angular tests are failing with `URL with hostname "localhost" is not allowed.` - // we need to investigate this so that we can un-quarantine the Angular tests - quarantine: true, }, { name: "angular:workers", @@ -189,9 +186,6 @@ function getFrameworkTestConfig(pm: string): NamedFrameworkTestConfig[] { }, nodeCompat: false, flags: ["--style", "sass"], - // TODO: currently the Angular tests are failing with `URL with hostname "localhost" is not allowed.` - // we need to investigate this so that we can un-quarantine the Angular tests - quarantine: true, }, { name: "gatsby:pages", @@ -790,9 +784,6 @@ function getExperimentalFrameworkTestConfig( nodeCompat: false, flags: ["--style", "sass"], verifyTypes: false, - // TODO: currently the Angular tests are failing with `URL with hostname "localhost" is not allowed.` - // we need to investigate this so that we can un-quarantine the Angular tests - quarantine: true, }, { name: "nuxt:workers", diff --git a/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts b/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts index f75db0a749..c59bdeb7c9 100644 --- a/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts +++ b/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts @@ -1,6 +1,12 @@ import { AngularAppEngine, createRequestHandler } from '@angular/ssr'; -const angularApp = new AngularAppEngine(); +// When running in wrangler dev, allow localhost SSR. +// `process.env.NODE_ENV` is statically replaced at build time by wrangler: +// - `wrangler dev` sets it to "development" +// - `wrangler deploy` sets it to "production" +const angularApp = new AngularAppEngine({ + allowedHosts: process.env['NODE_ENV'] === 'development' ? ['localhost'] : [], +}); /** * This is a request handler used by the Angular CLI (dev-server and during build). diff --git a/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts b/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts index f75db0a749..c59bdeb7c9 100644 --- a/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts +++ b/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts @@ -1,6 +1,12 @@ import { AngularAppEngine, createRequestHandler } from '@angular/ssr'; -const angularApp = new AngularAppEngine(); +// When running in wrangler dev, allow localhost SSR. +// `process.env.NODE_ENV` is statically replaced at build time by wrangler: +// - `wrangler dev` sets it to "development" +// - `wrangler deploy` sets it to "production" +const angularApp = new AngularAppEngine({ + allowedHosts: process.env['NODE_ENV'] === 'development' ? ['localhost'] : [], +}); /** * This is a request handler used by the Angular CLI (dev-server and during build). diff --git a/packages/wrangler/src/autoconfig/frameworks/angular.ts b/packages/wrangler/src/autoconfig/frameworks/angular.ts index f9b2af11ab..7598d5fbd8 100644 --- a/packages/wrangler/src/autoconfig/frameworks/angular.ts +++ b/packages/wrangler/src/autoconfig/frameworks/angular.ts @@ -60,7 +60,13 @@ async function overrideServerFile() { dedent` import { AngularAppEngine, createRequestHandler } from '@angular/ssr'; - const angularApp = new AngularAppEngine(); + // When running in wrangler dev, allow localhost SSR. + // \`process.env.NODE_ENV\` is statically replaced at build time by wrangler: + // - \`wrangler dev\` sets it to "development" + // - \`wrangler deploy\` sets it to "production" + const angularApp = new AngularAppEngine({ + allowedHosts: process.env['NODE_ENV'] === 'development' ? ['localhost'] : [], + }); /** * This is a request handler used by the Angular CLI (dev-server and during build). From 56920b5025c92b86dc6e8702be136e0cd1a35e24 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Tue, 24 Feb 2026 06:54:53 +0000 Subject: [PATCH 2/2] just use allowedHosts The ng build was stripping the NODE_ENV condition before even getting to Wrangler. --- .changeset/fix-angular-localhost-ssr.md | 2 +- .../templates/angular/pages/templates/src/server.ts | 8 +++----- .../templates/angular/workers/templates/src/server.ts | 8 +++----- packages/wrangler/src/autoconfig/frameworks/angular.ts | 8 +++----- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.changeset/fix-angular-localhost-ssr.md b/.changeset/fix-angular-localhost-ssr.md index 9d191b5365..d46a2d4deb 100644 --- a/.changeset/fix-angular-localhost-ssr.md +++ b/.changeset/fix-angular-localhost-ssr.md @@ -7,4 +7,4 @@ Fix Angular scaffolding to allow localhost SSR in development mode Recent versions of Angular's `AngularAppEngine` block serving SSR on `localhost` by default. This caused `wrangler dev` / `wrangler pages dev` to fail with `URL with hostname "localhost" is not allowed.` -The fix passes `allowedHosts: ["localhost"]` to the `AngularAppEngine` constructor in `server.ts`, conditionally based on `process.env.NODE_ENV`. Wrangler statically replaces `process.env.NODE_ENV` with `"development"` during `wrangler dev` and `"production"` during `wrangler deploy`, so the localhost allowlist is only active during local development and is dead-code eliminated from production builds. +The fix passes `allowedHosts: ["localhost"]` to the `AngularAppEngine` constructor in `server.ts`, which is safe to do even in production since Cloudflare will already restrict which host is allowed. diff --git a/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts b/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts index c59bdeb7c9..a13fcf7814 100644 --- a/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts +++ b/packages/create-cloudflare/templates/angular/pages/templates/src/server.ts @@ -1,11 +1,9 @@ import { AngularAppEngine, createRequestHandler } from '@angular/ssr'; -// When running in wrangler dev, allow localhost SSR. -// `process.env.NODE_ENV` is statically replaced at build time by wrangler: -// - `wrangler dev` sets it to "development" -// - `wrangler deploy` sets it to "production" const angularApp = new AngularAppEngine({ - allowedHosts: process.env['NODE_ENV'] === 'development' ? ['localhost'] : [], + // It is safe to set allow `localhost`, so that SSR can run in local development, + // as, in production, Cloudflare will ensure that `localhost` is not the host. + allowedHosts: ['localhost'], }); /** diff --git a/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts b/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts index c59bdeb7c9..a13fcf7814 100644 --- a/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts +++ b/packages/create-cloudflare/templates/angular/workers/templates/src/server.ts @@ -1,11 +1,9 @@ import { AngularAppEngine, createRequestHandler } from '@angular/ssr'; -// When running in wrangler dev, allow localhost SSR. -// `process.env.NODE_ENV` is statically replaced at build time by wrangler: -// - `wrangler dev` sets it to "development" -// - `wrangler deploy` sets it to "production" const angularApp = new AngularAppEngine({ - allowedHosts: process.env['NODE_ENV'] === 'development' ? ['localhost'] : [], + // It is safe to set allow `localhost`, so that SSR can run in local development, + // as, in production, Cloudflare will ensure that `localhost` is not the host. + allowedHosts: ['localhost'], }); /** diff --git a/packages/wrangler/src/autoconfig/frameworks/angular.ts b/packages/wrangler/src/autoconfig/frameworks/angular.ts index 7598d5fbd8..193ae77d33 100644 --- a/packages/wrangler/src/autoconfig/frameworks/angular.ts +++ b/packages/wrangler/src/autoconfig/frameworks/angular.ts @@ -60,12 +60,10 @@ async function overrideServerFile() { dedent` import { AngularAppEngine, createRequestHandler } from '@angular/ssr'; - // When running in wrangler dev, allow localhost SSR. - // \`process.env.NODE_ENV\` is statically replaced at build time by wrangler: - // - \`wrangler dev\` sets it to "development" - // - \`wrangler deploy\` sets it to "production" const angularApp = new AngularAppEngine({ - allowedHosts: process.env['NODE_ENV'] === 'development' ? ['localhost'] : [], + // It is safe to set allow \`localhost\`, so that SSR can run in local development, + // as, in production, Cloudflare will ensure that \`localhost\` is not the host. + allowedHosts: ['localhost'], }); /**