14

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.

Ripper346
  • 662
  • 7
  • 22

4 Answers4

34

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
Emanuele Scarabattoli
  • 4,103
  • 1
  • 12
  • 21
  • 1
    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 – Ripper346 Jan 06 '21 at 11:34
  • 1
    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? – Ripper346 Jan 06 '21 at 11:45
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"

  • 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](/help/how-to-answer). – Community Aug 11 '22 at 04:47
2

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.

Mr. T
  • 12,795
  • 5
  • 39
  • 47
Jay McDoniel
  • 57,339
  • 7
  • 135
  • 147
0

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/