Angular Universal SSR TransferState仅第一页数据可用

时间:2018-06-20 23:00:18

标签: angular angular-universal static-generator angular-transfer-state

我已经使用TransferState API创建了ApiService来缓存来自wordpress的数据:

get(url, id) {
  const key = makeStateKey(id);
  if (this.transferState.hasKey(key)) {
    const item = this.transferState.get(key, null);
    return of(item);
  } else {
    return this.http.get(url).pipe(
      map(items => {
        this.transferState.set(key, items);
        return items;
      })
    );
  }
}

然后我用它来获取数据:

this.apiService.get(environment.url + '/wp-json/wp/v2/posts').subscribe(res => {
  this.posts = res;
});

这很好用,并且在运行时,第一次调用该API,然后总是缓存第二次。

静态生成时:

/index.html

<script id="my-app-state" type="application/json">
  <!-- top level page data -->
</script>

/posts/index.html

<script id="my-app-state" type="application/json">
  <!-- top level page data -->
  <!-- posts data -->
</script>

据我了解,原因是因为您位于一个真正的静态index.html文件中,其中包含,然后在导航时,所有后续页面均未加载.html文件,它们实际上是html5路由/ posts。

问题是,如何获得TransferState缓存以使用静态生成的/posts/index.html文件中的?

可能的解决方案:

  • 预先加载所有数据(可以,但是每个页面1.1MB)
  • 将数据放入可以由ajax加载的静态文件中
  • 禁用html5路由,以便用户使用正确的脚本标记访问静态.html文件
  • 一些未记录的角度解决方案?

静态生成的演示:

https://kmturley.github.io/angular-universal-wordpress-cms/frontend/dist/browser/

静态生成的源:

https://github.com/kmturley/angular-universal-wordpress-cms/tree/gh-pages/frontend/dist/browser

完整的代码库在这里:

https://github.com/kmturley/angular-universal-wordpress-cms

1 个答案:

答案 0 :(得分:1)

我设法使用一种解决方法解决了这个问题。我创建了一个新的TransferState JSON,该JSON以JSON形式返回数据,该数据可以在多个页面之间共享:

export function serializeTransferStateFactory(
    doc: Document, appId: string, transferStore: TransferState) {
  return () => {
    return JSON.parse(transferStore.toJson());
  };
}

https://github.com/kmturley/angular-universal-google-apis/blob/master/src/app/shared/transfer_state_json.ts

,然后修改renderModuleFactory以分别返回html和数据:

const callbacks = moduleRef.injector.get(BEFORE_APP_SERIALIZED, null);
let data = null;
if (callbacks) {
  for (const callback of callbacks) {
    try {
      data = callback();
    } catch (e) {
      // Ignore exceptions.
      console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e);
    }
  }
}
const output = platformState.renderToString();
platform.destroy();
return {
  output: output,
  data: data
};

https://github.com/kmturley/angular-universal-google-apis/blob/master/utils.ts#L53

以便可以将其保存到prerender.ts中的.json文件:

previousRender = previousRender.then(_ => renderModuleFactory(AppServerModuleNgFactory, {
  document: index,
  url: route,
  extraProviders: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
})).then((res: { output: string, data: object }) => {
  // write html file
  writeFileSync(join(fullPath, 'index.html'), res.output);

  // write json files from TransferState objects
  Object.keys(res.data).forEach(item => {
    writeFileSync(join(jsonPath, item + '.json'), JSON.stringify(res.data[item]));
  });
});

https://github.com/kmturley/angular-universal-google-apis/blob/master/prerender.ts#L53

您可以在此处使用json查看演示静态版本:

https://kmturley.github.io/angular-universal-google-apis

以及此处的源代码:

https://github.com/kmturley/angular-universal-google-apis