Skip to content

Backend boilerplate and libraries for NestJS utilizing @nrwl/nx. [mirror: gitlab]

Notifications You must be signed in to change notification settings

diamirio/backend-nx-skeleton

Repository files navigation

Web und Söhne - Logo

Web & Söhne is Austria's leading expert in programming and implementing complex and large web projects.

@webundsoehne/nx-skeleton

A set of schematics and tools that provides the basis for fast template scaffolding base on the @nrwl/nx.


Packages

brownie - @webundsoehne/brownie

A CLI interface for creating @nrwl/nx workspaces and Docker templates from scratch.

Read more...

deep-merge - @webundsoehne/deep-merge

Helper tools for deep merge objects.

Read more...

eslint-config - @webundsoehne/eslint-config

eslint configuration for variety of environments.

Read more...

nestjs-graphql-typeorm-dataloader - @webundsoehne/nestjs-graphql-typeorm-dataloader

Easily implement data-loader to Typeorm projects via decorating the DTOs or entities instead of creating custom ones.

Read more...

nestjs-keycloak - @webundsoehne/nestjs-keycloak

This package includes Keycloak integration for NestJS.

Read more...

nestjs-keycloak-seeder - @webundsoehne/nestjs-keycloak-seeder

This package extends the @webundsoehne/nestjs-keycloak to have the seeding functionality to initiate and manage a Keycloak instance.

Read more...

nestjs-seeder - @webundsoehne/nestjs-seeder

A generic seeder to inject services in to and initiate a application programmatically.

Read more...

nestjs-util - @webundsoehne/nestjs-util

Utility package for @nestjs.

Read more...

nestjs-util-graphql - @webundsoehne/nestjs-util-graphql

Utility package for @nestjs for GraphQL applications.

Read more...

nestjs-util-microservices - @webundsoehne/nestjs-util-microservices

Utility package for @nestjs for microservices applications.

Read more...

nestjs-util-restful - @webundsoehne/nestjs-util-restful

Utility package for @nestjs for restful applications.

Read more...

nx-builders - @webundsoehne/nx-builders

Custom builders for @nrwl/nx.

Read more...

nx-nest - @webundsoehne/nx-nest

A skeleton that can be generated through @nrwl/nx schematics.

Read more...

nx-tools - @webundsoehne/nx-tools

Various tools that can be used while developing new @nrwl/nx schematics.

Read more...

nx-workspace - @webundsoehne/nx-workspace

Schematic for scaffolding @nrwl/nx workspace.

Read more...

patch-package - @webundsoehne/patch-package

A wrapper around the patch-package library, which can automatically apply predefined patches or create new ones.

Read more...

ts-utility-types - @webundsoehne/ts-utility-types

Some basic utility types for Typescript.

Read more...

Further Development

Developing schematics for @nrwl/nx is not really possible in one-hit wonder due to templating and all the options that can be added to the schematics itself.

Using the scripts link all the packages to your global link directory.

You can use the -d or --develop flag in brownie commands workspace and nx to put schematics in development mode. This will do some additional tasks to ensure that it will work in a development environment. For dependencies, it will only install the linked versions.

You can use the --debug flag for brownie, which will activate the debug log level for both the schematics that it runs and the brownie itself.

Local Development Steps

This is a brief walkthrough, you can find more information in the following sections.

  • Install the dependencies with yarn.
  • Run the docker-compose stack. All the packages will be built locally.
  • Link all the packages to your global link folder. You can use yarn run scripts:link to link them all at once.
  • Create a mock NX workspace with brownie. You should definitely use -d flag to put brownie and some schematics in to development mode and can always use --debug flag for more output.
  • You can then just run brownie as you wish to test things out. But always remember to put it in to development mode with -d flag.

Warnings

  • If you have a new or updated NPM module added to one of the packages, you might need to install it again from root. Because yarn workspaces and resolutions field do not play nice. But do not worry since the installation will only fix the resolutions and not take much of time.
  • Since it was taking a lots of resources to use Typescript compiler on this repository, it is converted to a tool called tsup based on esbuild and rollup. esbuild is very strict with import type and export type statements where isolatedModules should be used. eslint will do its best to convert the code to use import/export type statements but sometimes since these types can be used in constructor it will leave them alone since they can also be dependency injection. This cannot be true for the cases with interfaces or types, but it still acts this way, so some caution is needed.

