PatrickJS / angular-hmr

:fire: Angular Hot Module Replacement for Hot Module Reloading
https://patrickjs.com
Apache License 2.0
507 stars 45 forks source link

Support for Angular 7? #81

Closed Epono closed 5 years ago

Epono commented 5 years ago

Hi,

I'm using Angular 7 and I followed these instructions, but states are not saved. Does it support Angular 7 yet? Is there something missing from the documentation? Or am I just a little stupid and did I miss something?

Also, this comment suggests that it won't save state for the modified component, only states of other components, is that what is happening?

Thanks for your help!

bufke commented 5 years ago

I couldn't get it working either. I think the issue is the angular cli wiki instructions don't mesh with the instructions in this repo.

bufke commented 5 years ago

Actually I got it working. Just ignore the angular cli instructions. The only thing to take from that is using an environment to enable/disable hmr. Here's the relevant lines from my main.ts

const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);

if (environment.hmr) {
  if (module[ 'hot' ]) {
    bootstrap().then((ngModuleRef) => {
      return hmrModule(ngModuleRef, module);
    }).catch(err => console.log(err));
  } 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));
}

Otherwise follow the instructions in this repo's readme. This is tested with angular 7 - so this ticket could probably be closed. Perhaps a section on using with angular cli could be added that warns against using angular-cli's documentation.

Epono commented 5 years ago

Thank you!

After tinkering a bit with your suggestion, I got it working too. Here are my app.module.ts and main.ts if anyone's interested:


main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

import { hmrModule } from '@angularclass/hmr';

if (environment.production) {
  enableProdMode();
}

const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);

if (environment.hmr) {
  if (module[ 'hot' ]) {
    // hmrBootstrap(module, bootstrap);
    bootstrap().then((ngModuleRef) => {
      return hmrModule(ngModuleRef, module);
    }).catch(err => console.log(err));
  } 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));
}

app.module.ts

import { removeNgStyles, createNewHosts, createInputTransfer } from '@angularclass/hmr';
import { NgModule, ApplicationRef } from "@angular/core";
import { AppComponent } from "./app.component";
...

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  imports: [
    ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
  constructor(public appRef: ApplicationRef) {}
  hmrOnInit(store) {
    if (!store || !store.state) return;
    // console.log('HMR store', store);
    // console.log('store.state.data:', store.state.data)
    // inject AppStore here and update it
    // this.AppStore.update(store.state)
    if ('restoreInputValues' in store) {
      store.restoreInputValues();
    }
    // change detection
    this.appRef.tick();
    delete store.state;
    delete store.restoreInputValues;
  }
  hmrOnDestroy(store) {
    var cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement);
    // recreate elements
    store.disposeOldHosts = createNewHosts(cmpLocation)
    // inject your AppStore and grab state then set it on store
    // var appState = this.AppStore.get()
    store.state = {data: 'yolo'};
    // store.state = Object.assign({}, appState)
    // save input values
    store.restoreInputValues  = createInputTransfer();
    // remove styles
    removeNgStyles();
  }
  hmrAfterDestroy(store) {
    // display new elements
    store.disposeOldHosts()
    delete store.disposeOldHosts;
    // anything you need done the component is removed
  }
}

And I agree, a clearer documentation would be nice.

fergardi commented 5 years ago

I'm also having issues with this. Tried your code @Epono, but it does not work for me. I can see clearly in the console the logs stating the changes, but no changes are being done in the browser.

image

Besides, when I start my app, I can see a strange error:

image

I got my main.ts and my app.module.ts exactly as yours. Any idea or clue I may have passed?

Thanks in advance.

Epono commented 5 years ago

Never encountered this error :/

Did you follow these instructions as well? Adding an environment and updating angular.json

Also, I run my projet with this command ng serve --configuration hmr, I'm not sure what yours does (I'm really no expert in Angular)

Epono commented 5 years ago

I created a small repo with a project in which HMR works for Angular 7. Clone it, npm i and ng serve --configuration hmr, put some text in the input fields, change something in the code and you should see the changes while keeping what you put in the fields.

beelio commented 5 years ago

I created a small repo with a project in which HMR works for Angular 7. Clone it, npm i and ng serve --configuration hmr, put some text in the input fields, change something in the code and you should see the changes while keeping what you put in the fields.

I tried it out but it doesn't work for me.

Epono commented 5 years ago

That's weird, I just tried it again with Angular 7.1.2 and it worked.
What's your problem exactly?

aymenha commented 5 years ago

@beelio i tried it and it works for me too what did you try exactly? maybe a fork we can look at?

webia1 commented 5 years ago

still an issue, see here: https://stackoverflow.com/questions/55355133/angular-7-hmr-hot-module-replacement-does-not-work-if-any-route-resolve-invo