18

I know how to run a script from command line, using npm or npx ts-node [script.ts] just as stated here.

My question is different, now that I can run scripts, can I use services that are inside modules in my project? Let's say that I have this structure that it is normally called inside the project by other modules:

foo/foo.module.ts

import { HttpModule, Module } from '@nestjs/common';

@Module({
  providers: [FooService],
  imports: [HttpModule],
  exports: [FooService]
})
export class FooModule { }

foo/foo.service.ts

import { HttpService, Injectable } from '@nestjs/common';

@Injectable()
export class FooService {
    constructor(
        private readonly httpService: HttpService,
    ) {}

    bar() {
        console.log('do stuff');
    }
}

how can I call bar() inside the file /src/script.ts and then call npx ts-node script.ts keeping all the imports? Thank you.

2
  • 1
    have you check this package ? nestjs-command Commented Dec 11, 2020 at 11:47
  • @antoineso no, I'll give a try. Thanks Commented Dec 11, 2020 at 12:09

4 Answers 4

39

Let say you have an application module like this:

import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';

@Module({
  imports: [
    UsersModule,
  ],
})
export class ApplicationModule {}

And an UserService used by UsersModule in this way:

import { Module } from '@nestjs/common';

@Module({
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

And you want to create a command to create a new user directly from command line.

You can create a file named console.ts and put the following content:

import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './application.module';
import { UsersService } from './users/users.service';

async function bootstrap() {
  const application = await NestFactory.createApplicationContext(
    ApplicationModule,
  );

  const command = process.argv[2];

  switch (command) {
    case 'create-administrator-user':
      const usersService = application.get(UsersService);
      await usersService.create({
        username: 'administrator',
        password: 'password',
      });
      break;
    default:
      console.log('Command not found');
      process.exit(1);
  }

  await application.close();
  process.exit(0);
}

bootstrap();

And now in your package.json you can create the following script:

"execute": "ts-node ./src/console.ts"

Now you have the ability to call a custom command in a NestJS context like in the following example:

// Using Yarn
yarn execute create-administrator-user

// Using NPM
npm run execute create-administrator-user
Sign up to request clarification or add additional context in comments.

4 Comments

So, the only thing is that I was forced to convert all the imports of my project from src/[...] to relative paths because it wasn't able to resolve them. For the rest it works like a charm. Thank you
Just a thing that came up in my mind, if I have some nest cron jobs in the project and it happens that in the moment that I run the script it is also in the time of a cron job, is it executed or not?
I am using prisma and cache in the services's constructor , it return Cannot find module 'src/prisma.service' error.
This helped a lot thanks. In my cases, a lot of my services implemented OnModuleInit so I created a specific module called CLIModule with which you can create the application context, ie. ` const application = await NestFactory.createApplicationContext(CLIModule); ` - that way you don't have to load your whole app, and can just register the services in CLIModule that you need.
5

To add to the @Emanuele answer. If you have issue with src/[...] relative path, then instead of running the script with ts-node, try run with the following "node -r ts-node/register -r tsconfig-paths/register path_to_script"

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
3

Generally, to use a service you'll need to instantiate the service class. Nest normally does this as a part of NestFactory.create. What you could do is something like this:

async function bootstrap() {
  const app = await NestFactory.createApplicationContext(FooModule);
  const service = app.get<FooService>(FooService); // this sets the type of service and gets the instance
  service.bar();
  await app.close();
}

Now all you would need is to compile the files and run them using node as you normally would a server.

Comments

1

To resolve the relative path issue, add this to the ts-config

{
  "ts-node": {
    // Do not forget to `npm i -D tsconfig-paths`
    "require": ["tsconfig-paths/register"]
  }
}

Source: https://typestrong.org/ts-node/docs/paths/

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.