Ng-News 25/14: Selectorless PR
Selectorless aims to eliminate the need for selectors in templates by referencing components directly via class names. A first PR has been merged, which shows the initial direction Angular is taking toward this feature. Selectorless Standalone components were introduced in Angular 14. They removed the abstraction of NgModules, which had caused some trouble for the compiler. To figure out a component’s dependencies, the compiler first had to find the NgModule, which was usually in another file. Modern bundlers are built for single-file compilation, which makes parallel builds possible. A perfect setup is if a file includes everything it needs, like its dependencies. On the path towards single-file compilation, another obstacle, namely the selector, will be removed. A component’s template uses selectors to reference its dependencies. The corresponding classes are imported in the TypeScript file, but that's not enough. Just having the name of the class doesn't tell anything about its selector. So in order to find out the selector of that dependency, the compiler needs to access the classes' filename and therefore break single-file compilation. An example: import { ComponentA } from './component-a'; import { ComponentB } from './component-b'; @Component({ template: '', imports: [ComponentA, ComponentB] }) class App {} The compiler needs to know what class is behind the selector app-home. With the information in this file, it is not possible to tell if it is ComponentA or CompomentB. So the compiler needs to traverse the imports to find the right class. The fix is simple. Why use a selector at all? Just reference the class directly in the template. That's the same thing we've been doing in TypeScript all the time. import { ComponentA } from './component-a'; import { ComponentB } from './component-b'; @Component({ template: '' }) class App {} Additionally, if it is clear what class is used in the template, it is also more straightforward for the runtime, which leads to better performance. And this is exactly what selectorless is all about. Selectorless is in a very early stage. Eventually, we will get an RFC with much more details. Selectorless template parsing #60724 crisbeto posted on Apr 03, 2025 ⚠️ Disclaimer ⚠️ this PR implements syntax that is still being designed and discussed. It's an initial prototype that will allow us experiment with the runtime and run user studies. These changes are an initial implementation of the template parsing for selectorless templates. Here's an example showing most of the syntax where we create a MatButton component as a link, we apply the HasRipple directive without any inputs and set a tooltip that's only enabled if the user doesn't have permissions to go to the admin page: Admin View on GitHub #angular #typescript #programming #webdev #webdevelopment #javascript | Minko Gechev | 80 comments So excited to see selectorless taking shape! In summary: selectorless removes the boilerplate in standalone components ("double import"), opens the door for many build time optimizations thanks to locality, and makes the framework smaller and faster. Here's an in-depth explanation https://lnkd.in/gNFWjdt4 This snippet shows the *entire* syntax of selectorless. Most components will look like this: instead of You can find the early syntax we're thinking about below. We'll share an RFC to collect community feedback in the upcoming months. And here's the template parsing pull request
Selectorless aims to eliminate the need for selectors in templates by referencing components directly via class names. A first PR has been merged, which shows the initial direction Angular is taking toward this feature.
Selectorless
Standalone components were introduced in Angular 14. They removed the abstraction of NgModules, which had caused some trouble for the compiler.
To figure out a component’s dependencies, the compiler first had to find the NgModule, which was usually in another file.
Modern bundlers are built for single-file compilation, which makes parallel builds possible. A perfect setup is if a file includes everything it needs, like its dependencies.
On the path towards single-file compilation, another obstacle, namely the selector, will be removed.
A component’s template uses selectors to reference its dependencies. The corresponding classes are imported in the TypeScript file, but that's not enough. Just having the name of the class doesn't tell anything about its selector.
So in order to find out the selector of that dependency, the compiler needs to access the classes' filename and therefore break single-file compilation.
An example:
import { ComponentA } from './component-a';
import { ComponentB } from './component-b';
@Component({
template: ' ',
imports: [ComponentA, ComponentB]
})
class App {}
The compiler needs to know what class is behind the selector app-home. With the information in this file, it is not possible to tell if it is ComponentA or CompomentB. So the compiler needs to traverse the imports to find the right class.
The fix is simple. Why use a selector at all? Just reference the class directly in the template. That's the same thing we've been doing in TypeScript all the time.
import { ComponentA } from './component-a';
import { ComponentB } from './component-b';
@Component({
template: ' '
})
class App {}
Additionally, if it is clear what class is used in the template, it is also more straightforward for the runtime, which leads to better performance.
And this is exactly what selectorless is all about.
Selectorless is in a very early stage. Eventually, we will get an RFC with much more details.
Selectorless template parsing
#60724
⚠️ Disclaimer ⚠️ this PR implements syntax that is still being designed and discussed. It's an initial prototype that will allow us experiment with the runtime and run user studies.
These changes are an initial implementation of the template parsing for selectorless templates. Here's an example showing most of the syntax where we create a MatButton
component as a link, we apply the HasRipple
directive without any inputs and set a tooltip that's only enabled if the user doesn't have permissions to go to the admin page:
<MatButton:a href="/admin" @HasRipple @Tooltip(message="Cannot navigate" [disabled]="hasPermissions")>AdminMatButton:a>