0
# Standalone Utilities
1
2
Utilities for working with Angular's standalone components and bootstrap configuration, supporting the modern Angular application architecture without NgModules.
3
4
## Capabilities
5
6
### Root Import Management
7
8
Functions for adding imports to the root application configuration in standalone applications.
9
10
```typescript { .api }
11
/**
12
* Adds an import to the root of the project
13
* @param options - Options for the root import
14
* @returns Rule that adds the import
15
*/
16
function addRootImport(options: AddRootImportOptions): Rule;
17
```
18
19
**Usage Example:**
20
21
```typescript
22
import { addRootImport } from '@schematics/angular/utility';
23
24
// Add router import to standalone app
25
export function addRouter(): Rule {
26
return addRootImport({
27
import: 'RouterModule.forRoot(routes)',
28
from: '@angular/router'
29
});
30
}
31
32
// Add HTTP client import
33
export function addHttpClient(): Rule {
34
return addRootImport({
35
import: 'HttpClientModule',
36
from: '@angular/common/http'
37
});
38
}
39
```
40
41
### Root Provider Management
42
43
Functions for adding providers to the root application configuration.
44
45
```typescript { .api }
46
/**
47
* Adds a provider to the root of the project
48
* @param options - Options for the root provider
49
* @returns Rule that adds the provider
50
*/
51
function addRootProvider(options: AddRootProviderOptions): Rule;
52
```
53
54
**Usage Examples:**
55
56
```typescript
57
import { addRootProvider } from '@schematics/angular/utility';
58
59
// Add router provider
60
export function addRouterProvider(): Rule {
61
return addRootProvider({
62
expression: 'provideRouter(routes)',
63
import: 'provideRouter',
64
from: '@angular/router'
65
});
66
}
67
68
// Add HTTP client provider
69
export function addHttpClientProvider(): Rule {
70
return addRootProvider({
71
expression: 'provideHttpClient()',
72
import: 'provideHttpClient',
73
from: '@angular/common/http'
74
});
75
}
76
77
// Add custom service provider
78
export function addCustomProvider(): Rule {
79
return addRootProvider({
80
expression: 'provideMyService({ apiUrl: "https://api.example.com" })',
81
import: 'provideMyService',
82
from: './my-service'
83
});
84
}
85
```
86
87
### Code Block Management
88
89
Low-level utilities for managing code blocks and pending code modifications.
90
91
```typescript { .api }
92
/**
93
* Generated code that hasn't been interpolated yet
94
*/
95
interface PendingCode {
96
/** Code that will be inserted */
97
expression: string;
98
/** Imports that need to be added to the file in which the code is inserted */
99
imports: Map<string, Map<string, string>>;
100
}
101
102
/**
103
* Callback invoked by a Rule that produces the code that needs to be inserted somewhere in the app
104
* @param block - CodeBlock instance for generating code
105
* @returns PendingCode object with expression and imports
106
*/
107
type CodeBlockCallback = (block: CodeBlock) => PendingCode;
108
109
/**
110
* Utility class used to generate blocks of code that can be inserted by the devkit into a user's app
111
*/
112
class CodeBlock {
113
/**
114
* Function used to tag a code block in order to produce a PendingCode object
115
* @param strings - Template strings array
116
* @param params - Template parameters
117
* @returns PendingCode object
118
*/
119
code(strings: TemplateStringsArray, ...params: unknown[]): PendingCode;
120
121
/**
122
* Function used to reference an external symbol that should be imported
123
* @param name - Name of the symbol to import
124
* @param moduleSpecifier - Module to import from
125
* @returns String reference to the symbol
126
*/
127
external(name: string, moduleSpecifier: string): string;
128
129
/**
130
* Transforms a PendingCode object into a format that can be inserted into a file
131
* @param pendingCode - Code to transform
132
* @param filePath - Target file path
133
* @returns Transformed PendingCode
134
*/
135
static transformPendingCode(pendingCode: PendingCode, filePath: string): PendingCode;
136
}
137
```
138
139
## Advanced Usage
140
141
### Complex Provider Setup
142
143
```typescript
144
import { addRootProvider } from '@schematics/angular/utility';
145
import { chain } from '@angular-devkit/schematics';
146
147
export function setupCompleteApp(): Rule {
148
return chain([
149
// Add router
150
addRootProvider('default', ({code, external}) => {
151
return code`${external('provideRouter', '@angular/router')}(routes)`;
152
}),
153
154
// Add HTTP client with features
155
addRootProvider('default', ({code, external}) => {
156
return code`${external('provideHttpClient', '@angular/common/http')}(
157
${external('withFetch', '@angular/common/http')}(),
158
${external('withInterceptors', '@angular/common/http')}([loggingInterceptor])
159
)`;
160
}),
161
162
// Add animations
163
addRootProvider('default', ({code, external}) => {
164
return code`${external('provideAnimations', '@angular/platform-browser/animations')}()`;
165
})
166
]);
167
}
168
```
169
170
### Conditional Provider Addition
171
172
```typescript
173
import { addRootProvider } from '@schematics/angular/utility';
174
175
export function conditionalProvider(): Rule {
176
return async (tree: Tree, context: SchematicContext) => {
177
// Check if app uses standalone architecture
178
const mainPath = '/src/main.ts';
179
const mainContent = tree.readText(mainPath);
180
181
if (mainContent.includes('bootstrapApplication')) {
182
return addRootProvider('default', ({code, external}) => {
183
return code`${external('provideMyFeature', './my-feature')}()`;
184
});
185
}
186
187
// Handle module-based app differently
188
context.logger.info('Module-based app detected, skipping standalone provider');
189
return noop();
190
};
191
}
192
```
193
194
### Custom Provider with Configuration
195
196
```typescript
197
import { addRootProvider } from '@schematics/angular/utility';
198
199
export function addConfiguredProvider(): Rule {
200
return addRootProvider('default', ({code, external}) => {
201
return code`${external('provideMyService', '@my-org/my-service')}({
202
apiUrl: 'https://api.example.com',
203
timeout: 5000,
204
retries: 3
205
})`;
206
});
207
}
208
```
209
210
### Multiple Providers
211
212
```typescript
213
import { addRootProvider } from '@schematics/angular/utility';
214
215
export function addMultipleProviders(): Rule {
216
return addRootProvider('default', ({code, external}) => {
217
return code`
218
${external('provideStore', '@ngrx/store')}(reducers),
219
${external('provideEffects', '@ngrx/effects')}([UserEffects, ProductEffects])
220
`;
221
});
222
}
223
```
224
225
## Integration with Module-based Apps
226
227
For applications that haven't migrated to standalone, these utilities will gracefully handle the differences:
228
229
```typescript
230
import { addRootProvider } from '@schematics/angular/utility';
231
232
// This will work in both standalone and module-based apps
233
export function universalProvider(): Rule {
234
return (tree: Tree, context: SchematicContext) => {
235
const mainPath = '/src/main.ts';
236
const mainContent = tree.readText(mainPath);
237
238
if (mainContent.includes('bootstrapApplication')) {
239
// Standalone app - add to providers array
240
return addRootProvider({
241
expression: 'provideMyFeature()',
242
import: 'provideMyFeature',
243
from: './my-feature'
244
});
245
} else {
246
// Module-based app - would need to use module utilities instead
247
context.logger.warn('Module-based app detected. Consider migrating to standalone.');
248
return noop();
249
}
250
};
251
}
252
```
253
254
## Error Handling
255
256
The standalone utilities include built-in error handling for common scenarios:
257
258
- **Missing main.ts**: Utilities will log appropriate errors if the main application file is not found
259
- **Non-standalone apps**: Functions will detect module-based applications and provide appropriate warnings
260
- **Invalid syntax**: Code parsing errors are caught and reported with helpful messages
261
- **Duplicate providers**: The utilities can detect and handle duplicate provider registrations