Skip to content

Commit 298b554

Browse files
clydindgp1130
authored andcommittedDec 17, 2024·
feat(@angular/build): enable component template hot replacement by default
When using the `application` builder (default for new projects) with the development server, component template only changes will now automatically replace the template within the running application without a full reload of the page. No application code changes are necessary and both file-based (`templateUrl`) and inline (`template`) component templates are supported. Additionally, changing a components styles in combination with a template change is also supported for hot replacement. This includes both inline and file-based changes. If any issues are encountered or it is preferred to not hot replace component templates, the `NG_HMR_TEMPLATES=0` environment variable can be used to disable the feature. Setting the `liveReload` option or `hmr` option to false will also disable all updates.
1 parent 3b7e6a8 commit 298b554

File tree

7 files changed

+29
-21
lines changed

7 files changed

+29
-21
lines changed
 

‎packages/angular/build/src/builders/dev-server/vite-server.ts

+5-8
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,14 @@ export async function* serveWithVite(
138138
process.setSourceMapsEnabled(true);
139139
}
140140

141-
// Enable to support component style hot reloading (`NG_HMR_CSTYLES=0` can be used to disable selectively)
141+
// Enable to support link-based component style hot reloading (`NG_HMR_CSTYLES=0` can be used to disable selectively)
142142
browserOptions.externalRuntimeStyles =
143143
serverOptions.liveReload && serverOptions.hmr && useComponentStyleHmr;
144144

145-
// Enable to support component template hot replacement (`NG_HMR_TEMPLATE=1` can be used to enable)
146-
browserOptions.templateUpdates = !!serverOptions.liveReload && useComponentTemplateHmr;
147-
if (browserOptions.templateUpdates) {
148-
context.logger.warn(
149-
'Experimental support for component template hot replacement has been enabled via the "NG_HMR_TEMPLATE" environment variable.',
150-
);
151-
}
145+
// Enable to support component template hot replacement (`NG_HMR_TEMPLATE=0` can be used to disable selectively)
146+
// This will also replace file-based/inline styles as code if external runtime styles are not enabled.
147+
browserOptions.templateUpdates =
148+
serverOptions.liveReload && serverOptions.hmr && useComponentTemplateHmr;
152149

