{"id":13406739,"url":"https://github.com/PatrickJS/angular-hmr","last_synced_at":"2025-03-14T11:30:40.359Z","repository":{"id":38470956,"uuid":"54366437","full_name":"PatrickJS/angular-hmr","owner":"PatrickJS","description":":fire: Angular Hot Module Replacement for Hot Module Reloading","archived":false,"fork":false,"pushed_at":"2023-01-07T21:04:10.000Z","size":445,"stargazers_count":507,"open_issues_count":36,"forks_count":45,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-10-29T17:14:00.125Z","etag":null,"topics":["angular","angular-hmr","angular2","angular2-hmr","angular4","angularclass","hmr","hot-module-replacement","hot-reload","loader","webpack"],"latest_commit_sha":null,"homepage":"https://patrickjs.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PatrickJS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-21T06:52:34.000Z","updated_at":"2024-10-22T09:56:43.000Z","dependencies_parsed_at":"2023-02-08T01:47:10.390Z","dependency_job_id":null,"html_url":"https://github.com/PatrickJS/angular-hmr","commit_stats":null,"previous_names":["angularclass/angular2-hmr"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatrickJS%2Fangular-hmr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatrickJS%2Fangular-hmr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatrickJS%2Fangular-hmr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PatrickJS%2Fangular-hmr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PatrickJS","download_url":"https://codeload.github.com/PatrickJS/angular-hmr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243569063,"owners_count":20312355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-hmr","angular2","angular2-hmr","angular4","angularclass","hmr","hot-module-replacement","hot-reload","loader","webpack"],"created_at":"2024-07-30T19:02:38.004Z","updated_at":"2025-03-14T11:30:40.351Z","avatar_url":"https://github.com/PatrickJS.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/PatrickJS/angular-hmr\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://cloud.githubusercontent.com/assets/1016365/26220655/77e69902-3be1-11e7-8305-87471affe598.png\" alt=\"Angular HMR\" width=\"500\" height=\"320\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\n# Angular Hot Module Replacement\n\u003e Angular-HMR\nHot Module Reloading for Webpack and Angular. All versions of Angular and Webpack will work with this module\n\n`npm install @angularclass/hmr`\n\n![hmr-state-dom](https://cloud.githubusercontent.com/assets/1016365/18380378/e573320e-762b-11e6-99e0-cc110ffacc6a.gif)\n\n`main.browser.ts`\n```typescript\nimport { removeNgStyles, createNewHosts, bootloader } from '@angularclass/hmr';\n\n@NgModule({\n  bootstrap: [ App ],\n  declarations: [ App ],\n  imports: [\n    // Angular 2\n    BrowserModule,\n    FormsModule,\n    HttpModule,\n    RouterModule.forRoot([], {\n      useHash: true\n    }),\n    // app\n    appModule\n    // vendors\n  ],\n  providers: []\n})\nclass MainModule {\n  constructor(public appRef: ApplicationRef) {}\n  hmrOnInit(store) {\n    if (!store || !store.state) return;\n    console.log('HMR store', store);\n    console.log('store.state.data:', store.state.data)\n    // inject AppStore here and update it\n    // this.AppStore.update(store.state)\n    if ('restoreInputValues' in store) {\n      store.restoreInputValues();\n    }\n    // change detection\n    this.appRef.tick();\n    delete store.state;\n    delete store.restoreInputValues;\n  }\n  hmrOnDestroy(store) {\n    var cmpLocation = this.appRef.components.map(cmp =\u003e cmp.location.nativeElement);\n    // recreate elements\n    store.disposeOldHosts = createNewHosts(cmpLocation)\n    // inject your AppStore and grab state then set it on store\n    // var appState = this.AppStore.get()\n    store.state = {data: 'yolo'};\n    // store.state = Object.assign({}, appState)\n    // save input values\n    store.restoreInputValues  = createInputTransfer();\n    // remove styles\n    removeNgStyles();\n  }\n  hmrAfterDestroy(store) {\n    // display new elements\n    store.disposeOldHosts()\n    delete store.disposeOldHosts;\n    // anything you need done the component is removed\n  }\n}\n\nexport function main() {\n  return platformBrowserDynamic().bootstrapModule(MainModule)\n    // use `hmrModule` or the \"@angularclass/hmr-loader\"\n    .then((ngModuleRef: any) =\u003e {\n      // `module` global ref for webpackhmr\n      // Don't run this in Prod\n      return hmrModule(ngModuleRef, module);\n    });\n}\n\n// boot on document ready\nbootloader(main);\n\n```\n`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.\n\n## Important Helpers\n* **removeNgStyles**: remove angular styles\n* **createNewHosts and disposeOldHosts**: recreate root elements for bootstrapping\n* **bootloader**: boot on document ready or boot if it's already ready\n* **createInputTransfer** and **restoreInputValues**: transfer input DOM state during replacement\n\n## Production\nIn production you only need bootloader which just does this:\n```typescript\nexport function bootloader(main) {\n  if (document.readyState === 'complete') {\n    main()\n  } else {\n    document.addEventListener('DOMContentLoaded', main);\n  }\n}\n```\nYou would bootstrap your app the normal way, in production, after dom is ready. Also, in production, you should remove the loader:\n\n___\n\n## @NGRX/platform (NGRX 4.x.x)\nTo hook into NGRX 4 you simply need to supply a reducer to set the state, and include it in your development metaReducers.\n```typescript\n// make sure you export for AoT\nexport function stateSetter(reducer: ActionReducer\u003cany\u003e): ActionReducer\u003cany\u003e {\n  return function(state: any, action: any) {\n    if (action.type === 'SET_ROOT_STATE') {\n      return action.payload;\n    }\n    return reducer(state, action);\n  };\n}\n```\nIn your root reducer you can do something like this to include it in your `metaReducers`.\nYou should access your environment here and only include this in development.\n```typescript\n/**\n * By default, @ngrx/store uses combineReducers with the reducer map to compose\n * the root meta-reducer. To add more meta-reducers, provide an array of meta-reducers\n * that will be composed to form the root meta-reducer.\n */\nexport const metaReducers: ActionReducer\u003cany, any\u003e[] = [stateSetter]\n```\nSimply supply the metaReducer to the `StoreModule` and your hmr is hooked in.\n```typescript\n StoreModule.forRoot(reducers, { metaReducers }),\n```\n\n\n\nenjoy — **PatrickJS**\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPatrickJS%2Fangular-hmr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPatrickJS%2Fangular-hmr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPatrickJS%2Fangular-hmr/lists"}