NG2: angular2-webpack-starter - what is the purpose of HMR?
Asked Answered
S

1

11

I'm cleaning up my angular2 project and for many reasons, I've decided to start with a seed. This one.

This seed uses HMR but I don't fully understand what is the purpose of that.

At the beginning, I was thinking that HMR was about dynamical loading and replacing component while the web app is running.

But since I've put my eyes on the app.service.ts, I've got lost. Here is the code of this service :

import { Injectable } from '@angular/core';
import { HmrState } from 'angular2-hmr';

@Injectable()
export class AppState {
  // @HmrState() is used by HMR to track the state of any object during a hot module replacement
  @HmrState() _state = { };

  constructor() {

  }

  // already return a clone of the current state
  get state() {
    return this._state = this._clone(this._state);
  }
  // never allow mutation
  set state(value) {
    throw new Error('do not mutate the `.state` directly');
  }


  get(prop?: any) {
    // use our state getter for the clone
    const state = this.state;
    return state[prop] || state;
  }

  set(prop: string, value: any) {
    // internally mutate our state
    return this._state[prop] = value;
  }


  _clone(object) {
    // simple object clone
    return JSON.parse(JSON.stringify( object ));
  }
}

I was thinking that service simply provides a space to store some data. After all, this is just an example.

But this line did confuse me: @HmrState() _state = { };. Is this service using HMR to manage data that we can manage with this.appState.set('value', value); (this is from the HomeComponent) like a little Redux's store (without actions, dispatcher, blabla) ?

What is the purpose of the decorator @HmrState() here ?

Thanks.

Sextans answered 28/6, 2016 at 14:1 Comment(0)
L
17

When I had a first look at angular2-hmr I was surprised as well. I thought it is something like a hot swap, but it is not really one. At least from what I see when I use it.

It looks like it always reloads the application regardless of the changes type. However it can restore the state of the swapped objects. The intention of @HmrState() is to restore the component's state when the application is reloaded.

Let's take a look at a small example. We have a form with an input which is bound (with ngModel or formControl) to some component's property:

@Component({
  template: `
    <input [(ngModel)]="inputValue" />
    <button (click)="click()">Click me</button>
  `
})
export class MyComponent {

  public inputValue: string;

  public click() {
    console.log(this.inputValue);
  }

}

We type in some value, e.g. 'test123' and click the button. It works.

Then suddenly we realise: the log description is missing. So we go to our code and add it:

@Component({
  template: `
    <input [(ngModel)]="inputValue" />
    <button (click)="click()">Click me</button>
  `
})
export class MyComponent {

  inputValue: string;

  public click() {
    console.log('inputValue:', this.inputValue);
  }

}

Then the component's code is changed, HMR replaces it and we realise that the inputValue is lost.

To restore the value during the HMR process angular2-hmr needs some information about the object state before it was wiped out. Here the @HmrState() comes into play: it points out to the state that should be restored. In other words to make the first code snippet work with HMR the following should be done:

@Component({
  template: `
    <input [(ngModel)]="state.inputValue" />
    <button (click)="click()">Click me</button>
  `
})
export class MyComponent {

  @HmrState() public state = {
    inputValue: ''
  }

  public click() {
    console.log(this.state.inputValue);
  }

}

The state is now known to the HMR processor and it can use the state to restore our value. Now when we change the component code to:

@Component({
  template: `
    <input [(ngModel)]="state.inputValue" />
    <button (click)="click()">Click me</button>
  `
})
export class MyComponent {

  @HmrState() public state = {
    inputValue: ''
  }

  public click() {
    console.log('inputValue:', this.state.inputValue);
  }

}

it magically reloads our application and the inputValue's value is preserved.

Liver answered 10/8, 2016 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.