【问题标题】:Angular Universal TransferState not loading on ClientAngular Universal TransferState 未加载到客户端
【发布时间】:2018-05-17 03:22:11
【问题描述】:

我正在尝试让TransferState 在我的 Angular Universal v5 应用程序中工作。经过大量调试,我意识到,在服务器上,TransferState 似乎正在工作,因为响应包含一个包含适当序列化状态 (TransferState source) 的 <script id=APP_ID></script> 标记。

由于某种原因,浏览器应用程序并未使用该状态进行初始化。如果我将测试状态硬编码到我的应用程序的 index.html 文件中(通过复制和粘贴),那么我的浏览器应用程序 已成功使用浏览器状态初始化。我不确定出了什么问题。任何想法都非常感谢!

我唯一的猜测是,当我在 Chrome 的检查器中查看我的应用程序加载时,似乎大部分元素一次加载,然后在另一个勾选中出现 <script id=APP_ID></script>。这似乎意味着脚本标签正在以某种方式在浏览器端生成/处理,即使我已经检查了服务器的响应并且它包含脚本标签。但是,如果脚本标签正在客户端进行某种处理,则可能TransferState 在该处理完成之前被初始化,这就是我的应用程序没有接收到状态的原因。再次感谢任何想法!

以下是相关代码:

app.module.ts

import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { environment } from '../environments/environment';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';    
import { AppRoutingModule } from './app-routing.module';
import { GraphQLModule } from './graphql.module';

@NgModule({
  imports: [
    BrowserModule.withServerTransition({ appId: 'service-work-coordination' }),
    BrowserTransferStateModule,
    AppRoutingModule,
    GraphQLModule,
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
})
export class AppModule {}

app.server.module.ts

import { NgModule } from '@angular/core';
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';

import { AppModule } from './app.module';
import { AppComponent } from './app.component';

@NgModule({
  imports: [
    AppModule,
    ServerModule,
    ServerTransferStateModule,
    ModuleMapLoaderModule, // <-- *Important* to have lazy-loaded routes work
  ],
  // Since the bootstrapped component is not inherited from your
  // imported AppModule, it needs to be repeated here.
  bootstrap: [AppComponent],
})
export class AppServerModule {}

graphql.module.ts

import { NgModule, APP_ID, PLATFORM_ID, Inject } from '@angular/core';
import { TransferState, makeStateKey } from '@angular/platform-browser';
import { HttpClientModule, HttpHeaders } from '@angular/common/http';
import { environment } from '../environments/environment';

// Apollo
import { ApolloModule, Apollo } from 'apollo-angular';
import { HttpLinkModule, HttpLink, HttpLinkHandler } from 'apollo-angular-link-http';
import { InMemoryCache, NormalizedCache, NormalizedCacheObject } from 'apollo-cache-inmemory';
import { setContext } from 'apollo-link-context';
import { isPlatformBrowser } from '@angular/common';

const uri = environment.uris.api.graphql;

const STATE_KEY = makeStateKey<any>('apollo.state');

@NgModule({
  imports: [
    HttpClientModule,
    ApolloModule,
    HttpLinkModule,
  ],
  exports: [
    HttpClientModule,
    ApolloModule,
    HttpLinkModule,
  ]
})
export class GraphQLModule {
  private cache: InMemoryCache;
  private link: HttpLinkHandler;

  constructor(
    private apollo: Apollo,
    private transferState: TransferState,
    private httpLink: HttpLink,
    @Inject(PLATFORM_ID) private platformId: any,
  ) {
    this.cache = new InMemoryCache();
    this.link = this.httpLink.create({ uri });

    console.log('transferState: ', this.transferState);

    const isBrowser = this.transferState.hasKey<NormalizedCache>(STATE_KEY);

    if (isPlatformBrowser(this.platformId)) {
      this.apollo.create({
        link: this.link,
        cache: this.cache,
        ssrForceFetchDelay: 100,
      });

      this.onBrowser();      
    } else {      
      this.apollo.create({
        link: this.link,
        cache: this.cache,
        ssrMode: true,
      });

      this.onServer();      
    }
  }

  onServer(): void {
    this.transferState.onSerialize(STATE_KEY, () => this.cache.extract());
  }

  onBrowser(): void {
    const state = this.transferState.get<NormalizedCacheObject | null>(STATE_KEY, null);

    if (state) {
      this.cache.restore(state);      
    }
  }
}

简化的服务器响应

<html>
<head>...app code...</head>
<body>
<app-root>...app code...</app-root>
<script type="text/javascript" src="inline.6ce41075b82d3dba433b.bundle.js"></script>
<script type="text/javascript" src="polyfills.37cc021a2888e752595b.bundle.js"></script>
<script type="text/javascript" src="main.1efdc21cec25daa396d1.bundle.js"></script>
<script id="service-work-coordination-state" type="application/json">{&q;apollo.state&q;:{&q;$ROOT_QUERY.person({\&q;id\&q;:\&q;074a9421-53bb-44c7-8afe-43130c723bd9\&q;})&q;:{&q;firstName&q;:&q;John&q;,&q;middleName&q;:null,&q;lastName&q;:&q;Carroll&q;,&q;primaryEmailAddress&q;:&q;:`EmailAddress::Person::Current`:`EmailAddress::Person`:`EmailAddress::Current`:`EmailAddress`:`Current` {uuid: &s;f0c4896a-27da-410b-84d3-3d66e1507a7e&s;}&q;,&q;__typename&q;:&q;Person&q;},&q;ROOT_QUERY&q;:{&q;person({\&q;id\&q;:\&q;074a9421-53bb-44c7-8afe-43130c723bd9\&q;})&q;:{&q;type&q;:&q;id&q;,&q;id&q;:&q;$ROOT_QUERY.person({\&q;id\&q;:\&q;074a9421-53bb-44c7-8afe-43130c723bd9\&q;})&q;,&q;generated&q;:true}}}}</script>
</body>
</html>

【问题讨论】:

    标签: angular apollo angular-universal angular5


    【解决方案1】:

    Uggg...所以事实证明我遇到了一个已知的(谢天谢地)bug in Angular。客户端上的TransferState 正在在脚本标签以某种方式被处理/加载时被启动。为了解决这个问题,目前您需要延迟 Angular 客户端应用程序的引导。

    更新main.ts

    document.addEventListener('DOMContentLoaded', () => {
      platformBrowserDynamic()
      .bootstrapModule(AppModule)
    });
    

    【讨论】:

    • 非常感谢,您拯救了我的一天!我想知道为什么 Angular 团队没有在他们的官方文档 (angular.io/api/platform-browser/TransferState) 中包含这些信息。
    • @kimamula hu,你说的很对!当我创建这个问题时,TransferState 是新的,而 Angular 存储库中的相关问题是新的。我只是假设他们会立即解决问题,并且不需要文档更新。那是我的一个错误。我刚刚创建了一个PR to update the docs。我确实想知道为什么您(以及在过去一年中没有其他人查看此问题)没有创建 PR 来更新文档。我猜答案就是为什么 Angular 团队也没有。
    • 就此问题,我收到的关于这个问题的持续 +1 应该告诉我它仍未解决,我应该做一个文档 PR。到处都是失败。
    • 我使用 CLI 向我的应用程序添加了 SSR 支持,但它有这个问题,我花了大约 3 天时间才意识到问题所在。感谢这个有用的答案
    • @John 我做了,我还审查并添加了评论以支持 PR。
    猜你喜欢
    • 2020-11-21
    • 2023-02-20
    • 2018-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    • 1970-01-01
    相关资源
    最近更新 更多