nestjs-console
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 nestjs-console
yarn add 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 { MyAppModule } from './my.application.module';
BootstrapConsole.init({ module: MyAppModule })
.then(({ app, boot }) => {
boot();
})
.catch(e => console.log('Error', e));
Import the 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...
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.myCommand.bind(this));
const parentCommand = this.consoleService.subCommands(
cli,
'new',
'A command to create an item'
);
parentCommand
.command('file <name>')
.description('Create a file')
.action((name: string) => {
console.log(`Creating a file named ${name} at path`);
process.exit(0);
});
parentCommand
.command('directory <name>')
.description('Create a directory')
.action((name: string) => {
console.log(`Creating a direcotry named ${name}`);
process.exit(0);
});
}
list(directory: string): void | Promise<void> {
const spin = this.consoleService.createSpinner();
spin.start();
console.log(`Listing files at path named ${directory}`);
spin.stop();
process.exit(0);
}
}
Add scripts in your package.json (if you want to 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
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
Create a Custom ConsoleService
You can create any number of custom ConsoleService and any nummber of entrypoints (BootstrapConsole).
The Commander provider can be injected using the decorators @InjectCommander()
.
The decorator can be imported from nestjs-console `import { InjectCommander } from 'nestjs-console';
Imagine we want to set the version of the cli for all commands, create a custom class then import it as a provider in your nest module.
import { Injectable } from '@nestjs/common';
import {
InjectCommander,
PatchedCommander,
ConsoleService
} from 'nestjs-console';
export class CustomConsole extends ConsoleService {
constructor(@InjectCommander() protected readonly cli: Command) {
super(cli);
}
init() {
this.cli.version('1.0.1', '-v, --version');
super.init();
}
}