Getting Started with building reusable packages for NestJS. (Step-By-Step)

For any node js developer NPM registry is like a weapon for a gladiator but against the gladiator that knows what his weapon was created with, it isn’t so necessary to know background details when we run npm install!

But that is not the end of the story, sometimes we need to directly interact with the NPM registry in order to publish our reusable packages for private usage across teams or even as an open source idea, so this time you need to act like a gladiator and enjoy publishing your package for the first time.

There are several articles about how to build and publish our reusable NestJS packages into the NPM registry around the net but I have tried to provide a quickest start as I can.

Setting up package

Run npm init to initialize an empty npm package. The terminal will ask for the details of the project such as name and description so fill them as your desire according to your idea. Then just replace.

Install nestJS dependencies

npm install @nestjs/common rxjs
npm install -d @types/node rimraf typescript

Edit package.json file

After installing the dependencies of NestJS package go to your package.json file and add/edit following lines

"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"build": "rimraf dist && tsc",
"prepublish": "npm run build"
},

Typescript config

Create tsconfig.json in your application root directory and add the following code to it

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "target": "es2017",
    "module": "commonjs",
    "lib": ["es2017", "es7", "es6"],
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "noImplicitAny": false,
    "strictNullChecks": false,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
}

Scaffolding

Now it is time to scaffold our project , create a src folder and we will add our nest logic in this folder.

After all add an index.ts which will responsible to export our modules and services as well

here I am going to create a module and service for our example :

Project  
└─── src  
│   └───index.ts  
│   └─── …..  
└─── package.json  
└─── tsconfig.json

Add our code

In this example we will use dynamic modules and useValue method to create our package’s module. NestJS providers: useValue, useClass and useFactory

Providers in NestJS are one of the most important parts when it comes to writing fully configurable modules in both…

First we are going to add our module register options DTO, so create a folder named dto and add a file named gladiator-options.dto.ts on it.

Second, we’ll define a GladiatorModule to provide and export a GladiatorService. GladiatorModule is the host module for GladiatorService.

import { Module, DynamicModule } from '@nestjs/common';
import { GladiatorService } from './gladiator.service';
import { GladiatorOptionsDto } from './dto/gladiator-options.dto';

@Module({})
export class GladiatorModule {
  static register(options: GladiatorOptionsDto) : DynamicModule {
    return {
      module: GladiatorModule,
      providers: [
        {
          provide: 'GLADIATOR_OPTIONS',
          useValue: options,
        },
        GladiatorService
      ],
      exports: [GladiatorService],
    }
  }
}

Now it is time to create our gladiator service

import { Injectable, Inject } from '@nestjs/common';
import { GladiatorOptionsDto } from './dto/gladiator-options.dto';

@Injectable()
export class GladiatorService {

	constructor(
		@Inject('GLADIATOR_OPTIONS') 
		private gladiatorOptions: GladiatorOptionsDto
	) 
	{}

	async IsUsingSword(): Promise<boolean> {
		return this.gladiatorOptions.weapon == 'Sword'
	}
}

The final scaffolding will look like above:

GladiatorProject  
└─── src  
│   └───index.ts  
│   └─── gladiator.module.ts  
│   └─── gladiator.service.ts  
│   └─── dto  
│     └─── gladiator-options.ts  
└─── package.json  
└─── tsconfig.json

Export Application

To make our code accessible for other applications we need to export our code, so add the following code in index.ts to make it possible.

export * from './gladiator.module.ts';
export * from './gladiator.service.ts';

Build The Gladiator

Now it is time to build our project by

npm install  
npm run build

This will compile our code into the dist folder. Now we can use this package in our application by running this command :

npm i PATH_TO_OUR_PACKAGE

We should now register our gladiator package’s module into our main application module like this :

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GladiatorModule } from 'gladiator'

@Module({
  imports: [GladiatorModule.register({
    weapon: "Sword",
    name: "Nikolaus",
    Level : 19
  })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

After registering module we can inject GladiatorService from gladiator package into our main application’s service or controller :

import { Injectable } from '@nestjs/common';
import { GladiatorService } from 'gladiator';

@Injectable()
export class AppService {
  constructor(private readonly gladiatorService: GladiatorService) 
  {}

  async getGladiator(): Promise<boolean> {
    return await this.gladiatorService.IsUsingSword()
  }
}

Calling this.gladiatorService.IsUsingSword() should return true as we have passed weapon: “Sword” in module registration

The package is ready now you can enjoy by publishing it :D

Publish Package

The are so many tutorials about publish package into npm registry , so here I am going to explain them in nutshell

To complete this step, you’ll need a free account at www.npmjs.com. If you don’t have one, go to the signup page to get one.

  • Set a name for your package

you should chose a unique name for you package or just use scoped names. scoped names are useful for unique namespace, for example if any one publishes gladiator package, who ever publishes first the package will own the gladiator name.

with scoped name you can name your package like @romans/gladiatorand any one that attends to install it will use : npm i @romans/gladiator

  • Edit package.json

package.json is like an identity to your reusable library, so open up it and change the values like name, version and author name, you can also give a link into package git repository.

if you need more information about how to versioning your package in publishing/republishing go through this semantic versioning (“semver”) and it is best practice for npm packages.

  • Publish Package

Go to https://www.npmjs.com/signup and register your account then run npm login in console. in the root of your package you can now run npm run publish to make a birthday for your new born package ;)