platformBrowserDynamic with Angular Universal
In the previous article I described how the platformBrowserDynamic
method can be provided with runtime configuration in client-side Angular applications.
Now we'll adapt the method so it also works with Angular Universal and server-side rendering (SSR) and even server-side generation (SSG).
Strictly speaking this process is simply about providing configuration to the AppServerModule
(and in turn AppModule
). As far as SSR/SSG goes this is a necessary step, because the clue is in the name: platformBrowserDynamic
- the method is specifically for browser i.e. client-side, execution.
With that in mind, all we actually need is to provide configuration for server-side on bootstrap, then when the application is hydrated on the client, the same configuration can be loaded via platformBrowserDynamic
.
So, after installing Angular Universal (the process is described here), the first thing we need to do is ensure that configuration is available to the bootstrapping process in app.server.module.ts
.
import { APP_CONFIG, AppConfig } from './app.config';
@NgModule({
imports: [
AppModule,
ServerModule,
],
providers: [
{
provide: APP_CONFIG,
useFactory: (config: AppConfig) => {
config = require("../assets/config.json");
console.debug(`Node server loaded app config for prerendering. Env: ${config.env}`);
return config;
}
}
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
When we run this
npm run dev:ssr
We can see the output logged from the app.component.ts
:
Node server loaded app config for prerendering. Env: Dev
AppComponent constructor: Dev
NgxLogger browser level configured by runtime configuration: 'INFO'
2024-01-16T21:02:25.349Z INFO [app.component.ts:31:17] Info output
2024-01-16T21:02:25.602Z LOG [app.component.ts:32:17] Log output
2024-01-16T21:02:25.789Z WARN [app.component.ts:33:17] Warn output
2024-01-16T21:02:25.968Z ERROR [app.component.ts:34:17] Error output
2024-01-16T21:02:26.121Z FATAL [app.component.ts:35:17] Fatal output
AppComponent onInit
{
env: 'Dev',
apiBaseUrl: 'https://collectionapi.metmuseum.org/public/collection/v1',
activeTheme: 'solution-b',
logger: { browserLogLevel: 2, serverLogLevel: 7, serverLoggingUrl: null },
buildRef: '1.0.0.0B-DEV'
}
Recall the default configuration in the LoggerConfig
class:
export class LoggerConfig {
browserLogLevel: NgxLoggerLevel = NgxLoggerLevel.TRACE;
serverLogLevel: NgxLoggerLevel = NgxLoggerLevel.TRACE;
serverLoggingUrl: string | undefined;
}
Now consider the following lines from app.component.ts
:
console.debug(`NgxLogger browser level configured by runtime configuration: '${NgxLoggerLevel[this.logger.level]}'`);
this.logger.trace(`Trace output`);
this.logger.debug(`Debug output`);
this.logger.info(`Info output`);
this.logger.log(`Log output`);
this.logger.warn(`Warn output`);
this.logger.error(`Error output`);
this.logger.fatal(`Fatal output`);
Notice how the TRACE and DEBUG lines are not shown in the output?
It's clear that the value of browserLevel
is being updated to INFO, and is in fact the value set in assets/config.json
, thus preventing output of TRACE and DEBUG, and proving that runtime configuration is working:
{
"env": "Dev",
"apiBaseUrl": "https://collectionapi.metmuseum.org/public/collection/v1",
"activeTheme": "solution-b",
"logger": {
"browserLogLevel": 2,
"serverLogLevel": 7,
"serverLoggingUrl": null
},
"buildRef": "1.0.0.0B-DEV"
}
This concludes my series of articles about Angular runtime configuration. I hope it is helpful.
Happy coding!