UNPKG

4.48 kBMarkdownView Raw
1<p align="center">
2 <a href="https://github.com/PatrickJS/angular-hmr" target="_blank">
3 <img src="https://cloud.githubusercontent.com/assets/1016365/26220655/77e69902-3be1-11e7-8305-87471affe598.png" alt="Angular HMR" width="500" height="320"/>
4 </a>
5</p>
6
7
8# Angular Hot Module Replacement
9> Angular-HMR
10Hot Module Reloading for Webpack and Angular. All versions of Angular and Webpack will work with this module
11
12`npm install @angularclass/hmr`
13
14![hmr-state-dom](https://cloud.githubusercontent.com/assets/1016365/18380378/e573320e-762b-11e6-99e0-cc110ffacc6a.gif)
15
16`main.browser.ts`
17```typescript
18import { removeNgStyles, createNewHosts, bootloader } from '@angularclass/hmr';
19
20@NgModule({
21 bootstrap: [ App ],
22 declarations: [ App ],
23 imports: [
24 // Angular 2
25 BrowserModule,
26 FormsModule,
27 HttpModule,
28 RouterModule.forRoot([], {
29 useHash: true
30 }),
31 // app
32 appModule
33 // vendors
34 ],
35 providers: []
36})
37class MainModule {
38 constructor(public appRef: ApplicationRef) {}
39 hmrOnInit(store) {
40 if (!store || !store.state) return;
41 console.log('HMR store', store);
42 console.log('store.state.data:', store.state.data)
43 // inject AppStore here and update it
44 // this.AppStore.update(store.state)
45 if ('restoreInputValues' in store) {
46 store.restoreInputValues();
47 }
48 // change detection
49 this.appRef.tick();
50 delete store.state;
51 delete store.restoreInputValues;
52 }
53 hmrOnDestroy(store) {
54 var cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement);
55 // recreate elements
56 store.disposeOldHosts = createNewHosts(cmpLocation)
57 // inject your AppStore and grab state then set it on store
58 // var appState = this.AppStore.get()
59 store.state = {data: 'yolo'};
60 // store.state = Object.assign({}, appState)
61 // save input values
62 store.restoreInputValues = createInputTransfer();
63 // remove styles
64 removeNgStyles();
65 }
66 hmrAfterDestroy(store) {
67 // display new elements
68 store.disposeOldHosts()
69 delete store.disposeOldHosts;
70 // anything you need done the component is removed
71 }
72}
73
74export function main() {
75 return platformBrowserDynamic().bootstrapModule(MainModule)
76 // use `hmrModule` or the "@angularclass/hmr-loader"
77 .then((ngModuleRef: any) => {
78 // `module` global ref for webpackhmr
79 // Don't run this in Prod
80 return hmrModule(ngModuleRef, module);
81 });
82}
83
84// boot on document ready
85bootloader(main);
86
87```
88`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.
89
90## Important Helpers
91* **removeNgStyles**: remove angular styles
92* **createNewHosts and disposeOldHosts**: recreate root elements for bootstrapping
93* **bootloader**: boot on document ready or boot if it's already ready
94* **createInputTransfer** and **restoreInputValues**: transfer input DOM state during replacement
95
96## Production
97In production you only need bootloader which just does this:
98```typescript
99export function bootloader(main) {
100 if (document.readyState === 'complete') {
101 main()
102 } else {
103 document.addEventListener('DOMContentLoaded', main);
104 }
105}
106```
107You would bootstrap your app the normal way, in production, after dom is ready. Also, in production, you should remove the loader:
108
109___
110
111## @NGRX/platform (NGRX 4.x.x)
112To hook into NGRX 4 you simply need to supply a reducer to set the state, and include it in your development metaReducers.
113```typescript
114// make sure you export for AoT
115export function stateSetter(reducer: ActionReducer<any>): ActionReducer<any> {
116 return function(state: any, action: any) {
117 if (action.type === 'SET_ROOT_STATE') {
118 return action.payload;
119 }
120 return reducer(state, action);
121 };
122}
123```
124In your root reducer you can do something like this to include it in your `metaReducers`.
125You should access your environment here and only include this in development.
126```typescript
127/**
128 * By default, @ngrx/store uses combineReducers with the reducer map to compose
129 * the root meta-reducer. To add more meta-reducers, provide an array of meta-reducers
130 * that will be composed to form the root meta-reducer.
131 */
132export const metaReducers: ActionReducer<any, any>[] = [stateSetter]
133```
134Simply supply the metaReducer to the `StoreModule` and your hmr is hooked in.
135```typescript
136 StoreModule.forRoot(reducers, { metaReducers }),
137```
138
139
140
141enjoy — **PatrickJS**