NestJS: innovative universal module

Exploring the official Nest documentation on modules, I came across information about global modules and dynamic modules. It got me thinking, is there a way to combine these two patterns?

In my scenario, I have a dynamic config module:

export class ConfigModule {
    static forRoot(baseConfigPath: string): DynamicModule {
        const providers = [{ provide: 'Config', useValue: configFactory(baseConfigPath) }];

        return {
            module: ConfigModule,
            providers,
            exports: providers,
        };
    }
}

This setup allows the config module to adapt based on the provided base configuration path. When importing this module into the main app module, it looks like this:

@Module({
    imports: [ConfigModule.forRoot(path.resolve(__dirname, '../config'))],
    controllers: [AppController],
    providers: [AppService],
})
export class AppModule implements NestModule {}

which works well. However, I also have several other modules (child modules of the app module and siblings to the config module) where I need the same instance of the dynamic config module to be injectable. Is there a way to designate the dynamic ConfigModule as global or any other approach that could help achieve this?

I attempted to make the ConfigModule global using @Global, but it didn't yield the desired results. For a simplified example, I created a repository based on the nest starter template generated by nest new: https://github.com/DeX3/nest-di-playground

Answer №1

Recently I created a similar setup inspired by the structure found in nest/typeorm

@Module({})
export class CustomModule {
  static forRoot(rootNamespace: string): DynamicModule {
    return {
      module: CustomModule,
      imports: [CoreModule.forRoot(rootNamespace)],
    };
  }
}
@Global()
@Module({})
export class CoreModule {
  static forRoot(rootNamespace: string): DynamicModule {
    const namespaceProvider = {
      provide: CUSTOM_ROOT_NAMESPACE,
      useValue: rootNamespace,
    };

    const customServiceProvider: Provider = {
      provide: CustomService,
      useFactory: (namespace) => new CustomService(namespace).init(),
      inject: [CUSTOM_ROOT_NAMESPACE],
    };

    return {
      module: CoreModule,
      providers: [customServiceProvider, namespaceProvider],
      exports: [customServiceProvider, namespaceProvider],
    };
  }
}

In this setup, you will now have access to a global CustomService exported from the CoreModule. The export of the config is optional but can be useful for non-core modules with additional methods like my forFeature method (which is not shown here).

Answer №3

Although the exact reason is unclear to me, it seems that the usage of the @Global decorator does not achieve the desired effect when attempting to register a dynamic module as global. The necessary steps to make a dynamic module global are outlined in the NestJS documentation, which suggests adding a global field set to true within the configuration object returned by the static method responsible for handling the dynamic setup (in this case, forRoot):

export class ConfigModule {
    static forRoot(baseConfigPath: string): DynamicModule {
        const providers = [{ provide: 'Config', useValue: configFactory(baseConfigPath) }];

        return {
            global: true,
            module: ConfigModule,
            providers,
            exports: providers,
        };
    }
}

If I can uncover the reasoning behind the incompatibility of the decorator in this scenario, I will update this response with an explanation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to retrieving the previous URL in Angular 2 using Observables

