Server-side Rendering
Prerequisites
An Angular project with server-side rendering enabled.
Overview
Orbit supports server-side rendering in two ways:
- It uses Angular's
HttpClientunder the hood which automatically supports server-side rendering as explained here. - It uses Angular's
TransferStateto transfer Apollo Client's cache from server to client.
signal.query and signal.query.once use PendingTasks so SSR waits for execution, variable changes, refetch and fetchMore. Termination releases pending tasks. Polling after the first execution, mutations and subscriptions do not hold application stability.
With custom scalars, cache.extract() serializes values for transfer and cache.restore() parses them again. Configure the same scalars on the server and browser caches.
Setup
Setup SSR based on your angular project's style.
- Standalone
- Module
Update appConfig
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideGraphQL } from './graphql/graphql.provider';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { provideClientHydration, withHttpTransferCacheOptions } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideGraphQL(),
provideHttpClient(withFetch()),
provideClientHydration(withHttpTransferCacheOptions({
includePostRequests: true
}))
]
};
Passing includePostRequests to withHttpTransferCacheOptions is required for default GraphQL setup where POST requests are used.
Update provideGraphQL
import { isPlatformBrowser } from '@angular/common';
import { EnvironmentProviders, PLATFORM_ID, TransferState, inject, makeEnvironmentProviders, makeStateKey, provideEnvironmentInitializer } from '@angular/core';
import { Apollo, InMemoryCache, provideApollo, withApolloOptions } from '@apollo-orbit/angular';
import { HttpLinkFactory, withHttpLink } from '@apollo-orbit/angular/http';
import { NormalizedCacheObject } from '@apollo/client';
const APOLLO_STATE_KEY = makeStateKey<NormalizedCacheObject>('APOLLO_STATE');
export function provideGraphQL(): EnvironmentProviders {
return makeEnvironmentProviders([
provideApollo(
withApolloOptions(() => {
const httpLinkFactory = inject(HttpLinkFactory);
const httpLink = httpLinkFactory.create({ uri: 'http://localhost:4000/graphql' });
const platformId = inject<object>(PLATFORM_ID);
const ssrOptions = isPlatformBrowser(platformId)
? { ssrForceFetchDelay: 200 }
: { ssrMode: true };
return {
link: httpLink,
cache: new InMemoryCache(),
...ssrOptions
};
}),
withHttpLink()
),
provideEnvironmentInitializer(() => {
const apollo = inject(Apollo);
const transferState = inject(TransferState);
const platformId = inject(PLATFORM_ID);
if (isPlatformBrowser(platformId)) {
const state = transferState.get(APOLLO_STATE_KEY, undefined);
if (state) apollo.cache.restore(state);
} else {
transferState.onSerialize(APOLLO_STATE_KEY, () => apollo.cache.extract());
}
})
]);
}
Update AppModule
import { provideHttpClient, withFetch } from '@angular/common/http';
import { provideClientHydration, withHttpTransferCacheOptions } from '@angular/platform-browser';
@NgModule({
...
providers: [
provideHttpClient(withFetch()),
provideClientHydration(withHttpTransferCacheOptions({
includePostRequests: true
}))
]
})
export class AppModule { }
Passing includePostRequests to withHttpTransferCacheOptions is required for default GraphQL setup where POST requests are used.
Update GraphQLModule
import { isPlatformBrowser } from '@angular/common';
import { Inject, NgModule, PLATFORM_ID, TransferState, inject, makeStateKey } from '@angular/core';
import { Apollo, InMemoryCache, provideApollo, withApolloOptions } from '@apollo-orbit/angular';
import { HttpLinkFactory, withHttpLink } from '@apollo-orbit/angular/http';
import { NormalizedCacheObject } from '@apollo/client';
const APOLLO_STATE_KEY = makeStateKey<NormalizedCacheObject>('APOLLO_STATE');
@NgModule({
providers: [
provideApollo(
withApolloOptions(() => {
const httpLinkFactory = inject(HttpLinkFactory);
const httpLink = httpLinkFactory.create({ uri: 'http://localhost:4000/graphql' });
const platformId = inject(PLATFORM_ID);
const ssrOptions = isPlatformBrowser(platformId)
? { ssrForceFetchDelay: 200 }
: { ssrMode: true };
return {
link: httpLink,
cache: new InMemoryCache(),
...ssrOptions
};
}),
withHttpLink()
)
]
})
export class GraphQLModule {
public constructor(
apollo: Apollo,
transferState: TransferState,
@Inject(PLATFORM_ID) platformId: { [key: string]: any }
) {
if (isPlatformBrowser(platformId)) {
const state = transferState.get(APOLLO_STATE_KEY, undefined);
if (state) apollo.cache.restore(state);
} else {
transferState.onSerialize(APOLLO_STATE_KEY, () => apollo.cache.extract());
}
}
}