@@ -29,8 +29,7 @@ import {
2929import { applyToUpdateRecorder } from '../utility/change' ;
3030import { getAppModulePath , isStandaloneApp } from '../utility/ng-ast-utils' ;
3131import { 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' ;
3433import { Schema as AppShellOptions } from './schema' ;
3534
3635const APP_SHELL_ROUTE = 'shell' ;
@@ -140,77 +139,6 @@ function validateProject(mainPath: string): Rule {
140139 } ;
141140}
142141
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-
214142function addRouterModule ( mainPath : string ) : Rule {
215143 return ( host : Tree ) => {
216144 const modulePath = getAppModulePath ( host , mainPath ) ;
@@ -313,6 +241,7 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
313241 throw new SchematicsException ( `Cannot find "${ configFilePath } ".` ) ;
314242 }
315243
244+ const recorder = host . beginUpdate ( configFilePath ) ;
316245 let configSourceFile = getSourceFile ( host , configFilePath ) ;
317246 if ( ! isImported ( configSourceFile , 'ROUTES' , '@angular/router' ) ) {
318247 const routesChange = insertImport (
@@ -322,10 +251,8 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
322251 '@angular/router' ,
323252 ) ;
324253
325- const recorder = host . beginUpdate ( configFilePath ) ;
326254 if ( routesChange ) {
327255 applyToUpdateRecorder ( recorder , [ routesChange ] ) ;
328- host . commitUpdate ( recorder ) ;
329256 }
330257 }
331258
@@ -340,45 +267,20 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
340267 }
341268
342269 // 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 ) ;
376270 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' ) } ]` ) ;
382284
383285 // Add AppShellComponent import
384286 const appShellImportChange = insertImport (
@@ -393,6 +295,52 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
393295 } ;
394296}
395297
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+
396344export default function ( options : AppShellOptions ) : Rule {
397345 return async ( tree ) => {
398346 const browserEntryPoint = await getMainFilePath ( tree , options . project ) ;
@@ -401,9 +349,9 @@ export default function (options: AppShellOptions): Rule {
401349 return chain ( [
402350 validateProject ( browserEntryPoint ) ,
403351 schematic ( 'server' , options ) ,
404- addAppShellConfigToWorkspace ( options ) ,
405352 isStandalone ? noop ( ) : addRouterModule ( browserEntryPoint ) ,
406353 isStandalone ? addStandaloneServerRoute ( options ) : addServerRoutes ( options ) ,
354+ addServerRoutingConfig ( options ) ,
407355 schematic ( 'component' , {
408356 name : 'app-shell' ,
409357 module : 'app.module.server.ts' ,
0 commit comments