当内容已经被 Scully 预渲染时,如何防止 Angular 在运行时加载内容?
How to prevent Angular from loading content in runtime when it was already prerendered by Scully?
我有一项服务可以从我的 Angular 应用中的无头 CMS Cockpit 获取数据。我正在使用 Scully 预呈现我的页面。它在进行预呈现时效果很好,它获取内容构建时间并创建静态页面,但是在打开页面时,Angular 会再次加载该数据,尽管它应该来自某种 scully 上下文。
在查看了 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()
在运行时将始终 return false
。
编辑: 从 @scullyio/ng-lib
IdleMonitorService
版本 0.0.15 开始不再需要在 AppModule
中注入,现在只需要需要导入 ScullyLibModule
。
我有一项服务可以从我的 Angular 应用中的无头 CMS Cockpit 获取数据。我正在使用 Scully 预呈现我的页面。它在进行预呈现时效果很好,它获取内容构建时间并创建静态页面,但是在打开页面时,Angular 会再次加载该数据,尽管它应该来自某种 scully 上下文。
在查看了 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()
在运行时将始终 return false
。
编辑: 从 @scullyio/ng-lib
IdleMonitorService
版本 0.0.15 开始不再需要在 AppModule
中注入,现在只需要需要导入 ScullyLibModule
。