153150
// Setup the prebundling transformer that will be shared across Vite prebundling requests
154151
const prebundleTransformer = new JavaScriptTransformer(

‎packages/angular/build/src/utils/environment-options.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export const useComponentStyleHmr =
107107

108108
const hmrComponentTemplateVariable = process.env['NG_HMR_TEMPLATES'];
109109
export const useComponentTemplateHmr =
110-
isPresent(hmrComponentTemplateVariable) && isEnabled(hmrComponentTemplateVariable);
110+
!isPresent(hmrComponentTemplateVariable) || !isDisabled(hmrComponentTemplateVariable);
111111

112112
const partialSsrBuildVariable = process.env['NG_BUILD_PARTIAL_SSR'];
113113
export const usePartialSsrBuild =

‎tests/legacy-cli/e2e/tests/basic/rebuild.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,8 @@ export default async function () {
99
const validBundleRegEx = esbuild ? /sent to client/ : /Compiled successfully\./;
1010
const lazyBundleRegEx = esbuild ? /chunk-/ : /src_app_lazy_lazy_component_ts\.js/;
1111

12-
// Disable component stylesheet HMR to support page reload based rebuild testing.
13-
// Ideally this environment variable would be passed directly to the new serve process
14-
// but this would require signficant test changes due to the existing `ngServe` signature.
15-
const oldHMRValue = process.env['NG_HMR_CSTYLES'];
16-
process.env['NG_HMR_CSTYLES'] = '0';
17-
const port = await ngServe();
18-
process.env['NG_HMR_CSTYLES'] = oldHMRValue;
12+
// Disable HMR to support page reload based rebuild testing.
13+
const port = await ngServe('--no-hmr');
1914

2015
// Add a lazy route.
2116
await silentNg('generate', 'component', 'lazy');

‎tests/legacy-cli/e2e/tests/vite/ssr-entry-express.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export default async function () {
9090
'src/app/home/home.component.html',
9191
'home works',
9292
'yay home works!!!',
93+
true,
9394
);
9495
await validateResponse('/api/test', /foo/);
9596
await validateResponse('/home', /yay home works/);
@@ -111,9 +112,12 @@ async function modifyFileAndWaitUntilUpdated(
111112
filePath: string,
112113
searchValue: string,
113114
replaceValue: string,
115+
hmr = false,
114116
): Promise<void> {
115117
await Promise.all([
116-
waitForAnyProcessOutputToMatch(/Page reload sent to client/),
118+
waitForAnyProcessOutputToMatch(
119+
hmr ? /Component update sent to client/ : /Page reload sent to client/,
120+
),
117121
setTimeout(100).then(() => replaceInFile(filePath, searchValue, replaceValue)),
118122
]);
119123
}

‎tests/legacy-cli/e2e/tests/vite/ssr-entry-fastify.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export default async function () {
9090
'src/app/home/home.component.html',
9191
'home works',
9292
'yay home works!!!',
93+
true,
9394
);
9495
await validateResponse('/api/test', /foo/);
9596
await validateResponse('/home', /yay home works/);
@@ -111,9 +112,12 @@ async function modifyFileAndWaitUntilUpdated(
111112
filePath: string,
112113
searchValue: string,
113114
replaceValue: string,
115+
hmr = false,
114116
): Promise<void> {
115117
await Promise.all([
116-
waitForAnyProcessOutputToMatch(/Page reload sent to client/),
118+
waitForAnyProcessOutputToMatch(
119+
hmr ? /Component update sent to client/ : /Page reload sent to client/,
120+
),
117121
setTimeout(100).then(() => replaceInFile(filePath, searchValue, replaceValue)),
118122
]);
119123
}

‎tests/legacy-cli/e2e/tests/vite/ssr-entry-h3.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default async function () {
8181
'src/app/home/home.component.html',
8282
'home works',
8383
'yay home works!!!',
84+
true,
8485
);
8586
await validateResponse('/api/test', /foo/);
8687
await validateResponse('/home', /yay home works/);
@@ -102,9 +103,12 @@ async function modifyFileAndWaitUntilUpdated(
102103
filePath: string,
103104
searchValue: string,
104105
replaceValue: string,
106+
hmr = false,
105107
): Promise<void> {
106108
await Promise.all([
107-
waitForAnyProcessOutputToMatch(/Page reload sent to client/),
109+
waitForAnyProcessOutputToMatch(
110+
hmr ? /Component update sent to client/ : /Page reload sent to client/,
111+
),
108112
setTimeout(100).then(() => replaceInFile(filePath, searchValue, replaceValue)),
109113
]);
110114
}

‎tests/legacy-cli/e2e/tests/vite/ssr-entry-hono.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { setTimeout } from 'node:timers/promises';
33
import { replaceInFile, writeMultipleFiles } from '../../utils/fs';
44
import { ng, silentNg, waitForAnyProcessOutputToMatch } from '../../utils/process';
55
import { installPackage, installWorkspacePackages, uninstallPackage } from '../../utils/packages';
6-
import { ngServe, updateJsonFile, useSha } from '../../utils/project';
6+
import { ngServe, useSha } from '../../utils/project';
77
import { getGlobalVariable } from '../../utils/env';
88

99
export default async function () {
@@ -73,6 +73,7 @@ export default async function () {
7373
'src/app/home/home.component.html',
7474
'home works',
7575
'yay home works!!!',
76+
true,
7677
);
7778
await validateResponse('/api/test', /foo/);
7879
await validateResponse('/home', /yay home works/);
@@ -94,9 +95,12 @@ async function modifyFileAndWaitUntilUpdated(
9495
filePath: string,
9596
searchValue: string,
9697
replaceValue: string,
98+
hmr = false,
9799
): Promise<void> {
98100
await Promise.all([
99-
waitForAnyProcessOutputToMatch(/Page reload sent to client/),
101+
waitForAnyProcessOutputToMatch(
102+
hmr ? /Component update sent to client/ : /Page reload sent to client/,
103+
),
100104
setTimeout(100).then(() => replaceInFile(filePath, searchValue, replaceValue)),
101105
]);
102106
}

0 commit comments

Comments
 (0)
Please sign in to comment.