Angular recently had an RFC (Request for Comments) on Standalone Components. It is an effort to make
NgModules in Angular optional. We do not want to remove them completely as many Angular apps currently rely on the building blocks that are
Manfred Steyer explored what this will mean for the ecosystem moving forward and how we can begin to think about writing our Angular apps in his short blog series: https://www.angulararchitects.io/en/aktuelles/angulars-future-without-ngmodules-part-2-what-does-that-mean-for-our-architecture/
I believe, however, that the best potential architecture we can achieve when Standalone Components are introduced, will be based around Declarative Routing.
Declarative Routing is a concept that we have seen implemented by packages such as
react-router. It involves declaring our routes as elements in our component’s template.
It allows us to define the Routes through our application in our components, removing the need to configure the
RouterModule at multiple layers of our application.
As Standalone Components require us to specify their
imports in their
@Component decorator, this could get unwieldy. It also means that we’re still relying on
NgModules, making it difficult to ever fully remove them from the framework.
However, what if we simply used our component’s template to define the Routes through our application? We could easily have a beautiful, declarative API for our application routing that supports redirects, fallbacks, lazy loading of components (key!), and standard Route Guards!
But, we should take this further. Right now, people could define Routes in any component in their application, and figuring out the full routing setup for the application will become extremely painful.
With Standalone Components, we should still slice our application by dedicated features or domains. We’ll create a folder/workspace structure wherein each feature has it’s own dedicated folder/library. At the root of these, there will live a
route-entry will contain the routes for this portion of the application. This creates a structure such as:
We can expect to see a
route-entry at the root of each domain/feature we have in our system which will define the routing for that area of the application. Now, every developer will know exactly where to look when they need to find, edit or add routes to the system.
From this, our top-level app routing should only ever point to
Following this pattern with Standalone Components means our components are the driving force of our applications, as they should be.
This is Component-First Architecture.
Component-First Architecture is where our components define and drive the user experience of our application. Anything that impacts the user’s experience should be handled via our components, as it is our components that the user interacts with.
Component-First aims to create an architectural pattern that places Components as the source of truth for your Angular application.
Currently in the Angular ecosystem,
NgModules act almost like orchestrators, wiring together your application. It's from the very existence of
NgModules where we created the
This architecture is fine. It works. It scales. But is it overkill? Possibly.
While it does introduce a great separation of concerns within your app's structure,
SharedModules often become overpopulated and difficult to maintain.
SharedModules in particular can become a dumping ground. This often leads to a situation where we need to import the
SharedModule into all our
FeatureModules, even if we one need 1 thing from it.
With Component-First, our Components decide themselves what they need to perform. They can take
Injectables via their
constructor and they can import any
pipe they need to function. This increased level of granularity allows our Components to be hyper-focused on their function, reducing any additional bloat that might end up compiled with the Component.
Components in a Component-First Architecture will be completely tree-shakeable. If they aren't imported or routed to, they won't be included in the final bundle for our applications. Currently, to achieve the same effect with
NgModules, we need to follow a pattern known as the SCAM (Single Component Angular Module) Pattern which was popularized by Lars Gyrup Brink Nielsen.
By following the Component-First Architecture Pattern, we also reduce the coupling between our Components and
NgModules which paves the way to a truly
NgModule-less Angular. We can still keep all the same composability that
NgModules offered by simply following some best practices on code-organization; something Angular has us well trained to do already.
If components point to components, our mental mind map of our application becomes simpler. You can traverse the tree of components in your app and build out a pretty comprehensive map of your app, without having to worry about
NgModules adding additional dependencies on your components that you may not be expecting. In Component-First, your components dictate their own dependencies. This massively reduces cognitive load, especially for newcomers to the codebase.
Colum Ferry’s Twitter: https://twitter.com/FerryColum