Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 24, 2022 04:28 pm GMT

Fullstack JS with Angular Universal and NestJS (Nx flavor)

TL;DR

  • Scaffold a Nx workspace with an Angular and NestJS app
nx-workspace@latest --preset angular-nest
  • Install @nxarch/ng-nest and use the init schematic to generate the necessary project setup
yarn add @nxarch/ng-nest@nxarch/ng-nest:init --ssrApp=my-angular-project --serverApp=my-nestjs-project
  • Use yarn dev:server to start the app

Side note:
If you're using relative paths for your server side API calls via the Angular HttpClient you might encounter an error as it doesn't prepend the base path.

There are multiple ways to solve this:

  • Use an HttpInterceptor that prepends the base url only on the server
  • or update the PlatformConfig to prepend relative paths with the base path
  • or just replace relative paths in your HttpClient calls with absolute paths
hello$ = this.http.get('http://localhost:4200/api/hello')

Angular and NestJS share a lot of common concepts and design patterns. You can even go as far as sharing services if you keep them framework agnostic. As a developer being familiar with either of the frameworks you will probably feel comfortable pretty quickly.

But why would you use Angular Universal?
There are a lot of use cases for server side rendered applications such as:

  • Improved SEO performance
  • Improved load performance of your application
  • Shortened time to interactive and first contentful paint. Your users will thank you.

Angular Universal itself isnt a new framework youd have to learn. Itll just enhance your apps capabilities as it will also run on the server. Eventually it will send the rendered html to the client.

Here are some (non-exhaustive) things you can do on the server within your Angular application when Angular Universal is used.

  • Accessing the request object in your Angular business logic
  • Caching responses
  • Issue requests from localhost to localhost (fast)
  • Getting access to session values in your Angular app

In order to use Angular Universal with a simple express server you can just use

ng add @nguniversal/express-engine

But youre here to read about how to setup Angular Universal with a NestJS server.

There is a great library created by the NestJS team that helps integrating an Angular Universal app with a NestJS app. It will compile the NestJS app together with the Angular SSR app in one bundle.

This article will show how to setup a Nx workspace with a compiled output of three separate bundles -> one for the server, one for the ssr app and one for the client side bundle.

This yields the advantage that we only need to recompile those bundles that are affected by code changes. Hence, it will decrease compile time significantly in bigger code bases.

One possible dist folder structure looks like this.

 dist    server   |    main.js    ssr-app   |    main.js    ui-app   |    main.js   |    index.html...

We also want to use browser-sync during local development in order to proxy our server and enable live refreshes whenever the NestJS app or the Angular app is rebuild.

Lets explore what the scaffolded projects look like after weve used the init generator

yarn add @nxarch/ng-nest@nxarch/ng-nest:init --ssrApp=my-angular-project --serverApp=my-nestjs-project

The scaffolded Projects

Now there are three app module files

The AppBrowserModule, the AppSsrModule and the server/AppModule.

// server/app.module.ts@Module({  imports: [    AngularUniversalModule.forRoot({      bootstrap: join(process.cwd(), 'dist/apps/ui/ssr/main.js'),      viewsPath: join(process.cwd(), 'dist/apps/ui/browser'),    }),  ],  controllers: [AppController],  providers: [AppService],})export class AppModule { }

The server AppModule will import the AngularUniversalModule which is responsible for setting up server-side-rendering routes and delegating requests to the ngExpressEngine.

For more options see the nxarch/nest-nguniversal repository. You can configure options such as using custom endpoints for render routes, asynchronous cache storages or the render path.

If you keep the default wildcard render path make sure to prefix the api paths. We do this in your main.ts file.

// server/main.tsapp.setGlobalPrefix("/api");

The AppSsrModule is only loaded and instantiated on the server. It uses the AppBrowserModule in order to render our html document. The AppBrowserModule is the main Angular module thats also used on the client side.

// ui/app.ssr.module.ts@NgModule({  imports: [    ServerModule,    AppBrowserModule  ],  bootstrap: [AppComponent],})export class AppSsrModule { }

main.ssr.ts

The path of the compiled output of this file is passed via the bootstrap option of the AngularUniversalModule options. We want to avoid to use any Angular specific dependencies in our NestJS bundle. Thats why we need to re-export the ngExpressEngine here.

// ui/main.ssr.tsimport'@angular/platform-server/init';import{enableProdMode}from'@angular/core';import{environment}from'./environments/environment';if(environment.production){enableProdMode();}export{AppSsrModule}from'./app/app.ssr.module';export{ngExpressEngine}from'@nguniversal/express-engine';

server/project.json

There are probably two additions worth mentioning.

The server project.json needs some external dependencies to be set in order to tell Webpack not to bundle those packages. This will prevent warnings and errors.

"targets": {        ...    "build": {        "executor": "@nrwl/webpack:webpack",        "outputs": [          "{options.outputPath}"        ],        "options": {          "target": "node",          "compiler": "tsc",          "outputPath": "dist/apps/server",          "main": "apps/server/src/main.ts",          "tsConfig": "apps/server/tsconfig.app.json",          "assets": [            "apps/server/src/assets"          ],          "externalDependencies": [            "@nestjs/common",            "@nestjs/core",            "express",            "@nestjs/microservices",            "@nestjs/microservices/microservices-module",            "@nestjs/websockets",            "@nestjs/websockets/socket-module",            "cache-manager"          ],          "optimization": false        }    },    ...}

Also theres another target added that can be used to serve the application during local development.

"targets": {    ...    "serve-ssr": {    "executor": "@nxarch/ng-nest:build",    "options": {      "browserTarget": "ui:build:development",      "ssrTarget": "ui:ssr:development",      "serveTarget": "api:serve:development"    }  },  ...}

ui/project.json

In the ui project.json one additional target for the server side rendered app has been added.

"targets": {    "ssr": {      "executor": "@angular-devkit/build-angular:server",      "options": {        "outputPath": "dist/apps/ui/ssr",        "main": "apps/ui/src/main.ssr.ts",        "tsConfig": "apps/ui/tsconfig.ssr.json",        "inlineStyleLanguage": "scss",        "outputHashing": "none",        "optimization": false      },      "configurations": {...},      "defaultConfiguration": "production"    },    ...}

package.json

Last but not least notice theres one more script in our scripts object which we can use to start the dev server.

"dev:server": "nx serve-ssr api"

@nxarch/ng-nest tries to make integrating and setting up an Angular Universal app and a NestJS app quick, simple and more productive.

If you enjoy using it don't forget to star .


Original Link: https://dev.to/yannickboetzkes/fullstack-js-with-angular-universal-and-nestjs-nx-flavor-46k5

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To