In my project, I have below module hierarchy.
And I have shared module which will be shared between Module A and all its children.
Q: Do I have to import shared module in every child module of Module A or importing it in Module A is enough?
Thanks,
You have to import it in each child module separately, if that module will use at least one item from the Shared module.
That being said, you should consider not having Shared module at all, since it's a bad practice. Imagine you have 20 items in your Shared module, and some of you child modules will use only one item from it. Well, you will have to import the whole Shared module (even you will use only one item from it), which will increase the final bundle for your child module and decrease the performance.
Related
In NPM, is it possible to import all the modules in a scope?
say I have a scope in my artifact
#myorg/m1
#myorg/m2
#myorg/m3
....
#myorg/mn
My current app depends on all the packages in #myorg. Is there an option or way to say in my package.json that I want to import all of them together?
Having an index.js file in #myorg will work? Before I walk down that path, wanted to check around.
Thanks
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.
I know I have to remove all deep imports before upgrading to Angular 4, but I have no idea what is a deep import. Literally nobody mentions it. What is it? How does it look like?
Taken from How to deal with losing deep imports in Angular 4, an example of a deep import:
import { VALID } from '#angular/forms/src/model'
meaning 3 levels deep, whereas now you can only go 1 level:
import { VALID } from '#angular/forms'
which is invalid if "VALID" is in model, 3 levels deep. that's all there is to it. If you need something that's in "deep", it should be exported to in the first level now, or you need to open a ticket to angular to export it.
Not trying to advertise my own gist article, but I explain them here
Description
A "deep import" is simply an ESM import that goes deeper than the package root:
import thingA from 'my-package-name/src/components/thingA'
import thingB from '#my-namespace/my-package-name/src/components/thingA'
A namespaced package does not necessitate a deep import if the package name (package.json:name key) contains a slash:
import thingA from '#my-namespace/my-package-name'
Relative imports (./path/to/module) are also not considered deep imports, in fact it might be considered bad practice to "shallow import" an exported module from one's own package by it's package.json:main key location (i.e. src/index.js) as this can often cause circular dependencies.
Why deep imports can be a problem
Package bundling
Package bundlers are often used to transpile and condense a project to a distributive, single-file version (i.e. dist/bundle.js). Other packages that try to deep import from such packages experience errors, as the directory structure from src may often not be maintained or even included in the published package.
Unintended imports and directory changes
A developer might deep import a module from a package when it was not intended to be used outside of the scope of that package. Your changing of the name of an internally-used export or your package's directory structure should not require a major version (breaking change) update for a module that was only intended to be consumed internally.
I'm using Angular2 in my project and I have several modules.
I have base module which is called BaseModule
And have for example two (or more) extra modules - FirstModule and SecondModule.
Each module has his own routing. BaseModule has basic routes for system,
FirstModule and SecondModule has his own separated routes.
BUT
I want to create routes like
/user/10/profile
Where ProfileComponent for user contains into FirstModule
Another examples
/user/10/stories
Where StoriesComponent for user contains into FirstModule
/user/10/news
Where NewsComponent for user contains into SecondModule!!!!
But Angular Router allow only routes like:
/firstmodule/......
/secondmodule/......
So, they should be grouped by module.
I want to do it with modules because I want to have async(lazy) loaded parts of my application.
As I know Angular disallow variants when we async(lazy) load components.
Anybody have ideas how I can create what I want?
For routes in root module define your roots as RouterModule.forRoot(['']) and for routes in the other modules use RouterModule.forChild(['']). Since your child modules will be in the imports of the parent this will route properly.
I wonder how NgModule actually affects Angular 2 injector hierarchy.
What does the hierarchy look like in an app with nested modules? Does it create a new injector instance per each module or gets access to top-level injector (similarly to Angular 1.x modules)?
It can be somewhat confusing to figure out the tree in a big app.
Is there a way to print out, inspect or explore visually the hierarchy of injectors (like it could be done for scope hierarchy in Angular 1.x)?
According to the Modules documentation: https://angular.io/docs/ts/latest/guide/ngmodule.html
Angular registers these providers with the root injector of the module's execution context. That's the application's root injector for all modules loaded when the application starts.
Angular can inject one of these provider services into any component
in the application. If this module provides the HeroService, or any
module loaded at launch provides the HeroService, Angular can inject
the same HeroService intance into any app component.
A lazy loaded module has its own sub-root injector which typically is
a direct child of the application root injector.
Lazy loaded services are scoped to the lazy module's injector. If a
lazy loaded module also provides the HeroService, any component
created within that module's context (e.g., by router navigation) gets
the local instance of the service, not the instance in the root
application injector.
Components in external modules continue to receive the instance
created for the application root.
So, you have one injector that is shared between all the modules. However, lazy-loaded components will have a child injector
You should be able to investigate providers using ng.probe($0) in the browser console. See also https://stackoverflow.com/a/35233711/217408.
You can load modules with MyModule.forRoot() (see also https://angular.io/docs/ts/latest/guide/ngmodule.html#!#providers) to get providers added at the root level.
If you provide it in a module, then it's available to the components in this module. I haven't seen it mentioned that a module introduces a child injector explicitly but to me this looks like it has to be the case.