《Angular Universal(SSR)的重复加载问题》一文中曾经介绍过Angular v14.x版本中出现的重复加载(flickering)问题,并给出了解决方案。然而,升级到Angular v15.x后,重复加载问题再次出现了。

诡异的是,实际上,state在服务端是正常调用并在页面缓存了的。如下:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
console.log(1, storedResponse); console.log(2, this.state.get(key, null)); console.log(3, this.state.toJson()); console.log(4, JSON.stringify(this.state));
console.log(1, storedResponse); console.log(2, this.state.get(key, null)); console.log(3, this.state.toJson()); console.log(4, JSON.stringify(this.state));

以上代码中,第一行输出是能够正常看到完整的值的,然而,第2-4行的输出却是空白的。因此,怀疑是在存值和取值的过程中二者不同步所导致的,或者,取值逻辑发生了变化。

但,知道了问题,却找不到解决方案。┓( ´∀` )┏

此时摆在面前的选择只有2个:

  1. 回退到Angular v14.x
  2. or,找到治本的适配Angular v15.x的解决方案。

继续在网上溜达,在GitHubissue中找到这么一条回复:

The current version of Angular uses destructive hydration which causes flickering, but the workarounds mentioned in the comments works well to address this issue. You can say its a limitation of the framework, but this is how it works in the current version of Angular.

可以确定是Angular v15.x的一些“破坏性更新”导致的此问题,因此回头去翻了下release notes,找到这么两篇:TransferStateStandalone migration,其中,ServerTransferStateModule显示为DEPRECATED状态,而renderApplication则显示为开发者预览状态,似乎都不太靠谱。

最后,只能死马当活马医,迁移到Standalone模式。

按照上述链接的文档执行以下命令3次,分别在给出的选项中选择不同的操作:

bashCopy code
  • 1
ng generate @angular/core:standalone
ng generate @angular/core:standalone

然后,启动服务,根据给出的报错提示逐一修改,完成之后再次启动服务,显示熟悉的页面且控制台无报错时,即表示成功。

然而,执行npm run dev:ssr切换到SSR模式时,却报错:

error NG6009: The `AppComponent` class is a standalone component, which can not be used in the `@NgModule.bootstrap` array. Use the `bootstrapApplication` function for bootstrap instead.

报错信息已经很清楚了,将AppComponent改回原来的方式即可,然后重新创建app.module.ts文件,内容如下:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
@NgModule({ declarations: [AppComponent], imports: [ BrowserModule.withServerTransition({ appId: 'ifuyun' }), TransferHttpCacheModule, AppRoutingModule, HttpClientModule, FormsModule, ReactiveFormsModule, BrowserAnimationsModule, CommonModule, HeaderComponent, FooterComponent, SiderComponent, ToolboxComponent, BackTopComponent ], providers: [ httpInterceptorProviders, { provide: APP_BASE_HREF, useValue: env.host }, provideHttpClient(withInterceptorsFromDi()), provideAnimations() ], bootstrap: [AppComponent] })
@NgModule({ declarations: [AppComponent], imports: [ BrowserModule.withServerTransition({ appId: 'ifuyun' }), TransferHttpCacheModule, AppRoutingModule, HttpClientModule, FormsModule, ReactiveFormsModule, BrowserAnimationsModule, CommonModule, HeaderComponent, FooterComponent, SiderComponent, ToolboxComponent, BackTopComponent ], providers: [ httpInterceptorProviders, { provide: APP_BASE_HREF, useValue: env.host }, provideHttpClient(withInterceptorsFromDi()), provideAnimations() ], bootstrap: [AppComponent] })

再次启动服务,完美![]~( ̄▽ ̄)~*

此时,再去测试SSR环境下的重复加载问题,发现也“被”解决了……╰(*°▽°*)╯

然而,执行npm outdated时却突然发现,Angular已经悄悄升级到v15.2.1了,怀疑是不是之前的v15.2.0版本的问题,而不是Standalone Component所致?

回退代码到迁移Standalone Component之前,并且更新Angularv15.2.1,再次测试,果然!

再去看GitHub上的版本提交记录,似乎得到了印证。

看来闹了一出乌龙……But,不管怎么说,问题解决了便是最好的……[]~( ̄▽ ̄)~*