We first talked about selectorless at ng-conf 2024.
Originally, Angular was designed to enhance HTML elements with components and directives. That was deeply embedded in AngularJS because there was a global directive registry. Each directive has a selector that could match any element of the page as long as it satisfies the directive's selector. This means that the same HTML can behave very differently depending on the directives that match its elements.
In Angular, we had a hierarchical registry via NgModules. In each NgModule, you can declare components and directives, which can dynamically match elements in the templates of components that belong to the transitive closure of these NgModules. This way, if you provide the same component in the context of a different trasitive closure, the elements of its template can match different components and directives and have a completely different behavior.
Throughout the years, we saw that NgModules was a redundant concept, creating a lot of indirection, confusion, and complexity. That's why we developed "standalone components" in v14. With standalone components, you have an imports
array in the metadata to import the directives and components you use in your template.
See how with standalone components, we're removing the indirection. The component's template can match only the directives and components that are within its import array. What we're left with is a static enhancement of the HTML and redundant "double import"—you import the components and directives once in the TypeScript file and once in the component metadata.
Instead of having this duplication of imports and unnecessary indirection, selectorless enable us to import directives and components and directly use them in a template.
That's only a fraction of the benefit, though! In TypeScript, we have a dependency graph that comes from the module imports. Component and directive selectors create yet another dependency graph that the TypeScript compiler is not aware of. This requires us to figure out the dependencies of the components with the Angular compiler and prevents us from performing efficient single-file compilation (i.e., we're losing locality).
Selectorless enables locality and single-file compilation.
Additionally, selector matching happens at runtime and requires extra code. With selectorless, we can remove the overhead of selector matching and get an even faster and smaller runtime.
In summary, selectorless reduces boilerplate, makes compilation faster with locality, shrinks the runtime, and makes it faster.