@@ -29,8 +29,7 @@ import {
29
29
import { applyToUpdateRecorder } from '../utility/change' ;
30
30
import { getAppModulePath , isStandaloneApp } from '../utility/ng-ast-utils' ;
31
31
import { findBootstrapApplicationCall , getMainFilePath } from '../utility/standalone/util' ;
32
- import { getWorkspace , updateWorkspace } from '../utility/workspace' ;
33
- import { Builders } from '../utility/workspace-models' ;
32
+ import { getWorkspace } from '../utility/workspace' ;
34
33
import { Schema as AppShellOptions } from './schema' ;
35
34
36
35
const APP_SHELL_ROUTE = 'shell' ;
@@ -140,77 +139,6 @@ function validateProject(mainPath: string): Rule {
140
139
} ;
141
140
}
142
141
143
- function addAppShellConfigToWorkspace ( options : AppShellOptions ) : Rule {
144
- return ( host , context ) => {
145
- return updateWorkspace ( ( workspace ) => {
146
- const project = workspace . projects . get ( options . project ) ;
147
- if ( ! project ) {
148
- return ;
149
- }
150
-
151
- const buildTarget = project . targets . get ( 'build' ) ;
152
- if ( buildTarget ?. builder === Builders . Application ) {
153
- // Application builder configuration.
154
- const prodConfig = buildTarget . configurations ?. production ;
155
- if ( ! prodConfig ) {
156
- throw new SchematicsException (
157
- `A "production" configuration is not defined for the "build" builder.` ,
158
- ) ;
159
- }
160
-
161
- prodConfig . appShell = true ;
162
-
163
- return ;
164
- }
165
-
166
- // Webpack based builders configuration.
167
- // Validation of targets is handled already in the main function.
168
- // Duplicate keys means that we have configurations in both server and build builders.
169
- const serverConfigKeys = project . targets . get ( 'server' ) ?. configurations ?? { } ;
170
- const buildConfigKeys = project . targets . get ( 'build' ) ?. configurations ?? { } ;
171
-
172
- const configurationNames = Object . keys ( {
173
- ...serverConfigKeys ,
174
- ...buildConfigKeys ,
175
- } ) ;
176
-
177
- const configurations : Record < string , { } > = { } ;
178
- for ( const key of configurationNames ) {
179
- if ( ! serverConfigKeys [ key ] ) {
180
- context . logger . warn (
181
- `Skipped adding "${ key } " configuration to "app-shell" target as it's missing from "server" target.` ,
182
- ) ;
183
-
184
- continue ;
185
- }
186
-
187
- if ( ! buildConfigKeys [ key ] ) {
188
- context . logger . warn (
189
- `Skipped adding "${ key } " configuration to "app-shell" target as it's missing from "build" target.` ,
190
- ) ;
191
-
192
- continue ;
193
- }
194
-
195
- configurations [ key ] = {
196
- browserTarget : `${ options . project } :build:${ key } ` ,
197
- serverTarget : `${ options . project } :server:${ key } ` ,
198
- } ;
199
- }
200
-
201
- project . targets . add ( {
202
- name : 'app-shell' ,
203
- builder : Builders . AppShell ,
204
- defaultConfiguration : configurations [ 'production' ] ? 'production' : undefined ,
205
- options : {
206
- route : APP_SHELL_ROUTE ,
207
- } ,
208
- configurations,
209
- } ) ;
210
- } ) ;
211
- } ;
212
- }
213
-
214
142
function addRouterModule ( mainPath : string ) : Rule {
215
143
return ( host : Tree ) => {
216
144
const modulePath = getAppModulePath ( host , mainPath ) ;
@@ -313,6 +241,7 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
313
241
throw new SchematicsException ( `Cannot find "${ configFilePath } ".` ) ;
314
242
}
315
243
244
+ const recorder = host . beginUpdate ( configFilePath ) ;
316
245
let configSourceFile = getSourceFile ( host , configFilePath ) ;
317
246
if ( ! isImported ( configSourceFile , 'ROUTES' , '@angular/router' ) ) {
318
247
const routesChange = insertImport (
@@ -322,10 +251,8 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
322
251
'@angular/router' ,
323
252
) ;
324
253
325
- const recorder = host . beginUpdate ( configFilePath ) ;
326
254
if ( routesChange ) {
327
255
applyToUpdateRecorder ( recorder , [ routesChange ] ) ;
328
- host . commitUpdate ( recorder ) ;
329
256
}
330
257
}
331
258
@@ -340,45 +267,20 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
340
267
}
341
268
342
269
// Add route to providers literal.
343
- const newProvidersLiteral = ts . factory . updateArrayLiteralExpression ( providersLiteral , [
344
- ...providersLiteral . elements ,
345
- ts . factory . createObjectLiteralExpression (
346
- [
347
- ts . factory . createPropertyAssignment ( 'provide' , ts . factory . createIdentifier ( 'ROUTES' ) ) ,
348
- ts . factory . createPropertyAssignment ( 'multi' , ts . factory . createIdentifier ( 'true' ) ) ,
349
- ts . factory . createPropertyAssignment (
350
- 'useValue' ,
351
- ts . factory . createArrayLiteralExpression (
352
- [
353
- ts . factory . createObjectLiteralExpression (
354
- [
355
- ts . factory . createPropertyAssignment (
356
- 'path' ,
357
- ts . factory . createIdentifier ( `'${ APP_SHELL_ROUTE } '` ) ,
358
- ) ,
359
- ts . factory . createPropertyAssignment (
360
- 'component' ,
361
- ts . factory . createIdentifier ( 'AppShellComponent' ) ,
362
- ) ,
363
- ] ,
364
- true ,
365
- ) ,
366
- ] ,
367
- true ,
368
- ) ,
369
- ) ,
370
- ] ,
371
- true ,
372
- ) ,
373
- ] ) ;
374
-
375
- const recorder = host . beginUpdate ( configFilePath ) ;
376
270
recorder . remove ( providersLiteral . getStart ( ) , providersLiteral . getWidth ( ) ) ;
377
- const printer = ts . createPrinter ( ) ;
378
- recorder . insertRight (
379
- providersLiteral . getStart ( ) ,
380
- printer . printNode ( ts . EmitHint . Unspecified , newProvidersLiteral , configSourceFile ) ,
381
- ) ;
271
+ const updatedProvidersString = [
272
+ ...providersLiteral . elements . map ( ( element ) => ' ' + element . getText ( ) ) ,
273
+ ` {
274
+ provide: ROUTES,
275
+ multi: true,
276
+ useValue: [{
277
+ path: '${ APP_SHELL_ROUTE } ',
278
+ component: AppShellComponent
279
+ }]
280
+ }\n ` ,
281
+ ] ;
282
+
283
+ recorder . insertRight ( providersLiteral . getStart ( ) , `[\n${ updatedProvidersString . join ( ',\n' ) } ]` ) ;
382
284
383
285
// Add AppShellComponent import
384
286
const appShellImportChange = insertImport (
@@ -393,6 +295,52 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
393
295
} ;
394
296
}
395
297
298
+ function addServerRoutingConfig ( options : AppShellOptions ) : Rule {
299
+ return async ( host : Tree ) => {
300
+ const workspace = await getWorkspace ( host ) ;
301
+ const project = workspace . projects . get ( options . project ) ;
302
+ if ( ! project ) {
303
+ throw new SchematicsException ( `Project name "${ options . project } " doesn't not exist.` ) ;
304
+ }
305
+
306
+ const configFilePath = join ( project . sourceRoot ?? 'src' , 'app/app.routes.server.ts' ) ;
307
+ if ( ! host . exists ( configFilePath ) ) {
308
+ throw new SchematicsException ( `Cannot find "${ configFilePath } ".` ) ;
309
+ }
310
+
311
+ const sourceFile = getSourceFile ( host , configFilePath ) ;
312
+ const nodes = getSourceNodes ( sourceFile ) ;
313
+
314
+ // Find the serverRoutes variable declaration
315
+ const serverRoutesNode = nodes . find (
316
+ ( node ) =>
317
+ ts . isVariableDeclaration ( node ) &&
318
+ node . initializer &&
319
+ ts . isArrayLiteralExpression ( node . initializer ) &&
320
+ node . type &&
321
+ ts . isArrayTypeNode ( node . type ) &&
322
+ node . type . getText ( ) . includes ( 'ServerRoute' ) ,
323
+ ) as ts . VariableDeclaration | undefined ;
324
+
325
+ if ( ! serverRoutesNode ) {
326
+ throw new SchematicsException (
327
+ `Cannot find the "ServerRoute" configuration in "${ configFilePath } ".` ,
328
+ ) ;
329
+ }
330
+ const recorder = host . beginUpdate ( configFilePath ) ;
331
+ const arrayLiteral = serverRoutesNode . initializer as ts . ArrayLiteralExpression ;
332
+ const firstElementPosition =
333
+ arrayLiteral . elements [ 0 ] ?. getStart ( ) ?? arrayLiteral . getStart ( ) + 1 ;
334
+ const newRouteString = `{
335
+ path: '${ APP_SHELL_ROUTE } ',
336
+ renderMode: RenderMode.AppShell
337
+ },\n` ;
338
+ recorder . insertLeft ( firstElementPosition , newRouteString ) ;
339
+
340
+ host . commitUpdate ( recorder ) ;
341
+ } ;
342
+ }
343
+
396
344
export default function ( options : AppShellOptions ) : Rule {
397
345
return async ( tree ) => {
398
346
const browserEntryPoint = await getMainFilePath ( tree , options . project ) ;
@@ -401,9 +349,9 @@ export default function (options: AppShellOptions): Rule {
401
349
return chain ( [
402
350
validateProject ( browserEntryPoint ) ,
403
351
schematic ( 'server' , options ) ,
404
- addAppShellConfigToWorkspace ( options ) ,
405
352
isStandalone ? noop ( ) : addRouterModule ( browserEntryPoint ) ,
406
353
isStandalone ? addStandaloneServerRoute ( options ) : addServerRoutes ( options ) ,
354
+ addServerRoutingConfig ( options ) ,
407
355
schematic ( 'component' , {
408
356
name : 'app-shell' ,
409
357
module : 'app.module.server.ts' ,
0 commit comments