Angular Universal with Standalone Component

Martin Choraine - Dec 17 '22 - - Dev Community

With the arrival of Standalone Component with Angular 15, it is now possible to do without @NgModules entirely. This opens the door to new possibilities.

It is now possible to bootstrap an Angular application by providing an entry point component with a list of providers in the main.ts :

bootstrapApplication(AppComponent, {
  providers: [
    provideAnimations(),
    provideRouter(routes)
  ]
})
Enter fullscreen mode Exit fullscreen mode

However, with this new approach, it is not yet possible to simply take advantage of the server side rendering (SSR) with Angular Universal because the function ngExpressEngine only takes a module parameter and not a component:

import express from 'express';
import { ngExpressEngine } from '@nguniversal/express-engine';

const app = express();

// Set the engine
app.engine(
  'html',
  // Bootstrap and render NgModule with express adapter for `@angular/platform-server`
  ngExpressEngine({
    // Take a module but we would like to provide component
    bootstrap: ServerAppModule
  }),
);

app.set('view engine', 'html');

app.get('/**/*', (req: Request, res: Response) => {
  res.render('../dist/index', {
    req,
    res,
  });
});
Enter fullscreen mode Exit fullscreen mode

On the other hand it is possible to use manually the render function provided by @angular/platform-server.
This forces us to redo the work done by Angular Universal inside ngExpressEngine but it's the only possibility while waiting for the support of standalone component :

import express from 'express';
import type { Request, Response } from 'express';
import * as fs from 'fs';
import { renderApplication } from '@angular/platform-server'

const app = express();

app.engine('html', async (path, options, callback) => {
    const document = fs.readFileSync(path, 'utf-8')
    const { req } = { ...options } as {req: Request, res: Response};

    // Bootstrap and render a Standalone Component 
    const html = await renderApplication(AppComponent, {
      appId: 'server-app',
      document: document,
      url: `${req.baseUrl}${req.url}`,
      providers: [
        provideRouter(routes),
      ]
    });
    callback(null, html)
});
app.set('view engine', 'html');

app.get('/**/*', (req: Request, res: Response) => {
  res.render('../dist/index', {
    req,
    res,
  });
});
Enter fullscreen mode Exit fullscreen mode

Thanks to the function renderApplication, it is possible to bootstrap an Angular component and render it on the server side while waiting for the full support of Standalone Component in Angular Universal with the provided function ngExpressEngine.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .