
nestjs-console is a module that provide a cli. A ready to use service class for your modules that exposes methods to register commands and sub commands using the npm package commander
Why
The nestjs framework is missing a cli to access the application context.
Common use case : Headless application, cront task, export data, etc...
nestjs-console provide a way to bind cli command and subcommands to providers's methods.
How it works
The console service works as a standalone process, like the classic entry point, and will initialize a NestApplicationContext (headless) instead a NestApplication.
The console service will be accesible inside the container.
- Bootstrap (entry point e.g console.ts) is invoked by cli.
- Init a headless nest app
- Any module inside the app can create command and subcommands using nestjs-console with commander
- nestjs-console invoke commander
- commander will do the rest.
npm install commander nestjs-console
yarn add commander nestjs-console
Create a cli endpoint
Create a file at root next to your entry point named console.ts
Import your app module or any module you want to be loaded. Usually this is your main nestjs module.
You can create as many entry points as you want.
You can also extend the BootstrapConsole
class to suit your needs.
import { BootstrapConsole } from 'nestjs-console';
import { MyModule } from './module';
BootstrapConsole.init({ module: MyModule }).then(({ app, boot }) => {
boot();
});
Import the ConsoleModule in your main module
import { Module } from '@nestjs/common';
import { ConsoleModule } from 'nestjs-console';
import { MyService } from './service';
@Module({
imports: [
ConsoleModule
],
providers: [MyService]
exports: [MyService]
})
export class MyModule {}
You can now inject the ConsoleService inside any nestjs providers, controllers...
There are 2 ways of registering providers methods to the console.
Using @decorators (>=v1.1 and >=v2 for multi dimensions) or using the ConsoleService.
Example of cli stack
Cli -> Command_A -> [
Command_A1 -> execution,
Command_A2 -> execution
]
-> Command_B -> [
Command_B1 -> execution,
Command_B2 -> [
Command_B2_a -> execution
Command_B2_b -> [... more sub commands ...]
]
]
-> Command_C -> execution
Api
As a simple example, we will define a cli with 2 commands (new and list), one of the command (new) will have 2 sub commands (directory and file)
Cli -> list -> -> execution,
-> new -> [
directory -> execution,
file -> execution
]
How to use Decorators
Registering methods using class decorators is very easy.
Nestjs providers that are decorated with @Console will be scanned and each member method that is decorated with @Command will be registered on the cli.
import { Console, Command, createSpinner } from 'nestjs-console';
@Console()
export class MyService {
@Command({
command: 'list <directory>',
description: 'List content of a directory'
})
async listContent(directory: string): void | Promise<void> {
const spin = createSpinner();
spin.start(`Listing files in directory ${directory}`);
const files = await new Promise(done =>
setTimeout(() => done(['fileA', 'fileB']), 1000)
);
spin.succeed('Listing done');
console.log(JSON.stringify(files));
process.exit(0);
}
}
Register a command with sub commands
By default, the @Console will tell the module to register all decorated methods at root of the cli.
Example of Usage: [options] [command]
You can name your provider to use it as a parent command container.
This is usefull when you have a lot of commands and you want to group them as sub command. (git style)
To achieve this, you have to group your methods into class.
You have to pass options to the @Console decorator to configure your provider as a parent command.
Decorated methods of the providers will be registered as a sub command instead of beeing registered at root.
@Console({
name: 'new',
description: 'A command to create an item'
})
export class MyNewService {
@Command({
command: 'file <name>',
description: 'Create a file'
})
async createFile(name: string): void | Promise<void> {
console.log(`Creating a file named ${name}`);
process.exit(0);
}
@Command({
command: 'directory <name>',
description: 'Create a directory'
})
async createDirectory(name: string): void | Promise<void> {
console.log(`Creating a directory named ${name}`);
process.exit(0);
}
}
Example of Usage: new [options] [command]
How to use the ConsoleService
Registering methods using the ConsoleService is more flexible than decorators.
When you use the ConsoleService, you simply bind your methods to the cli manually.
This is usefull if you need to create the cli or a part of the cli at runtime.
This way you can also create mutliple commands ans sub commands from the same class.
import { Injectable } from '@nestjs/common';
import { ConsoleService } from 'nestjs-console';
@Injectable()
export class MyService {
constructor(private readonly consoleService: ConsoleService) {
const cli = this.consoleService.getCli();
cli.command('list <directory>')
.description('List content of a directory')
.action(this.listContent);
const parentCommand = this.consoleService.subCommands(
cli,
'new',
'A command to create an item'
);
parentCommand
.command('file <name>')
.description('Create a file')
.action(this.createFile);
parentCommand
.command('directory <name>')
.description('Create a directory')
.action(this.createDirectory);
}
listContent = async (directory: string): void | Promise<void> => {
console.log(`Listing files in directory ${directory}`);
process.exit(0);
};
createFile = async (name: string): void | Promise<void> => {
console.log(`Creating a file named ${name}`);
process.exit(0);
};
createDirectory = async (name: string): void | Promise<void> => {
console.log(`Creating a directory named ${name}`);
process.exit(0);
};
}
Add scripts in your package.json (if you want to use them)
{
"scripts": {
"console:dev": "ts-node -r tsconfig-paths/register src/console.ts",
"console": "node lib/console.js"
}
}
Usage
Call the cli (production)
node lib/console.js --help
npm run console -- --help
yarn console --help
Call the cli from sources (dev)
ts-node -r tsconfig-paths/register src/console.ts --help
npm run console:dev -- --help
yarn console:dev --help
Example of Response
Usage: console [options] [command]
Options:
-h, --help output usage information
Commands:
list <directory> List content of a directory
new A command to create an item