New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(core): added unique dynamic module factory #12898
Conversation
const kUniqueModuleId = Symbol('kUniqueModuleId'); | ||
|
||
export class UniqueDynamicModuleFactory { | ||
protected static readonly uniqueMap = new Map<string, string>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit concerned on this being static
what if we want to create multiple apps (let's say, one NestFactory.createApplicationContext
and other with NestFactory.create
)
I can't think of any other approach tho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if we want to create multiple apps (let's say, one NestFactory.createApplicationContext and other with NestFactory.create)
Just chiming in here - I don't think anyone should be doing that 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, me too :p So we can treat that as a limitation of UniqueDynamicModuleFactory
if someone try to do so
|
||
throw new RuntimeException( | ||
`A module with this ID was already added before for "${ | ||
this.uniqueMap.get(staticUniqueId).split('_')[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of another API for this I believe yours is better
Another concern of mine: does module re-exporting still works? what about |
We may introduce a breaking change in one of the next major releases instead of complicating the API even further. Upon importing a module, the framework would internally assign a private attribute (symbol?) to the dynamic module object which serves as a "unique, predictable key" of that module. This means that if one does this: imports: [TypeOrmModule.forFeature([User])], and elsewhere: imports: [TypeOrmModule.forFeature([User])], again then 2 modules would be created. However, if one does this instead: const MyTypeOrmModule = TypeOrmModule.forFeature([User]);
// and then
imports: [MyTypeOrmModule],
// and somewhere else
imports: [MyTypeOrmModule], Then only 1 module node would be created. Now when it comes to generating hashes, they may still come in handy for tools like devtools, and serialized graphs. For this, we could use a simplified algorithm where instead of serializing literally everything we just serialize the module name, its providers (tokens, not values), and possibly exports and imports too (this is something to figure out). |
@kamilmysliwiec I already did that with WeakMap, I describe that approach at #10844 (comment) under
This will not have a good outcome, trying to decide what is important and what is not. I think it will be better to give the user a feature, and they decide whether they use it or not, instead of trying to guess their use cases. What we can also do is expose that But even with the feature of giving the user the freedom to choose how the hash is generated, I think it will not have any harm to also add this feature of skipping the hash entirely. |
99,9% of users wouldn't ever make use of that simply because most framework users don't (and really shouldn't) care about how they (modules) are internally represented & orchestrated.
That's why I proposed generating predictable keys.
What key features of the framework, specifically, rely on predictable serialization? |
thinking better now, can't we instead expose such feature like this: // User-land code
class InternalModuleTokenFactory implements Something { /* ... */ }
// before any `NestFactory.create*` call
UniqueDynamicModuleFactory.apply(new InternalModuleTokenFactory()) like we have for durable providers It would change the behavior of |
I agree with you, most of the time the startup will be very fast, especially if the users don't use dynamic modules. The ones who will use that feature are people who have issues with performance during the startup, who saw the warning that we introduced, and who are interested in improving their initialization time. This feature that we are discussing is literally for edge-cases, and that's why I think is not good to introduce breaking changes just for those edge-cases.
I only know DevTools. But if we are talking about The two issues that were opened about slow startup were caused by:
The first one is very hard to avoid/detect. @micalevisk I liked your idea, that's a good API to expose the hashing algorithm. |
And this only occurs for providers that use the The only way to finally fix it is by introducing a breaking change anyway, that's why I'm generally OK with doing that as part of the next major release. If the only reason was performance then yeah perhaps replacing the current solution wouldn't be the most reasonable decision. PS. "useClass" syntax is generally broken too |
@kamilmysliwiec From what I understand, we have some choices:
I can help with the first one but I don't have enough knowledge on the other topics to be able to propose a PR, what do you want to do? |
Let's track this here #13336 |
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Today, we don't have any way to skip the hashing algorithm of
ModuleTokenFactory
.Refs: #12719
Refs: #12753 (comment)
What is the new behavior?
In this new way, we have this new module that we can use to avoid the serialization of
ModuleTokenFactory
:This also solves the issue on #12719, just adds
.wrap
to that module.Why do you need the
staticUniqueId
?Because of the following comment: #10844 (comment)
If we didn't have to maintain the same ID, we could drop the
staticModuleId
.Does this PR introduce a breaking change?
Other information
I opened it as a draft because I want to get some feedback about this API before starting to write tests.
/cc @micalevisk @jmcdo29