Skip to content

Commit 50d5c29

Browse files
SkyZeroZxAndrewKushnir
authored andcommitted
docs: align lightweight injection tokens with the style guide
1 parent d23ce76 commit 50d5c29

File tree

1 file changed

+29
-29
lines changed

1 file changed

+29
-29
lines changed

adev/src/content/guide/di/lightweight-injection-tokens.md

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,36 +38,36 @@ import {Component, contentChild} from '@angular/core';
3838
selector: 'lib-header',
3939
…,
4040
})
41-
class LibHeaderComponent {}
41+
class LibHeader {}
4242

4343
@Component({
4444
selector: 'lib-card',
4545
…,
4646
})
47-
class LibCardComponent {
48-
readonly header = contentChild(LibHeaderComponent);
47+
class LibCard {
48+
readonly header = contentChild(LibHeader);
4949
}
5050
```
5151

5252
Because `<lib-header>` is optional, the element can appear in the template in its minimal form, `<lib-card />`.
5353
In this case, `<lib-header>` is not used and you would expect it to be tree-shaken, but that is not what happens.
54-
This is because `LibCardComponent` actually contains two references to the `LibHeaderComponent`:
54+
This is because `LibCard` actually contains two references to the `LibHeader`:
5555

5656
```ts
57-
readonly header = contentChild(LibHeaderComponent);
57+
readonly header = contentChild(LibHeader);
5858
```
5959

60-
- One of these reference is in the _type position_-- that is, it specifies `LibHeaderComponent` as a type: `readonly header: Signal<LibHeaderComponent|undefined>`.
61-
- The other reference is in the _value position_-- that is, `LibHeaderComponent` is the value passed into the `contentChild` function: `contentChild(LibHeaderComponent)`.
60+
- One of these reference is in the _type position_-- that is, it specifies `LibHeader` as a type: `readonly header: Signal<LibHeader|undefined>`.
61+
- The other reference is in the _value position_-- that is, `LibHeader` is the value passed into the `contentChild` function: `contentChild(LibHeader)`.
6262

6363
The compiler handles token references in these positions differently:
6464

6565
- The compiler erases _type position_ references after conversion from TypeScript, so they have no impact on tree-shaking.
6666
- The compiler must keep _value position_ references at runtime, which **prevents** the component from being tree-shaken.
6767

68-
In the example, the compiler retains the `LibHeaderComponent` token that occurs in the value position.
68+
In the example, the compiler retains the `LibHeader` token that occurs in the value position.
6969
This prevents the referenced component from being tree-shaken, even if the application does not actually use `<lib-header>` anywhere.
70-
If `LibHeaderComponent` 's code, template, and styles combine to become too large, including it unnecessarily can significantly increase the size of the client application.
70+
If `LibHeader` 's code, template, and styles combine to become too large, including it unnecessarily can significantly increase the size of the client application.
7171

7272
## When to use the lightweight injection token pattern
7373

@@ -77,18 +77,18 @@ There are two cases when that can happen:
7777
- The token is used in the value position of a [content query](guide/components/queries#content-queries).
7878
- The token is used with the `inject` function.
7979

80-
In the following example, both uses of the `OtherComponent` token cause retention of `OtherComponent`, preventing it from being tree-shaken when it is not used:
80+
In the following example, both uses of the `CustomOther` token cause retention of `CustomOther`, preventing it from being tree-shaken when it is not used:
8181

8282
```ts {highlight: [[2],[4]]}
83-
class MyComponent {
84-
private readonly other = inject(OtherComponent, {optional: true});
83+
class App {
84+
private readonly other = inject(CustomOther, {optional: true});
8585

86-
readonly header = contentChild(OtherComponent);
86+
readonly header = contentChild(CustomOther);
8787
}
8888
```
8989

9090
Although tokens used only as type specifiers are removed when converted to JavaScript, all tokens used for dependency injection are needed at runtime.
91-
When using `inject(OtherComponent)`, `OtherComponent` is passed as a value argument.
91+
When using `inject(CustomOther)`, `CustomOther` is passed as a value argument.
9292
The token is now in a value position, which causes the tree-shaker to keep the reference.
9393

9494
HELPFUL: Libraries should use [tree-shakable providers](guide/di/dependency-injection#providing-dependency) for all services, providing dependencies at the root level rather than in components or modules.
@@ -98,33 +98,33 @@ HELPFUL: Libraries should use [tree-shakable providers](guide/di/dependency-inje
9898
The lightweight injection token design pattern consists of using a small abstract class as an injection token, and providing the actual implementation at a later stage.
9999
The abstract class is retained, not tree-shaken, but it is small and has no material impact on the application size.
100100

101-
The following example shows how this works for the `LibHeaderComponent`:
101+
The following example shows how this works for the `LibHeader`:
102102

103103
```ts {highlight: [[1],[5], [15]]}
104104
abstract class LibHeaderToken {}
105105

106106
@Component({
107107
selector: 'lib-header',
108-
providers: [{provide: LibHeaderToken, useExisting: LibHeaderComponent}],
108+
providers: [{provide: LibHeaderToken, useExisting: LibHeader}],
109109
…,
110110
})
111-
class LibHeaderComponent extends LibHeaderToken {}
111+
class LibHeader extends LibHeaderToken {}
112112

113113
@Component({
114114
selector: 'lib-card',
115115
…,
116116
})
117-
class LibCardComponent {
117+
class LibCard {
118118
readonly header = contentChild(LibHeaderToken);
119119
}
120120
```
121121

122-
In this example, the `LibCardComponent` implementation no longer refers to `LibHeaderComponent` in either the type position or the value position.
123-
This lets full tree-shaking of `LibHeaderComponent` take place.
122+
In this example, the `LibCard` implementation no longer refers to `LibHeader` in either the type position or the value position.
123+
This lets full tree-shaking of `LibHeader` take place.
124124
The `LibHeaderToken` is retained, but it is only a class declaration, with no concrete implementation.
125125
It is small and does not materially impact the application size when retained after compilation.
126126

127-
Instead, `LibHeaderComponent` itself implements the abstract `LibHeaderToken` class.
127+
Instead, `LibHeader` itself implements the abstract `LibHeaderToken` class.
128128
You can safely use that token as the provider in the component definition, allowing Angular to correctly inject the concrete type.
129129

130130
To summarize, the lightweight injection token pattern consists of the following:
@@ -141,8 +141,8 @@ The token is now an abstract class. Since the injectable component implements th
141141
The implementation of the method, with all its code overhead, resides in the injectable component that can be tree-shaken.
142142
This lets the parent communicate with the child, if it is present, in a type-safe manner.
143143

144-
For example, the `LibCardComponent` now queries `LibHeaderToken` rather than `LibHeaderComponent`.
145-
The following example shows how the pattern lets `LibCardComponent` communicate with the `LibHeaderComponent` without actually referring to `LibHeaderComponent`:
144+
For example, the `LibCard` now queries `LibHeaderToken` rather than `LibHeader`.
145+
The following example shows how the pattern lets `LibCard` communicate with the `LibHeader` without actually referring to `LibHeader`:
146146

147147
```ts {highlight: [[2],[9],[11],[19]]}
148148
abstract class LibHeaderToken {
@@ -151,9 +151,9 @@ abstract class LibHeaderToken {
151151

152152
@Component({
153153
selector: 'lib-header',
154-
providers: [{provide: LibHeaderToken, useExisting: LibHeaderComponent}],
154+
providers: [{provide: LibHeaderToken, useExisting: LibHeader}],
155155
})
156-
class LibHeaderComponent extends LibHeaderToken {
156+
class LibHeader extends LibHeaderToken {
157157
doSomething(): void {
158158
// Concrete implementation of `doSomething`
159159
}
@@ -162,7 +162,7 @@ class LibHeaderComponent extends LibHeaderToken {
162162
@Component({
163163
selector: 'lib-card',
164164
})
165-
class LibCardComponent implements AfterContentInit {
165+
class LibCard implements AfterContentInit {
166166
readonly header = contentChild(LibHeaderToken);
167167

168168
ngAfterContentInit(): void {
@@ -180,8 +180,8 @@ If the child component has been tree-shaken, there is no runtime reference to it
180180
### Naming your lightweight injection token
181181

182182
Lightweight injection tokens are only useful with components.
183-
The Angular style guide suggests that you name components using the "Component" suffix.
184-
The example "LibHeaderComponent" follows this convention.
183+
The [Angular Style Guide](style-guide) suggests that you name components without the suffix `Component`.
184+
The example `LibHeader` follows this convention.
185185

186186
You should maintain the relationship between the component and its token while still distinguishing between them.
187-
The recommended style is to use the component base name with the suffix "`Token`" to name your lightweight injection tokens: "`LibHeaderToken`."
187+
The recommended style is to use the component base name with the suffix `Token` to name your lightweight injection tokens: `LibHeaderToken`.

0 commit comments

Comments
 (0)