Can someone help me retrieve my previous URL? Below is the code snippet I am working with: prev2() { Promise.resolve(this.router.events.filter(event => event instanceof NavigationEnd)). then(function(v){ console.log('Previous ' ...

Angular 2/4 - Saving User Object Information in the Front-End Instead of Repeatedly Contacting the Back-End Server

Is there a more efficient way to store and update the current user details in the frontend, without constantly making new HTTP GET requests to the backend every time a new component loads? The solution I came up with is a UserService class that handles se ...

The elements within the side navigation menu are not displaying correctly within the app component's HTML file

In my Models.ts file, I created a code that requires me to call the headers in side-nav.component.ts to app.component.html. However, when I try to call app.index.html by typing <side-nav><side-nav>, the component seems to be not specific. mode ...

Retrieving Angular observable data from a component with the assistance of the async pipe

Currently, I am in the process of refactoring some Angular code that previously involved subscribing to data from a service call. My goal now is to have the data returned from the service as an observable so that I can make use of the async pipe and avoid ...

Wondering how to leverage TypeScript, Next-redux-wrapper, and getServerSideProps in your project?

Transitioning from JavaScript to TypeScript for my codebase is proving to be quite challenging. // store.ts import { applyMiddleware, createStore, compose, Store } from "redux"; import createSagaMiddleware, { Task } from "redux-saga"; ...

Using TypeScript and Angular to modify CSS properties

I'm trying to figure out how to change the z-index CSS attribute of the <footer> element when the <select> is open in TypeScript (Angular 10). The current z-index value for the footer is set to 9998;, but I want it to be 0;. This adjustmen ...

Pattern matching to eliminate line breaks and tabs

Hey there, I'm working with a string: "BALCONI \n\n\t\t\t\t10-pack MixMax chocolade cakejes" and trying to tidy it up by removing unnecessary tabs and new lines. I attempted using .replace(/(\n\t)/g, '&apo ...

Is there a tool in Node.js to set up a new project, similar to the scaffolding feature in Visual Studio for C# projects

Is there a way to efficiently create a node.js project with TypeScript and Express, and embed an SPA client using React and Redux templates written in TypeScript as well? Is there a scaffolding tool available to streamline this process, similar to the ea ...

The function of getTime is not available for use

I assigned the date_work property to a Date data type. However, when I check the data type using the command console.log(typeof master.date_work), it shows as a string for some reason. This causes an error when using the getTime() function. How can I conve ...

Looking for a top-notch type definition management solution for Typescript, similar to tsd?

When considering the use of Typescript, the resolution of type definition files (*.d.ts) is essential. There are various systems for managing Typescript definition files, including: tsd typings @types It seems that tsd is the oldest system and the orig ...

Using curly braces in a fat arrow function can cause it to malfunction

Could someone provide insight into why this code snippet functions as intended: filteredArray = contacts.filter( (contact: Contact) => contact.name.toLowerCase().includes(term.toLowerCase()) ); while this variation does not: filteredArray = contact ...

Using the useRef validation can lead to errors when trying to reference the current value against an input

Currently, the code is functioning well but an error alert from Typescript needs to be addressed. A warning pops up regarding the use of ref.current.value. ERROR 1. TS18048: 'ref.current' is possibly 'undefined'. To tackle this issue, ...

Dealing with TypeScript and the Mongoose loadClass problem

Working with Mongoose's class schemas has been very beneficial for me. Incorporating TypeScript into my Node project has enhanced the development process. I made sure to refer to Mongoose the Typescript way...? in order to ensure that my Model align ...

Troubleshooting in Visual Studio Code using an npm script

Within my package.json file, I have defined some scripts as shown below: "scripts": { "build": "tsc -p tsconfig.json", "run": "node --experimental-specifier-resolution=node .", "start" ...

Why is NestJS Axios failing to retrieve data for me?

I'm facing a challenge while using the @nestjs/axios library based on the provided documentation. Making a simple API call seems to be causing me some trouble: const test = this.httpService.get('http://localhost:3001/test/testificate') The ...

What is the process for removing an image from Firebase storage using its URL?

Is there a way to delete an image from Firebase storage using its URL? I have noticed that when I remove an item (category) from the collection, the image associated with it remains in storage. This is the interface for category: export interface ICat ...

Creating a unique user interface for VSCode extension

Recently, I've delved into the world of developing extensions for Visual Studio. Unfortunately, my expertise in TypeScript and Visual Studio Code is quite limited. My goal is to create an extension that mirrors the functionality of activate-power-mod ...

What is the best way to set a value for a variable that is asynchronous by design?

I'm currently working on an Appium automation framework that is typescript based. The element locator strategy used in this framework is async due to the nature of the plugin I am using, which requires the use of await. However, I encountered some err ...

Increasing an ID number automatically using Javascript

I'm currently working on a functionality where a unique number is automatically generated whenever a new record is created. For instance, if I were to click "Create record" on a webpage, the number would auto-fill in the record ID field. Subsequently, ...

I'm puzzled as to why there is a blank space in the false element statements

Hey there! I'm noticing a blank space on the page, and when I inspect it, I see this bindings={ "ng-reflect-ng-if": "false" }. It seems like I am getting some blank cards displayed. Here is an image showing what I mean: https://i. ...