NestJS: Using forRoot / forChild in custom module - race condition? - javascript

Repo is available here to highlight the issue.
I am having a problem with a race condition. I have created a ConfigModule - this has a forRoot and a forChild.
The forRoot sets up the loading of the .env file and the forChild uses it in another module.
The problem is that forChild is called before forRoot. The ConfigService would be injected with missing config because forRoot hasn't executed first.
> AppModule > ConfigModule.forRoot InstanceModule >
> ConfigModule.forChild
I placed some simple console.log commands that output this
I am in Config Module FOR CHILD
I am in Config Module FOR ROOT
As you can see the forChild is being executed first, I tried using forwardRef and that didn't work.
If you let the application run you will see
[2019-03-24T11:49:33.602] [ERROR] ConfigService - There are missing mandatory configuration: Missing PORT
[2019-03-24T11:49:33.602] [FATAL] ConfigService - Missing mandatory configuration, cannot continue!, exiting
This is because I check that some process.env are available which are loaded in via dotenv. Of course, because the forRoot isn't executed first then the forChild returns its own new instance of the ConfigService.
ConfigService validates the availability of the environment variables.
So, basically, the forChild is executing and returning its own ConfigService before forRoot.
TO make it work, if you comment out the InstanceModule inside the AppModule then it will automatically start listening and returns the port number from an environment variable.
Of course, because InstanceModule uses the forChild - there is a race condition.

Why does this not work?
1) Nest builds up a dependency graph and instantiates the given modules and their providers according to this graph. The order of your imports or the naming of your dynamic modules's methods (forRoot/forChild) does not influence the order of the instantiation.
2) When you create dynamic modules, each module will be its own instance, they won't be singletons like regular modules. In your case, you'd create two different ConfigModule instances and with it, two different ConfigService instances; hence they won't share your .env configuration. This can't work, independent of the instantiation order.
Alternatives
Have a look at the nestjs/typeorm package. Under the hood, it creates a shared TypeOrmCoreModule, which is shared between the different dynamic module instances created by TypeOrmModule.forRoot / TypeOrmModule.forChild. For it to be shared and dynamic at the same time, it has to be made #Global though. In your case, since you don't have any configurations in your forChild imports, you would just make the whole ConfigModule global and then omit the forChild() imports, since the ConfigService would be globally available anyway.
If you don't want your service to be globally available, you could initialize your service after the startup process, for example in your AppModule's onModuleInit method.

Related

Angular: Deregister a component but keep files and folders

I have a angular project which have few components that are not used currently but kept as I have plans to work on those in future. Removing the components from declarations from it's respective modules does not fully de-registers it. When I start the server again or create build the removed components throws errors that it cannot find the dependencies.
An example is below screenshot when I removed compiler component from portal.module.ts declaration it still throws error that it cannot find the mat-icon.
Removing the whole folder solves the problem after removing the declaration but at this moment I want to keep the component folder. What I am expecting is that once I remove the component from declaration I will be able to run my project as normal by skipping those removed folders.
Is there any way around to solve this scenario?
To use <mat-icon> in a component, the MatIconModule needs to be imported into that component's imports tree (i.e. whichever NgModule is declaring the component). If you have uncommented references to <mat-icon> in a component, and the MatIconModule is not found, you will correctly receive that error.
Options:
Comment references to <mat-icon> in any HTML templates in which the component is not receiving an imported instance of MatIconModule
Ensure that the MatIconModule is imported in the components declaring NgModule
As #mike-s suggested (and likely the best option for code quality), delete the unused code and store it on a separate branch/use git to retrieve it again when needed

Instantiate an object defined in module A and use its methods in module B javascript

I'm working in a web development project.
Right now i'm using a 3rd party library to instantiate an object of that library in a file called, let's say, fileA.js
so i do:
import libraryExport from "./librarymain.js"
var object = libraryExport( ... );
export default object;
Now, in fileB.js i want to use the methods that the instantiated object has, for example:
import object from "fileA.js"
object.methodOfTheLibrary();
However, when im running this in my browser console i always get "methodOfTheLibrary is not a function", which means, from my point of view, that the library is not being imported properly in fileB.js
Note: I'm using webpack to bundle all of my files and everything was compiling and bundling just fine until i came with issues. I usually know my way around C++ in an advanced way but for JS i just still don't fully understand how to solve these kind of import issues.
Thank you for any help
It's generally* recommended that you avoid using an imported module directly in the body of another module. (One of your own modules, that is... as you'll see in a moment, third-party modules are generally fine to use.)
The big issue is load order. If your fileA also imports some other module, which imports another module which then imports fileB, then fileB will attempt to run and, since fileA is still trying to load dependencies, object will not actually have been instantiated yet.
You'll either need to carefully review your dependencies to look for just such a loop and then eliminate it or, if possible, restructure fileA to wrap your code in a function that can be called once the entry point has finished loading (which will guarantee that all other modules have been resolved):
// fileB.js
import object from "fileA.js"
export function init() {
object.methodOfTheLibrary();
}
// main.js
import init from "fileB.js";
init();
* "generally" meaning that there are plenty of perfectly acceptable situations where it's fine. You just have to mindful of the pitfalls and mitigate against those situations.

