Thank you for reading my blog posts, I am no longer publishing new content on this platform. You can find my latest content on either mainawycliffe.dev or All Things Typescript Newsletter (✉️)
Hot Module Replacement (HMR) is a key webpack feature that is not enable by default in Angular. It allows for modules to be replaced without need for a full browser refresh. This allows you to retain much of the application state, usually lost when reloading. It also saves valuable times by only updating what has changed. And changes to the code reflect almost instantly, like when you are messing with dev tools on the browser. This is great for productivity.
In this post, I will show you how to add Hot Module Replacement to your angular project. We will add it as an extra tool for you, without taking away the tools you are already used to such as ng serve. If you find it useful, you can continue using it and if not, nothing changes, you can fallback to your old tools. To enable HMR, we are going to make some modification to our code and add a new dev dependency. Let’s gets started:
First, we are going to install @angularclass/hmr
dev package:
yarn add –dev @angularclass/hmr
// or with npm
npm install --save-dev @angularclass/hmr
Next, we need to add an extra environment for our angular application, specifically for HMR. On top of that, we need to modify our existing environments and set HMR to false. You can learn more about environment variables here.
Create a new environment file called environment.hmr.ts
, under src/environment
directory at the root of your workspace. Add the following code:
export const environment = {
production: false,
hmr: true
};
Please note, we added an extra HMR property for our environment and set it to true. After these, we need to modify our angular configuration and add this environment for both our build and serve properties. Open angular.json
at the root of your angular workspace. Under build property, add a new configuration for HMR, with the content below:
"build": {
"configurations": {
// ...
"hmr": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.hmr.ts"
}
]
}
}
}
And then under serve property, add another HMR configuration with the content below:
"serve": {
"configurations": {
// ...
"hmr": {
"hmr": true,
"browserTarget": "<project-name>:build:hmr"
}
}
}
Next up, modify your typescript configurations (src/tsconfig.app.json
), to add Node to the typings array.
{
// ...
"compilerOptions": {
// ...
"types": ["node"]
}
}
Next, we need to modify our existing environment files, and set the HMR property to false. So, inside our environment.ts
and environment.prod.ts
add the hmr property and set it to false. Do the same for all other extra environments you may have in your app.
// environment.prod.ts
export const environment = {
production: true,
hmr: false
};
// environment.ts
export const environment = {
production: false,
hmr: false
};
Next up, we need to configure our angular app to use Hot Module Replacement. If you have an Angular Workspace with multiple projects/apps, you will have to do this for each app. First, create a new file – src/hmr.ts
– next to the src/main.ts
file and add the following code:
import { NgModuleRef, ApplicationRef } from '@angular/core';
import { createNewHosts } from '@angularclass/hmr';
export const hmrBootstrap = (
module: any,
bootstrap: () => Promise<NgModuleRef<any>>
) => {
let ngModule: NgModuleRef<any>;
module.hot.accept();
bootstrap().then(mod => (ngModule = mod));
module.hot.dispose(() => {
const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);
const elements = appRef.components.map(c => c.location.nativeElement);
const makeVisible = createNewHosts(elements);
ngModule.destroy();
makeVisible();
});
};
Then, modify src/main.ts
file to use src/hmr.ts
code when serving your app with Hot Module Replacement enabled. This modification will only apply when you serve your app with --configuration hmr
flag and not under any other circumstances.
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { hmrBootstrap } from './hmr';
if (environment.production) {
enableProdMode();
}
const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);
if (environment.hmr) {
if (module['hot']) {
hmrBootstrap(module, bootstrap);
} else {
console.error('HMR is not enabled for webpack-dev-server!');
console.log('Are you using the --hmr flag for ng serve?');
}
} else {
bootstrap().catch(err => console.log(err));
}
Now, you can serve your app using the command below:
ng serve --configuration hmr
But since this is a long command to write every time, we can add it to our npm scripts
in our package.json
to make it shorter and easier to remember:
"scripts": {
// ...
"hmr": "ng serve --configuration hmr"
}
And finally, we can just run:
npm run hmr
Each time you run the command, you will get the following warning:
NOTICE: Hot Module Replacement (HMR) is enabled for the dev server.
With some more information on where to learn more about Hot Module Replacement.
Angular has built-in input validators for common input validation such as checking min and max length, email etc. These built-in validators …
Read MoreIn an earlier post, I wrote about Angular CLI Workspaces, a new feature in Angular 6 that allows you to have more than one project in a …
Read MoreOne of the least talked about features of Angular 6 is Angular CLI Workspaces. Workspaces or Angular CLI Workspaces give angular developers …
Read MoreIn this post, we are going to look at how to deploy an angular app using docker. Docker containers can be used to simplify the process of …
Read MoreIn my last post, I looked at how you can use HTTP Interceptors to attach and refresh authorization tokens. In this post, we are going to use …
Read MoreIn this post, we are going to build a http interceptor for refreshing authorization tokens once expired. The idea here is to be able to …
Read More