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"] 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 {