Table of contents
Open Table of contents
TLDR
When using Angular SSR with different origins between server and client (e.g. your-internal-endpoint.internal vs your-public-exposed-endpoint.com), HTTP state is lost during hydration. The HTTP_TRANSFER_CACHE_ORIGIN_MAP
token lets you map these origins, preserving HTTP cache state and preventing duplicate requests, therefore you don’t have a flickering effect when you handling different states, like loading.
Configure it in your app.config.ts to maintain state consistency across server and client environment.
The problem
When it comes to hydration process, you can set up very promising feature, that makes your app not performing additional requests when hydration is enabled. By that we will avoid also some additional flickering.
export const appConfig: ApplicationConfig = {
providers: [provideClientHydration(withHttpTransferCacheOptions({}))],
};
In some scenarios, it will work, but in major use cases it won’t work as expected and we will still have double request on our page. Why? Because we have different endpoint on server and on client in most cases!
Understanding API Endpoint Differences
- we want to achieve rendering content as fast as possible from server, so we want to bypass additional layer of networking from reverse proxy that normally protects our endpoints (e.g Cloudflare) and hit our service directly
- we develop locally and client is hitting by example localhost:3000 and SSR http://node-backend:3000
- we don’t use external services that are only available to hit via public endpoint (endpoints are same on both environments)
When hydration mechanism starts, it checks if the endpoints are same, if they’re not, it will perform the request anyway during hydration. That can cause us aditional flickering because application state may change during making another call - for example from loading to loaded.
What’s the fix for that?
Actually, it’s not popular token (I found it accidentally during watching some docs in IDE), but IMHO it’s yet must have for most of the SSR apps. Usage of this token:
export const appConfigServer: ApplicationConfig = {
providers: [
{
provide: HTTP_TRANSFER_CACHE_ORIGIN_MAP,
useValue: {
"http://internal-host.internal": "https://mycoolapi.com",
},
},
],
};
We basically map ours server available host to client’s available domain and that’s it.
⚠️ Remember to provide it only in your app server config, when there will be provider on client, Angular will throw an error.
❗ Common mistake
A lot of times our public and internal endpoint fragments aren’t same. We can have some another prefix in our domains, or we’re using gateway service.
For example:
On the backend you can have
http://internal-host.internal/api/endpoint
and as public endpoint https://mycoolapi.com/gateway/endpoint
As you see there’s a mismatch in fragment - /api/endpoint !== /gateway/endpoint. Unfortunately, it will cause another call to API since fragment after mapped domains must be identical and in this case cache won’t work. Maybe in the future we will be able to solve this problem. There’s open issue on Github that points out this problem - https://github.com/angular/angular/issues/57080.
Conclusion
By implementing the HTTP_TRANSFER_CACHE_ORIGIN_MAP, you can maintain smooth hydration despite different server and client endpoints. This solution ensures your Angular SSR application remains fast, efficient, and flicker-free. 🚀