Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hot Module Replacement in angular 11

Tags:

angular

I have an angular 10 project that I opened at work. after a while, when I saw that HMR added to angular 11 I upgraded the project by trying to work with HMR. Since it didn't, I opened a brand new angular project. checked that HMR working. I moved all components, services, modules, styles (without node folder of course) and launched it using ng serve --hmr and it failed to work again. the page is being refreshed.

I am on this 2 days. Any idea will be appreciated? thank you. my package JSON is:

{
  "name": "date-manager-ui",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~11.2.4",
    "@angular/cdk": "^11.2.3",
    "@angular/common": "~11.2.4",
    "@angular/compiler": "~11.2.4",
    "@angular/core": "~11.2.4",
    "@angular/forms": "~11.2.4",
    "@angular/material": "^11.2.3",
    "@angular/platform-browser": "~11.2.4",
    "@angular/platform-browser-dynamic": "~11.2.4",
    "@angular/router": "~11.2.4",
    "angular2-text-mask": "^9.0.0",
    "bootstrap": "^4.6.0",
    "rxjs": "~6.6.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.3"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1102.3",
    "@angular/cli": "~11.2.3",
    "@angular/compiler-cli": "~11.2.4",
    "@types/jasmine": "~3.6.0",
    "@types/node": "^12.11.1",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~3.6.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.1.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "~4.1.5"
  }
}

update: i opened a new brand angular 11 project, ran with --hmr. i written alert() at AppComponent's ngOnInit. i see that on each save, ngOnInit is called ( alert pops up). so, all code, ajax calls will be executed. isnt hmr suppose to bypass that? if all code under ngOnInit executed, how hmr is helpful. what am i missing here?

export class AppComponent {
  title = 'AppTest';

  ngOnInit(): void {
    alert();
  }
}
like image 227
Ronen009 Avatar asked Mar 14 '26 22:03

Ronen009


2 Answers

Lets do it step by step.

  1. Install the required hmr angular package.

    npm install @angularclass/hmr --save-dev
    
  2. Add a new environment file called environment.hmr.ts inside your src/environments folder

    export const environment = {
      production: false,
      hmr: true
    }
    
  3. Update 'build' & 'serve' properties in the angular.json

     "build": {
       "configurations": {
          //
         "hmr": {
            "fileReplacements": [
             {
               "replace": "src/environments/environment.ts",
               "with": "src/environments/environment.hmr.ts"
             }
            ]
         }
         //
       }
     }
    
     "serve": {
         "configurations": {
             //
             "hmr": {
                "hmr": true,
                "browserTarget": "date-manager-ui:build:hmr"
             }
             //
         }
     }
    
  4. Add 'node' into the types array in compilerOptions in src/tsconfig.app.json file.

    {
      //
      "compilerOptions": {
         //
         "types": ["node"]
      }
      //
    }
    
  5. Now we need to add the hmr property with value 'false' in all other environment files except the newly added environment.hmr.ts file

    export const environment = {
      //
      hmr: false
    }
    
  6. Lets configure our app to use hmr by creating a new file named hmr.ts inside src folder and finally by updating main.ts file as well.

    //hmr.ts
    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()
    })
    }
    
    //main.ts
    import { enableProdMode } from '@angular/core'
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
    import { environment } from './environments/environment'
    import { hmrBootstrap } from './hmr'
    import { RootModule } from './app/root/root.module'
    
    if (environment.production) {
      enableProdMode()
    }
    
    const bootstrap = () => platformBrowserDynamic().bootstrapModule(RootModule)
    
    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))
    }
    
  7. Final step. Add hmr property in scripts object in the package.json file to make running app easier.

    "scripts": {
      //
      "hmr": "ng serve --configuration hmr"
    }
    
like image 62
Zam Abdul Vahid Avatar answered Mar 16 '26 13:03

Zam Abdul Vahid


Updated to angular 12 today. hmr started working.

like image 45
Ronen009 Avatar answered Mar 16 '26 15:03

Ronen009



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!