首页 > 解决方案 > 当 Scully 已经预渲染内容时,如何防止 Angular 在运行时加载内容?

问题描述

我有一项服务可以从我的 Angular 应用程序中的无头 CMS Cockpit 中获取数据。我正在使用 Scully 来预渲染我的页面。它在进行预渲染时效果很好,它获取内容构建时间并创建一个静态页面,但是当打开页面时,Angular 会再次加载该数据,尽管它应该来自某种 scully 上下文。

标签: angularangular-scullyscullyscullyio

解决方案


在查看了 scully 的源代码后,我设法在那里找到了一个有用的服务:TransferStateService. 所以我修改了我的服务,以便在从 Cockpit 获取数据的服务中发挥我的优势:

private getCockpitData<T>(path: string): Observable<T> {
    const url = `${this.baseApiUrl}${path}`;
    const urlHash = btoa(url);
    if (isScullyRunning()) {
      const headers = new HttpHeaders({ 'Cockpit-Token': environment.cockpit.apiccessToken });
      const queryParams = new HttpParams({ fromObject: { lang: 'uk' } });
      return this.http
        .get<T>(url, { headers, params: queryParams })
        .pipe(
          tap(data => this.transferStateService.setState<T>(urlHash, data)),
          shareReplay(1)
        );
    }
    return this.transferStateService.getState<T>(urlHash).pipe(shareReplay(1));
}

因此,当 scully 运行时,我们会获取数据并使用副作用TransferStateService在页面上设置数据。否则,当它已经是一个生成的页面时,我们只是从页面中获取该数据,而不是执行另一个请求。然后任何端点都可以像这样调用这个方法:

getHeaderContentData(): Observable<HeaderContent> {
  return this.getCockpitData<HeaderContent>('singletons/get/header');
}

因此,当使用服务加载数据时,我的所有组件都将使用相同的接口接收正确的数据,并在内部处理数据的来源。

此处的重要说明:确保您还IdleMonitorService注入了某处,例如在 AppModule 中,如下所示:

export class AppModule {
  // @ts-ignore Property 'idle' is declared but its value is never read.
  // IdleMonitorService has to be injected so that the instance of it is created
  // which allows scully to track wether angular page became idle in build time
  constructor(private readonly idle: IdleMonitorService) {}
}

如果IdleMonitorService没有在任何地方注入 Angular 永远不会创建它的实例,并且 scully 无法跟踪 angular 在预渲染期间何时空闲,这会导致构建时间更长,并且它也会错过window['ScullyIO']设置为'generated',因此isScullyGenerated()总是会false在运行时返回。

编辑:从 0.0.15 版开始,@scullyio/ng-lib IdleMonitorService不再需要注入AppModule,现在只需要导入即可ScullyLibModule


推荐阅读