The description of NestJS specifically states that this framework was designed for "scalable server-side applications". Surprisingly, only in the eighth version it began to support prefixes at the module level, and this feature has a number of significant limitations.
In this post, NestJS v9.2 and Ditsmod v2.27 are used for comparison. A finished example with nested routes in Ditsmod can be viewed on github. I am the author of Ditsmod.
In addition to the slow implementation of nested routes in NestJS, its router even now (in the ninth version) does not care about collisions of path in routes. If you are writing a large project and accidentally duplicated a path, the NestJS router will not tell you anything about it. Likewise, it won't say anything if you accidentally duplicated the parameter name: one/:two/:two
. It's especially easy to make such duplicates when you use third-party modules. Although this is how the Express router works, NestJS could fix this if it positions itself as a framework for "scalable server-side applications".
Currently, NestJS does not support the ability to import a module while simultaneously adding guards to routes of this module. This feature can also be very useful in large projects, especially for importing third-party modules.
Unlike NestJS, Ditsmod has been able to add prefixes at the module level since the first version. For example, to serve /posts/:postId
, the parent module is imported as follows:
import { rootModule } from '@ditsmod/core';
import { PostsModule } from './posts/posts.module';
@rootModule({
appends: [
{ path: 'posts/:postId', module: PostsModule }
// ..
],
})
export class AppModule {}
And to import the child module serving /posts/:postId/comments/:commentId
, in Ditsmod it is done as follows:
import { featureModule } from '@ditsmod/core';
import { CommentsModule } from './comments/comments.module';
@featureModule({
appends: [{ path: 'comments/:commentId', module: CommentsModule }],
// ...
})
export class PostsModule {}
In Ditsmod, appends
is a lightweight version of imports
that only allows you to appending modules, inheriting only the prefix of the current module. No providers or extensions are imported in this case.
Starting with the eighth version, NestJS can create nested routes in a similar way:
@featureModule({
imports: [
PostsModule,
CommentsModule,
RouterModule.register([
{
path: 'posts',
module: PostsModule,
children: [
{
path: ':postId/comments/:commentId',
module: CommentsModule
},
]
},
]),
],
// ...
})
export class AppModule {}
But there are the following limitations:
- Such configuration import can be done only once for the entire application.
- If imported modules have no controllers, all controllers from their child modules are ignored. That is, if there are no controllers in
PostsModule
from the previous example, then all controllers fromCommentsModule
will be ignored. - In this case, it is not enough that you pass
PostsModule
andCommentsModule
to theRouterModule.register()
method, you also need to directly pass them to theimports
array ofAppModule
data. Moreover, if you do not make such an import, NestJS will not tell you anything about it, but routes from imported modules will not work.
These limitations very significantly reduce the possibility of scaling projects, their modularity.
Conclusion
Statistics show that currently NestJS is downloaded about 1.8 million times per week, which shows how much developers like this framework. NestJS took many concepts from Angular. Likewise, many concepts from Angular were taken to design Ditsmod. As the author of Ditsmod, I may not always be objective, but I try to criticize NestJS constructively. If you have anything to add to this criticism, please do so in the comments.
Top comments (8)
A note regarding
RouterModule
from Nestjs: I'm pretty sure that we still need to import the modules at the parent due to some design decision made by Kamil. After changing one line at@nestjs/core
's source I was able to circumvent that duplication (at least in a simple use case of mine).btw looks like in Ditsmod we can easily add prefixes to several modules at once, which we can't do with
RouterModule
. Am I correct?Yes you're right.
Oh, I looked into this issue, it turns out that the router in NestJS is even worse than I imagined before. The issue is still not fixed in NestJS v9.2.
judging by Kamil's response, there's nothing to fix. I can't tell if that's a limitation or not, but I found it pretty odd.
does Ditsmod has lifecycle hooks like Angular and Nest?
No, Ditsmod does not currently have hooks. I don't see the need for them yet.
I'd like to see a comparison on the circular dependencies issue.
Both NestJS and Ditsmod use the
forwardRef()
function to avoid circular dependencies issue. In both cases, this is also taken from Angular.