项目作者: PatrickJS

项目描述 :
:fire: Angular Hot Module Replacement for Hot Module Reloading
高级语言: TypeScript
项目地址: git://github.com/PatrickJS/angular-hmr.git
创建时间: 2016-03-21T06:52:34Z
项目社区:https://github.com/PatrickJS/angular-hmr

开源协议:Apache License 2.0

下载




Angular HMR

Angular Hot Module Replacement

Angular-HMR
Hot Module Reloading for Webpack and Angular. All versions of Angular and Webpack will work with this module

npm install @angularclass/hmr

hmr-state-dom

main.browser.ts

  1. import { removeNgStyles, createNewHosts, bootloader } from '@angularclass/hmr';
  2. @NgModule({
  3. bootstrap: [ App ],
  4. declarations: [ App ],
  5. imports: [
  6. // Angular 2
  7. BrowserModule,
  8. FormsModule,
  9. HttpModule,
  10. RouterModule.forRoot([], {
  11. useHash: true
  12. }),
  13. // app
  14. appModule
  15. // vendors
  16. ],
  17. providers: []
  18. })
  19. class MainModule {
  20. constructor(public appRef: ApplicationRef) {}
  21. hmrOnInit(store) {
  22. if (!store || !store.state) return;
  23. console.log('HMR store', store);
  24. console.log('store.state.data:', store.state.data)
  25. // inject AppStore here and update it
  26. // this.AppStore.update(store.state)
  27. if ('restoreInputValues' in store) {
  28. store.restoreInputValues();
  29. }
  30. // change detection
  31. this.appRef.tick();
  32. delete store.state;
  33. delete store.restoreInputValues;
  34. }
  35. hmrOnDestroy(store) {
  36. var cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement);
  37. // recreate elements
  38. store.disposeOldHosts = createNewHosts(cmpLocation)
  39. // inject your AppStore and grab state then set it on store
  40. // var appState = this.AppStore.get()
  41. store.state = {data: 'yolo'};
  42. // store.state = Object.assign({}, appState)
  43. // save input values
  44. store.restoreInputValues = createInputTransfer();
  45. // remove styles
  46. removeNgStyles();
  47. }
  48. hmrAfterDestroy(store) {
  49. // display new elements
  50. store.disposeOldHosts()
  51. delete store.disposeOldHosts;
  52. // anything you need done the component is removed
  53. }
  54. }
  55. export function main() {
  56. return platformBrowserDynamic().bootstrapModule(MainModule)
  57. // use `hmrModule` or the "@angularclass/hmr-loader"
  58. .then((ngModuleRef: any) => {
  59. // `module` global ref for webpackhmr
  60. // Don't run this in Prod
  61. return hmrModule(ngModuleRef, module);
  62. });
  63. }
  64. // boot on document ready
  65. bootloader(main);

bootloader is only needed to detect that the dom is ready before bootstraping otherwise bootstrap. This is needed because that dom is already ready during reloading.

Important Helpers

  • removeNgStyles: remove angular styles
  • createNewHosts and disposeOldHosts: recreate root elements for bootstrapping
  • bootloader: boot on document ready or boot if it’s already ready
  • createInputTransfer and restoreInputValues: transfer input DOM state during replacement

Production

In production you only need bootloader which just does this:

  1. export function bootloader(main) {
  2. if (document.readyState === 'complete') {
  3. main()
  4. } else {
  5. document.addEventListener('DOMContentLoaded', main);
  6. }
  7. }

You would bootstrap your app the normal way, in production, after dom is ready. Also, in production, you should remove the loader:


@NGRX/platform (NGRX 4.x.x)

To hook into NGRX 4 you simply need to supply a reducer to set the state, and include it in your development metaReducers.

  1. // make sure you export for AoT
  2. export function stateSetter(reducer: ActionReducer<any>): ActionReducer<any> {
  3. return function(state: any, action: any) {
  4. if (action.type === 'SET_ROOT_STATE') {
  5. return action.payload;
  6. }
  7. return reducer(state, action);
  8. };
  9. }

In your root reducer you can do something like this to include it in your metaReducers.
You should access your environment here and only include this in development.

  1. /**
  2. * By default, @ngrx/store uses combineReducers with the reducer map to compose
  3. * the root meta-reducer. To add more meta-reducers, provide an array of meta-reducers
  4. * that will be composed to form the root meta-reducer.
  5. */
  6. export const metaReducers: ActionReducer<any, any>[] = [stateSetter]

Simply supply the metaReducer to the StoreModule and your hmr is hooked in.

  1. StoreModule.forRoot(reducers, { metaReducers }),

enjoy — PatrickJS