Skip to content

Commit 2942461

Browse files
committed
feat(modules): added readme documentation
1 parent a61a0ac commit 2942461

2 files changed

Lines changed: 119 additions & 1 deletion

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ The various packages are managed using Yarn Workspaces and Lerna and published u
3030
#### [RabbitMQ - @levelup-nestjs/rabbitmq](packages/rabbitmq/README.md)
3131

3232
- A NestJS native module for RabbitMQ that supports both RPC and Publish/Subscribe messaging patterns
33+
34+
#### [Modules - @levelup-nestjs/modules](packages/modules/README.md)
35+
36+
- A NestJS Dynamic Module helper. Useful for configuring once and importing anywhere else.

packages/modules/README.md

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,118 @@
66
<img alt="license" src="https://img.shields.io/npm/l/@levelup-nestjs/modules.svg">
77
</p>
88

9-
Reusable utilities for working with NestJS Modules
9+
## Description
10+
11+
This module provides a reusable, minimal boilerplate method for creating [dynamic module](https://docs.nestjs.com/fundamentals/dynamic-modules) that can be configured synchronously or asynchronously once and then re-used anywhere.
12+
13+
Along with reusable configured dynamic modules, this module provides a way to reduce the majority of dynamic module boilerplate, allowing you to stop working with creating your own `forRoot/forRootAsync` methods and getting on to developing your top tier application.
14+
15+
If you haven't worked with creating dynamic modules yet, take a look [at this article](https://dev.to/nestjs/advanced-nestjs-how-to-build-completely-dynamic-nestjs-modules-1370) by [John Biundo](https://github.com/johnbiundo) to help get used to the topic.
16+
17+
## Motivation
18+
19+
Every now and again you'll come across a use case where you will want to configure a dynamic module and re-use that configuration elsewhere, without having to re-declare the configuration. The immediate example that comes to mind is a non-global `ConfigModule` or a `DatabaseModule` that implements a core module behind the scenes. In either case, you would want to be able to set up your configuration in your root module (`AppModule`) and import the configured module anywhere else in your application. With creating a re-usable dynamic module, we are essentially achieving the same outcome as using `@Global()` without polluting the module's scope. This is a nice alternative if you want to be a little more verbose in where all of your dependencies are coming from.
20+
21+
In addition to the reusability of the module, this package removes the need to write the same boilerplate over and over again. This saves time, errors, and sanity from the developer to allow a better experience while creating a new application.
22+
23+
## Usage
24+
25+
### Installation
26+
27+
To install, run
28+
29+
```sh
30+
npm install @levelup-nestjs/modules
31+
```
32+
33+
or
34+
35+
```sh
36+
yarn add @levelup-nestjs/modules
37+
```
38+
39+
and wait for the installation to finish.
40+
41+
### Dynamic Module Creation
42+
43+
Creating a new dynamic module is now easier than ever, all that is needed is the module's name, the options that are to be provided for the module, and a constant string, symbol, or token that is to be used for providing the options through injection. Following the idea of a non-global `ConfigModule`, you can do something like the following:
44+
45+
```ts
46+
import { MakeConfigurableDynamicRootModule } from '@levelup-nestjs/modules';
47+
import { Module } from '@nestjs/common';
48+
import { CONFIG_MODULE_OPTIONS } from './config.constants'; // the constant string/symbol/token
49+
import { ConfigModuleOptions } from './config.options'; // the options to provide to the service
50+
import { ConfigModule } from './config.service'; // the service to be provided to the rest of the server
51+
52+
@Module({
53+
providers: [ConfigService],
54+
exports: [ConfigService]
55+
})
56+
export class ConfigModule extends MakeConfigurableDynamicRootModule<
57+
ConfigModule,
58+
ConfigModuleOptions
59+
>(CONFIG_MODULE_OPTIONS) {}
60+
```
61+
62+
And just like that, you've created a Dynamic module. Now in your root module you can configure it like so:
63+
64+
```ts
65+
@Module({
66+
imports: [ConfigModule.forRoot(ConfigModule, synchronousConfigModuleOptions)]
67+
})
68+
export class AppModule {}
69+
```
70+
71+
or asynchronously
72+
73+
```ts
74+
@Module({
75+
imports: [ConfigModule.forRootAsync(ConfigModule, asyncConfigModuleOptions)]
76+
})
77+
export class AppModule {}
78+
```
79+
80+
It is important to note that you **must** provide the name of the module class as the first argument of the `forRoot` and `forRootAsync` methods to make sure the library can configure your dynamic module correctly. This is a Type Safe method and will cause the server to fail to start up if a constructor is not passed in.
81+
82+
### Re-Using Dynamic Modules
83+
84+
For re-using the configured dynamic modules, the module provides a static method called `externallyConfigured` that takes in the module class and a number, the milliseconds to wait for asynchronously configured modules. This number does need to be provided, but can usually be set to `0` unless there are asynchronous calls (http calls to other systems or retrieving data from a database) being made. To use the dynamic module in another module, simply import it with the call to `externallyConfigured` like so:
85+
86+
```ts
87+
@Module({
88+
imports: [ConfigModule.externallyConfigured(ConfigModule, 0)]
89+
})
90+
export class ConfigModuleDependentModule {}
91+
```
92+
93+
#### One Other Option
94+
95+
if you don't like the idea of calling `externallyConfigured` every time, you can create a `static` property on the Dynamic Module and set it equal to the `externallyConfigured` method. Take the above `ConfigModule` example:
96+
97+
```ts
98+
import { MakeConfigurableDynamicRootModule } from '@levelup-nestjs/modules';
99+
import { Module } from '@nestjs/common';
100+
import { CONFIG_MODULE_OPTIONS } from './config.constants'; // the constant string/symbol/token
101+
import { ConfigModuleOptions } from './config.options'; // the options to provide to the service
102+
import { ConfigModule } from './config.service'; // the service to be provided to the rest of the server
103+
104+
@Module({
105+
providers: [ConfigService],
106+
exports: [ConfigService]
107+
})
108+
export class ConfigModule extends MakeConfigurableDynamicRootModule<
109+
ConfigModule,
110+
ConfigModuleOptions
111+
>(CONFIG_MODULE_OPTIONS) {
112+
static Deferred = ConfigModule.externallyConfigured(ConfigModule, 0);
113+
}
114+
```
115+
116+
Now it can be used in another module like this:
117+
118+
```ts
119+
@Module({
120+
imports: [ConfigModule.Deferred]
121+
})
122+
export class ConfigModuleDependentModule {}
123+
```

0 commit comments

Comments
 (0)