Difference forRoot and forFeature [Nest JS]

I would like to understand the difference between forRoot and forFeature in nest js dynamic modules.
I also would like to understand this difference in the case of the TypeOrm dynamic module used with nestjs.
Generally speaking, as this does not always hold true, forRoot/register is a way to provide the configuration the module is going to use whereas forFeature is away to create a dynamic provider that has it's own injection token.
In the case of the TypeOrmModule as you mentioned, forRoot() sets up the connection information that Nest makes use of, and Nest creates the injection token for the connection that is created. For forFeature, Nest takes that connection injection token under the hood and creates the injection token and custom provider for the repositories that were passed n. The token usually looks like <EntityName>Repository, and uses a factory under the hood to inject the connection and get the repository out from the TypeORM system so it can be injected into your regular services.
From nestjs discord,
forRoot/forRootAsync: configure a module one time. This is either for a global service, or a re-used configuration internally
forFeature/forFeatureAsync: make use of the configuration from forRoot/forRootAsync for a specific provider. This usually creates an injection token.
register/registerAsync: a module that can be registered multiple times with different configurations each time.
The official explanation (https://docs.nestjs.com/fundamentals/dynamic-modules#community-guidelines) is also helpful.
Use forRoot if you are expecting to configure a dynamic module once and reuse that configuration in multiple places.
Use forFeature to use the configuration of a dynamic module's forRoot but need to modify some configuration specifics in the calling module.

Mock vs Import Then Mock

I'm trying to understand when I can just import a mock vs when I need to import the mock and still use jest.mock in the test file. I'm looking at the manual-mocks example from Jest's Github.
One Step Module Mocking
In the Lodash test, Lodash is mocked in the __mocks__ directory using createMockFromModule, exported, and simply imported using the standard module import and used directly in the test (no additional mocking).
Two Step Mocking
In that same project, the User model is exported and there is a separate User mock file. But in the User mocked test, the User is imported but there is an additional step using jest.mock('../models/user');
My Question/Confusion
Why would the Lodash test not require the additional jest.mock in the test file, or why does the User test require it? In the project, it seems like I can test both actual and mocked User implementation, but Lodash will only use the mocked implementation, even though both are created/exported using createMockFromModule in the __mocks__ directories.
The difference is that lodash is Node module and user is local module, the latter needs jest.mock('../models/user') in order for a mock from __mocks__ to be used.
As the documentation states,
If the module you are mocking is a Node module (e.g.: lodash), the mock should be placed in the __mocks__ directory adjacent to node_modules (unless you configured roots to point to a folder other than the project root) and will be automatically mocked. There's no need to explicitly call jest.mock('module_name').
Warning: If we want to mock Node's core modules (e.g.: fs or path), then explicitly calling e.g. jest.mock('path') is required, because core Node modules are not mocked by default.
This allows to avoid accidental collisions between mocks for NPM packages and local modules of the same name.

angular js dependency module config works one time

I have a module composition like this:
angular.module('mainModule',["cityModule", "countryModule"]);
angular.module('mapModule',[]);
angular.module('cityModule',["mapModule"]);
angular.module('countryModule',["mapModule"]);
main module contains countryModule and cityModule. And mapModule goes to cityModule and countryModule.
so I have a config on mapModule.
angular.module("mapModule").config([function () {
console.log("this is map config")
}]);
I have seen that writes "this is map config" only one time. But I referenced mapModule two different modules (cityModule and countryModule).
Should it write two times? Why?
(if I have a provider on mapModule it writes console one times as well.)
The single output is correct.
From the documentation:
Modules can list other modules as their dependencies. Depending on a
module implies that the required module needs to be loaded before the
requiring module is loaded. In other words the configuration blocks of
the required modules execute before the configuration blocks of the
requiring module. The same is true for the run blocks. Each module can
only be loaded once, even if multiple other modules require it.
In your example mapModule's config will run first, but only once.

Categories