From fa1199a97eadff996475f095449fd1b93b1831ea Mon Sep 17 00:00:00 2001 From: lukekania Date: Wed, 10 Jun 2026 09:16:44 +0200 Subject: [PATCH 1/2] feat(builder): accept and forward the dev-server `hmr` option (#145) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rust side of HMR landed in PRs #185-#187, but the Architect builder still rejected `hmr` at schema validation (additionalProperties: false) and never forwarded a flag, so `ng serve` users could not reach it. - schemas/dev-server.json: declare `hmr` (boolean, no default) - serve/options.ts: tri-state forwarding — true → --hmr, false → --no-hmr, unset → nothing (binary inherits architect.serve.options.hmr from angular.json) --- packages/builder/schemas/dev-server.json | 4 ++++ .../src/serve/__tests__/options.test.ts | 18 ++++++++++++++++++ packages/builder/src/serve/options.ts | 9 +++++++++ 3 files changed, 31 insertions(+) diff --git a/packages/builder/schemas/dev-server.json b/packages/builder/schemas/dev-server.json index 3396d2f..62c1075 100644 --- a/packages/builder/schemas/dev-server.json +++ b/packages/builder/schemas/dev-server.json @@ -73,6 +73,10 @@ "type": "object", "additionalProperties": { "type": "string" }, "description": "Custom HTTP response headers emitted on every served response (static assets, the SPA-fallback index.html, and the SSE live-reload stream). Use this to serve production-like security headers (CSP, Cross-Origin-Opener-Policy), CORS headers, or cache-control overrides in dev. Headers the dev server sets itself (Content-Type, Cache-Control) are not overridden. Headers are not added to proxy-forwarded responses, which keep their upstream headers." + }, + "hmr": { + "type": "boolean", + "description": "Enable Hot Module Replacement: edits to component templates and styles (and global stylesheets) are applied in place without a full page reload, preserving component and form state. TypeScript edits still trigger a full reload. When unset, the spawned binary falls back to `architect.serve.options.hmr` in angular.json (default false, matching today's full-reload behavior)." } }, "additionalProperties": false diff --git a/packages/builder/src/serve/__tests__/options.test.ts b/packages/builder/src/serve/__tests__/options.test.ts index e228107..d583876 100644 --- a/packages/builder/src/serve/__tests__/options.test.ts +++ b/packages/builder/src/serve/__tests__/options.test.ts @@ -226,6 +226,24 @@ describe('translateOptions', () => { ).not.toContain('--headers'); expect(translateOptions(base, '/ws').args).not.toContain('--headers'); }); + + it('forwards hmr: true as --hmr', () => { + const t = translateOptions({ ...base, hmr: true }, '/ws'); + expect(t.args).toContain('--hmr'); + expect(t.args).not.toContain('--no-hmr'); + }); + + it('forwards hmr: false as --no-hmr', () => { + const t = translateOptions({ ...base, hmr: false }, '/ws'); + expect(t.args).toContain('--no-hmr'); + expect(t.args).not.toContain('--hmr'); + }); + + it('omits both hmr flags when hmr is unset so the binary inherits angular.json', () => { + const args = translateOptions(base, '/ws').args; + expect(args).not.toContain('--hmr'); + expect(args).not.toContain('--no-hmr'); + }); }); describe('formatUrl', () => { diff --git a/packages/builder/src/serve/options.ts b/packages/builder/src/serve/options.ts index c22e9b5..6ce4433 100644 --- a/packages/builder/src/serve/options.ts +++ b/packages/builder/src/serve/options.ts @@ -17,6 +17,7 @@ export interface DevServerOptions extends json.JsonObject { servePath: string | null; allowedHosts: string[] | null; headers: { [key: string]: string } | null; + hmr: boolean | null; } export interface TranslatedServeArgs { @@ -95,6 +96,14 @@ export function translateOptions( if (headers !== null) { args.push('--headers', headers); } + // `hmr` is tri-state: an explicit true/false becomes `--hmr`/`--no-hmr` + // (the CLI override flags), while unset forwards nothing so the binary + // falls back to `architect.serve.options.hmr` in angular.json. + if (raw.hmr === true) { + args.push('--hmr'); + } else if (raw.hmr === false) { + args.push('--no-hmr'); + } args.push(...sslArgs); return { From 5059196e74a17099630ab8872ab6c58c4384fdaa Mon Sep 17 00:00:00 2001 From: lukekania Date: Wed, 10 Jun 2026 09:21:42 +0200 Subject: [PATCH 2/2] chore: bump version to 0.10.18 (#145 builder hmr option) --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07ccdae..1869cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -874,7 +874,7 @@ dependencies = [ [[package]] name = "ngc-bundler" -version = "0.10.17" +version = "0.10.18" dependencies = [ "dashmap", "ngc-diagnostics", @@ -899,7 +899,7 @@ dependencies = [ [[package]] name = "ngc-dev-server" -version = "0.10.17" +version = "0.10.18" dependencies = [ "ngc-diagnostics", "rcgen", @@ -912,7 +912,7 @@ dependencies = [ [[package]] name = "ngc-diagnostics" -version = "0.10.17" +version = "0.10.18" dependencies = [ "serde_json", "thiserror", @@ -920,7 +920,7 @@ dependencies = [ [[package]] name = "ngc-linker" -version = "0.10.17" +version = "0.10.18" dependencies = [ "dashmap", "insta", @@ -938,7 +938,7 @@ dependencies = [ [[package]] name = "ngc-npm-resolver" -version = "0.10.17" +version = "0.10.18" dependencies = [ "dashmap", "ngc-diagnostics", @@ -953,7 +953,7 @@ dependencies = [ [[package]] name = "ngc-project-resolver" -version = "0.10.17" +version = "0.10.18" dependencies = [ "dashmap", "glob", @@ -969,7 +969,7 @@ dependencies = [ [[package]] name = "ngc-rs" -version = "0.10.17" +version = "0.10.18" dependencies = [ "base64 0.22.1", "clap", @@ -1003,7 +1003,7 @@ dependencies = [ [[package]] name = "ngc-template-compiler" -version = "0.10.17" +version = "0.10.18" dependencies = [ "insta", "ngc-diagnostics", @@ -1025,7 +1025,7 @@ dependencies = [ [[package]] name = "ngc-ts-transform" -version = "0.10.17" +version = "0.10.18" dependencies = [ "ngc-diagnostics", "oxc_allocator", @@ -1044,7 +1044,7 @@ dependencies = [ [[package]] name = "ngc-watch" -version = "0.10.17" +version = "0.10.18" dependencies = [ "ngc-diagnostics", "notify", diff --git a/Cargo.toml b/Cargo.toml index 6a8f4c5..6bf3f94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["crates/cli", "crates/diagnostics", "crates/project-resolver", "crates/ts-transform", "crates/bundler", "crates/template-compiler", "crates/npm-resolver", "crates/linker", "crates/watch", "crates/dev-server"] [workspace.package] -version = "0.10.17" +version = "0.10.18" edition = "2021" license = "MIT OR Apache-2.0" authors = ["lukekania"]