我正在开发一个基于 angular universal starter 的小型网络应用程序和 pokeapi 。由于我想要显示的许多数据实际上并没有改变,因此我想使用预渲染页面来减少对 API 的请求数量并提高性能。对于我的示例,我在应用程序的主页上放置了一个神奇宝贝列表,我从 API 中检索该列表。
export class HomeComponent implements OnInit {
pokemon$: ReplaySubject<ResourceList> = new ReplaySubject<ResourceList>();
constructor(private pokedexService: PokedexService, private state: TransferState) { }
ngOnInit() {
if (this.state.hasKey(STATE_KEY_POKEMON)) {
this.pokemon$.next(this.state.get(STATE_KEY_POKEMON, {} as ResourceList));
}
else {
this.pokedexService.getResourceByCategory(ResourceCategory.POKEMON)
.subscribe((resourceList: ResourceList) => {
this.pokemon$.next(resourceList);
this.state.set(STATE_KEY_POKEMON, resourceList.results);
});
}
}
}
当我让客户端渲染页面时,这工作得很好。但是,当我尝试预渲染应用程序时,构建过程会挂起。由于我正在运行 API 的本地实例,因此我可以看到发出了请求并且返回了 200 状态。构建日志如下所示:
npm run build:prerender
> <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ddb3baf0a8b3b4abb8afaebcb1f0b9b8b0b29dedf3edf3ed" rel="noreferrer noopener nofollow">[email protected]</a> build:prerender C:\Users\thijs\Development\pokedex universal\angular-universal-pokedex
> npm run build:client-and-server-bundles && npm run compile:server && npm run generate:prerender
> <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a4cac389d1cacdd2c1d6d7c5c889c0c1c9cbe4948a948a94" rel="noreferrer noopener nofollow">[email protected]</a> build:client-and-server-bundles C:\Users\thijs\Development\pokedex universal\angular-universal-pokedex
> ng build --prod && ng run ng-universal-demo:server:production
Date: 2018-09-22T16:47:41.687Z
Hash: c49708f1ccb7e73e327a
Time: 8181ms
chunk {0} runtime.6afe30102d8fe7337431.js (runtime) 1.05 kB [entry] [rendered]
chunk {1} styles.34c57ab7888ec1573f9c.css (styles) 0 bytes [initial] [rendered]
chunk {2} polyfills.c174e4dc122f769bd68b.js (polyfills) 64.3 kB [initial] [rendered]
chunk {3} main.19481e4ceb7a5808fe78.js (main) 312 kB [initial] [rendered]
Date: 2018-09-22T16:47:50.816Z
Hash: ee7e30e1f9c277bb5cbf
Time: 5739ms
chunk {main} main.js (main) 38.2 kB [entry] [rendered]
> <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1e7079336b7077687b6c6d7f72337a7b73715e2e302e302e" rel="noreferrer noopener nofollow">[email protected]</a> compile:server C:\Users\thijs\Development\pokedex universal\angular-universal-pokedex
> tsc -p server.tsconfig.json
> <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6c020b411902051a091e1f0d0041080901032c5c425c425c" rel="noreferrer noopener nofollow">[email protected]</a> generate:prerender C:\Users\thijs\Development\pokedex universal\angular-universal-pokedex
> cd dist && node prerender
完成预渲染构建的唯一方法是删除网络请求。我想肯定还有什么东西在后台运行。我尝试将 Observable 切换为 Promise,但这并没有改变任何东西。我错过了什么?
最佳答案
有点晚了,但是如果有人遇到困难,这可能会有所帮助:
Similarly to the above section on waiting for macrotasks to complete, the flip-side is that the platform will not wait for microtasks to complete before finishing the render. In Angular Universal, we have patched the Angular HTTP client to turn it into a macrotask, to ensure that any needed HTTP requests complete for a given render. However, this type of patch may not be appropriate for all microtasks, and so it is recommended you use your best judgment on how to proceed. You can look at the code reference for how Universal wraps a task to turn it into a macrotask, or you can simply opt to change the server behavior of the given tasks.
基本上,如果您的 http 请求花费太长时间,预渲染就会挂起并且无法完成。 websocket 连接也是如此(firebase 在 angular-firebase 中使用 WS)。 另外,当我遇到这个问题时,终端中没有错误输出,这使得调试非常困难。 我建议如下:
- WS 连接仅在 CSR 上,将它们也包装在 if 语句中
- 对于 SSR 或静态预渲染,请使用 REST API 端点并确保不会收到任何超时错误。
关于Angular Universal 构建因 API 请求而卡在预渲染页面上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52458865/