On the angular application I am working on there is a noticeable flicker if the browser simulates a mid-tier mobile. It seems that angular is not doing Dom rehydration when the application changes from Server to Browser, it's fully replacing the DOM.
However, this effect should be noticeable if the page doesn't have changes or doesn't pull in new data. Therefor, to reduce the effects I am trying to insure api calls on the server are not repeated.
The code base is pretty large so I am not sure I will place anything that seems relevant here but if there is anything missing please ask in the comments.
My App Server Module
is:
import { NgModule } from '@angular/core';
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server';
import { BrowserModule } from '@angular/platform-browser';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
BrowserModule.withServerTransition({ appId: 'api-example' }),
ServerModule,
ServerTransferStateModule,
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
And my App Module:
@NgModule({
imports: [
ConfigModule,
TransferHttpCacheModule,
AppRoutingModule,
HttpClientModule,
BrowserAnimationsModule,
I18nModule,
NgbModule,
SwiperModule,
ToastNoAnimationModule,
NotificationModule,
ToastrModule.forRoot({
enableHtml: true,
closeButton: true,
positionClass: 'toast-top-right',
toastClass: 'ngx-toastr',
preventDuplicates: true,
}),
GoogleAnalyticsGTagModule,
ProfileEditModalModule,
NgcCookieConsentModule.forRoot(cookieConfig),
FaqPageModule,
CriticalApplicationErrorModule,
],
declarations: [AppComponent],
providers: [
...
{
provide: LocationStrategy,
useClass: PathLocationStrategy,
},
{
provide: HTTP_INTERCEPTORS,
useClass: HttpInterceptorService,
multi: true,
},
],
bootstrap: [AppComponent],
})
export class AppModule {}
It is worth noting here that I am not using a separate App Browser Module
and that I also not importing BrowserModule.withServerTransition({ appId: 'api-example'})
and BrowserTransferStateModule
because when I do that, for example following the guide listed in the last link, it still does an api call and it when the page reloads on the browser it looses its styles (CSS). Furthermore, I can print the transferred state stored in the browser at the moment of transitioning between server and browser.
I am also delaying the bootstrap in my main.ts
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.log(err));
});
Then I use an HTTP Interceptor
:
public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (request.method !== 'GET') {
return next.handle(request);
}
const key: StateKey<string> = makeStateKey<string>(request.url);
if (isPlatformServer(this.platformId)) {
return next.handle(request).pipe(
tap((event) => {
this.transferState.set(key, (event as HttpResponse<any>).body);
console.log(this.transferState.get(key, null) // Prints transferred stated item
})
);
} else {
const storedResponse = this.transferState.get<any>(key, null);
console.log(storedResponse) // Prints null
console.log(this.transferState) // Prints complete State
console.log(this.transferState.get(key, null)) // Prints null
if (storedResponse) {
const response = new HttpResponse({ body: storedResponse, status: 200 });
this.transferState.remove(key);
return of(response);
} else {
return next.handle(request);
}
}
}
So that's where i'm starting to get confused, logging the transferState
in its entirety works but not if I try to use transferState.get()
why is that?
Here is the console.log
from the browser related to this.transferState
:
It's the same thing in the Page Component
.
Also if I try to use JSON.parse(this.transferState.toJson())
it will only print the first stored object, which has additional caching since it's the i18n
data.
Never the less the i18n
data also does not get transferred from server to browser if caching is disabled, else it gets pulled from cache.
On the Page component data is being pull with a api service:
preparePageData(): void {
this.server.getPageData().subscribe((res: any) => {
this.pageData = res['data-details'];
}
}
and is called on ngOnInit
the service itself if a http get
getPageDate() {
return this.http.get('http://example.com/getPageData')
}
What could be causing this issue?
Is there any other information that would be useful to solve this issue?
Is it normal that all my styles get removed is if I add BrowserModule.withServerTransition({ appId: 'api-example'})
to my app module or to a separate App Browser Module
?
If it could be an external renderer causing an issue please advise me as what to look for.
Here are some possibly relevant links I have found:
Angular Universal SSR TransferState only first page data available Since I am using SSR and he is using static pages this is does not apply.
Angular Universal TransferState not loading on Client His solution is already implemented in my codebase.
Angular - TransferState - page is loading twice (flickering) Similar issue but has not solution available. I am also aware Rehydration is not a thing in angular, (hopefully will be in the future).
Transfer State with Angular Tutorial on Ganatan.com Attempted using this implementation but it did not fix the issue. It still fetches the data from the server, and additionally removed some styles from the client app but not from the server app.
I have done more research and read the docs but that seems to be the most relevant information I found.