我尝试了上面的鲈鱼方法,但在使其发挥作用时遇到了一些困难。我确实发现它非常有帮助且信息丰富。利用他的想法,我能够创建一个新的 Angular 6 应用程序,并让应用程序状态通过 HMR 构建得以保留。我在 Github 上创建了一个项目,这样其他人如果想尝试的话可以把它拉下来,因为这是最好的学习方式。阅读代码注释并检查控制台日志,以了解事情发生的顺序以及它们如何工作。
https://github.com/ermcgrat/NgStarter https://github.com/ermcgrat/NgStarter
克隆项目,执行 npm install,然后使用“运行应用程序”npm 运行开始”。尝试更改 AppComponent 中的代码,看看 hmr 是如何工作的。
然而简而言之,我能够通过创建状态服务并在我的应用程序中利用它来实现状态持久性。应用程序模块 and hmr引导程序。首先,我从 Angular CLI 团队指定的基本 HMR 功能开始:
https://github.com/angular/angular-cli/wiki/stories-configure-hmr https://github.com/angular/angular-cli/wiki/stories-configure-hmr
这将使 HMR 正常工作,但不会保留状态。我延长了hmr.ts文件来保存模块被处置(卸载)时的状态。当新模块被评估时,它将从 HMR 模块读取保存的状态并将其注入到我们的新模块中:
hmr.ts
export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => {
module.hot.accept();
bootstrap().then(mod => {
// Attach a dispose handler. When this module is replaced, we will first run this code before
// evaluating the new module. (eg. running main.ts)
module.hot.dispose(data => {
if (mod.instance.hmrOnDestroy) {
mod.instance.hmrOnDestroy(data);
}
const appRef: ApplicationRef = mod.injector.get(ApplicationRef);
const elements = appRef.components.map(c => c.location.nativeElement);
const makeVisible = createNewHosts(elements);
mod.destroy();
makeVisible();
});
// Does this module have an hmrOnInit method for us to run?
// And is there state data from previous unloaded module to initalize?
let prevData;
if (module.hot.data && module.hot.data.appState) {
prevData = module.hot.data.appState;
}
if (mod.instance.hmrOnInit && prevData) {
mod.instance.hmrOnInit(prevData);
}
});
};
这是我们的 AppModule,实现了hmrOnInit and hmrOnDestroy上面使用的方法。值得注意的是 hmrOnInit 如何通过状态服务恢复应用程序状态(如果存在)。
应用程序模块.ts
export class AppModule {
constructor(private appRef: ApplicationRef, private stateService: AppStateService) { }
hmrOnInit(prevState: any) {
if (prevState) {
this.stateService.saveAppState(prevState);
// change detection.
this.appRef.tick();
}
}
hmrOnDestroy(data: any) {
// Here we will increment our hmrBuilds counter, and then save our state to
// data (module.hot.data), so that it will be available to the new module.
const hmrBuilds = this.stateService.getHmrBuilds() + 1;
this.stateService.saveHmrBuilds(hmrBuilds);
data.appState = this.stateService.getAppState();
}
}
最后是应用程序状态服务。唯一特别棘手的事情是我们本质上以两种形式维护应用程序状态。其中 1 个是用于同步访问的普通旧版对象(这对于 HMR 重建是必要的,因为无法保证模块中的异步函数在评估新模块之前完成)。第二个是我们的应用程序状态的可观察版本,以便各个组件可以轻松观察状态的更改/更新。
应用程序状态服务.ts
export class AppStateService {
// attach various component states to this object
// We maintain an object for synchronous use by the HMR, and an Observable for use by the application and its templates.
private appState: IAppState = { hmrBuilds: 0 };
private appStateSubject = new BehaviorSubject<IAppState>({ hmrBuilds: 0 });
public appState$: Observable<IAppState> = this.appStateSubject.asObservable();
constructor() { }
public getAppState() {
return this.appState;
}
public getHmrBuilds(): number {
return this.appState.hmrBuilds ? this.appState.hmrBuilds : 0;
}
public saveAppState(newState: IAppState) {
this.appState = newState;
this.appStateSubject.next(newState);
}
public saveHmrBuilds(buildNum: number) {
this.appState.hmrBuilds = buildNum;
}
}
最后,任何应用程序组件现在都可以观察到这一点应用程序状态$并在其组件代码或模板中使用它。
我还想指出,这种在 HMR 构建之间维护状态的方法本质上会导致单一事实来源。我认为像这样的州立图书馆ngrx会与这样的东西完美结合。