Publishing Process

This is a brief walkthrough, you can find more information in the following sections.

Repository has git commit hook to ensure the commit format.

  • fix -> will publish new patch version for the package that the commits apply to
  • feat -> will publish new minor version for the package that the commits apply to
  • perf with breaking changes selected -> will publish new major version for the package that the commits apply to

semantic-release decides to publish the packages or not depending on whether the new commits since the last known tag has been made to the given package.

So it is better to commit often for little things to ensure that your final version matches what you expect.

To give an example to these lets say we will do changes in 2 packages, nx-nest and nx-tools.

nx-nest will have just a bug fix. So after changing the related files, we can just commit with fix to ensure that it will publish a patch version. nx-tools will have a new feature that is not breaking. So again after changing the related files, we can just commit with feat to ensure that it will publish a minor version.

So even though we will publish them at the same time, they will get individually versioned depending on what commits have been made to them.

The other options that are inside the git commit hook, which uses a interactive selection for commitizen is:

  • scope -> you can scope your changes to a package, so when you are searching through commits it's easier to find them. We now have no convention for this.
  • long description -> will append the description to the issues replied and the commit itself
  • resolves issues -> will automatically respond to related issues and close them if specified
  • breaking changes -> breaking changes is required to publish a major version, it will also append it in the changelogs
  • skip ci -> if you are sure that the ci does not have to be run after this commit and everything lints and builds fine and there is no publishing needed you can select this to save ci resources

The other commit types like refactor, build, ci, style does not affect versioning in any way. But it helps to identify the changes made to the repository.

Versioning of Individual Packages

This repository uses semantic-release to versioning of the indivudal packages. Since semantic-release is not intended for multiple packages at the same time it uses multi-semantic-release on top of it.

What it does is:

  • Goes through all the packages analyzes the commits and generate changelogs and decide next version for each. It will scope the changes inside the folder of the package.
  • Writes cross-dependency versions as pinned to avoid dependency problems to each package.
  • Release packages that have relevant commits on it filtering the commits to their own folder.
  • Closes issues depending on the commits, comments them if they have been released in which version.

semantic-release relies on conventional-commits commit format to decide through these changes. This is enforced through a git prepare-commit-msg hook to create a interactive menu to help you through the process.

Docker Setup

This repository includes a Docker-Compose stack for automatically compiling SERVICES variable defined. It will first compile the RUN_IN_BAND packages sequentially and after that it will compile everything else defined in the SERVICES variable in parallel.

The image uses s6-overlay to monitor the crashes and will run dev:start for each package unless overridden with the SERVICE variable. Since these are intended to be published packages to NPM, it is a better approach to use tsc-watch to create a structure as if the package is published.

CLI-Script

./cli script can be used to access in to Docker container directly. These commands can be interactive that requires keyboard or not. But on the base Docker image, which is based on Alpine-Linux there is no bash, so for interactive session ash should be run.

  • ./cli ws ${COMMAND}, ./cli . ${COMMAND}, ./cli root ${COMMAND} -> Will run the command in the workspace root.
  • ./cli ${PACKAGE_NAME} ${COMMAND} -> Will look for package name in packages/* folder and execute the command in that root.
  • ./cli all ${COMMAND} -> Will run the command for every package.
  • ./cli lerna ${COMMAND} -> Will run a lerna command for every package.
  • ./cli ls -> Will list the available packages.

Scripts

There are a couple of scripts in the scripts folder:

  • ./scripts/link-packages.sh [link | unlink] This can also be accessed through: yarn run scripts:link yarn run scripts:unlink

    Will link all the packages inside the packages folder.

  • ./link-packages-to-workspace.sh [link | unlink] \${PWD_OF_MOCK_PROJECT} This can also be accessed through: yarn run scripts:workspace:link yarn run scripts:workspace:unlink

    Copy this script to somewhere else for easily creating a new empty workspace in the designated folder to test out the schematics.

Package Manager

yarn must be used due to its support of resolutions field in the package.json as well as this repository being configured for yarn workspaces.

@angular scoped packages have inconsistencies between similar versions due to utilizing different versioned sub-packages. In the development process you can get over this with fixing the package versions utilizing resolutions in the root package.json.