angular: provideClientHydration does not wait for a waterfall of requests for caching
Which @angular/* package(s) are the source of the bug?
common
Is this a regression?
No
Description
So the way that our application works, we kind of have a waterfall of requests due to needing to visit multiple sources for some information:
- A) go to CMS to get list of campaigns for guest users
- B) go to API to fetch information about those campaigns
- C) go back to CMS to fetch the content for the bonuses associated with those campaigns (interpolation purposes etc)
So you end up with requests like so:
A.....
B.....
C......... (fully ready)
Obviously we have caching within our CDN so it’s not TOO slow, but when delivering a response from Universal SSR you kind of get this: appReady: false… true… false… true.
We’ve been using TransferState to cache things like so:
return cmsCache.has(CACHE_KEY) ? cmsCache.get(CACHE_KEY) : cmsService.fetchSomething(...);
We sent that data to the browser and re-hydrated like so:
export const CACHE_STATE_KEY = makeStateKey<any>('api-cache.state');
export const apiCache = new Map<ApiCacheKey | string, any>();
...
// SSR hydration and dehydration of the cache
if (transferState.hasKey(CACHE_STATE_KEY)) {
const state = transferState.get(CACHE_STATE_KEY, {});
for (const key of Object.keys(state)) {
apiCache.set(key, state[key]);
}
} else {
transferState.onSerialize(CACHE_STATE_KEY, () => Object.fromEntries(apiCache.entries()));
apiCache.clear();
}
Now since Angular 16 there’s experimental DOM Hydration and automatic HTTP Caching I thought great, I can delete most of my custom code and just use that.
After testing it, it mostly looked good but I noticed that there are a few API requests being made in both server and client. If I add logging to those, I can see them being made in both places but they never get added to TransferState. After some digging I found the culprits:
https://github.com/angular/universal/blob/main/modules/common/src/transfer_http.ts#L82-L89
For caching and transferState to be used, the application needs to do everything before the first ready state and can’t be: unready/ready/unready/ready (as more requests/pending tasks are discovered).
Is there any reaason for it to work like this? It can’t be correct because Universal still doesn’t return the response until all of that is 100% settled anyway, so shouldn’t the caching/transferstate also work the same way?
In my opinion, either:
- The logic for when universal should stop what it’s doing and deliver the response, should be the same as when cache and TransferState stop recording
- Cache and TransferState shouldn’t stop recording until Universal is fully ready and delivers the response
I’m assuming there’s something I’m missing here for why it works the way it does.
Please provide a link to a minimal reproduction of the bug
No response
Please provide the exception or error you saw
No response
Please provide the environment you discovered this bug in (run ng version
)
Angular CLI: 16.2.1
Node: 16.14.0
Package Manager: yarn 1.22.17
OS: darwin arm64
Angular: 16.2.3
... animations, common, compiler, compiler-cli, core, forms
... localize, platform-browser, platform-browser-dynamic
... platform-server, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1602.1
@angular-devkit/build-angular 16.2.1
@angular-devkit/core 16.2.1
@angular-devkit/schematics 16.2.1
@angular/cdk 16.2.2
@angular/cli 16.2.1
@angular/flex-layout 15.0.0-beta.42
@angular/material 16.2.2
@nguniversal/builders 16.2.0
@nguniversal/express-engine 16.2.0
@schematics/angular 16.2.1
rxjs 7.8.1
typescript 5.0.4
webpack 5.88.2
zone.js 0.13.2
Anything else?
As it stands, the only way for me proceed is to either:
- Copy/Paste all logic and provide it myself using the private APIs
- Hack my application to force all 3x requests (A, B, C) to be in a single observable and wait for it, instead of letting universal discover when it’s ready based on what appears in the DOM and what is newly discovered.
About this issue
- Original URL
- State: closed
- Created 10 months ago
- Comments: 20 (8 by maintainers)
@intellix, is the request a
GET
?, the HTTP Cache transfer only cachesGET
andHEAD
requests.