You can use glob package to dynamically find modules then use NestJs dynamic module feature to load them dynamically.
Suppose all of your worker files are stored in a directory named workers and with extention .worker.ts:
@Module({})
export class WorkerModule {
static forRootAsync(): DynamicModule {
return {
module: WorkerModule ,
imports: [WorkerCoreModule.forRootAsync()],
};
}
}
export class WorkerCoreModule {
static async forRootAsync(): Promise<DynamicModule> {
// Feel free to change path if your structure is different
const workersPath = glob.sync('src/**/workers/*.worker.ts');
const workersRelativePathWithoutExt = modelsPath
// Replace src, because you are probably running the code
// from dist folder
.map((path) => path.replace('src/', './../'))
.map((path) => path.replace('.ts', ''));
const workerProviders: Provider<any>[] = [];
const importedModules = await Promise.all(
workersRelativePathWithoutExt.map((path) => import(path)),
);
importedModules.forEach((modules) => {
// Might be different if you are using default export instead
const worker = modules[Object.keys(modules)[0]];
workerProviders.push({
provide: worker.name,
useValue: worker,
});
});
return {
module: WorkerCoreModule,
providers: [...workerProviders],
// You can omit exports if providers are meant to be used
// only in this module
exports: [...workerProviders],
};
}
}
Now suppose you have a simple worker class with path src/anyModule/workers/simple-worker.ts, you can use it like this:
class WrokersService {
constructor(@Inject('SimpleWorker') simpleWroker: SimpleWorker) {}
.
.
.
}
If you want to omit @Inject('SimpleWorker') and automatically inject modules like NestJs services then you need to make these changes to WorkerCoreModule:
workerProviders.push({
provide: worker,
});
However in order for this to work you need to be sure that your workers classes are decorated with @injectable().