From 44bad004e1e060dcee2b4ac955a7f02664641f33 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Wed, 19 Mar 2025 12:03:24 +0000 Subject: [PATCH] fix(@schematics/angular): ensure app-shell schematic consistently uses `withAppShell` Previously, Webpack-based builders did not utilize this option. --- .../schematics/angular/app-shell/index.ts | 140 +----------------- packages/schematics/angular/server/index.ts | 2 - 2 files changed, 2 insertions(+), 140 deletions(-) diff --git a/packages/schematics/angular/app-shell/index.ts b/packages/schematics/angular/app-shell/index.ts index 66e188c4e45d..6e4c11181002 100644 --- a/packages/schematics/angular/app-shell/index.ts +++ b/packages/schematics/angular/app-shell/index.ts @@ -6,34 +6,23 @@ * found in the LICENSE file at https://angular.dev/license */ -import { - Rule, - SchematicsException, - Tree, - chain, - noop, - schematic, -} from '@angular-devkit/schematics'; +import { Rule, SchematicsException, Tree, chain, schematic } from '@angular-devkit/schematics'; import { dirname, join } from 'node:path/posix'; import ts from '../third_party/github.com/Microsoft/TypeScript/lib/typescript'; import { - addSymbolToNgModuleMetadata, findNode, findNodes, getDecoratorMetadata, getSourceNodes, insertImport, - isImported, } from '../utility/ast-utils'; import { applyToUpdateRecorder } from '../utility/change'; import { getAppModulePath, isStandaloneApp } from '../utility/ng-ast-utils'; -import { isUsingApplicationBuilder, targetBuildNotFoundError } from '../utility/project-targets'; +import { targetBuildNotFoundError } from '../utility/project-targets'; import { findBootstrapApplicationCall, getMainFilePath } from '../utility/standalone/util'; import { getWorkspace } from '../utility/workspace'; import { Schema as AppShellOptions } from './schema'; -const APP_SHELL_ROUTE = 'shell'; - function getSourceFile(host: Tree, path: string): ts.SourceFile { const content = host.readText(path); const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true); @@ -156,126 +145,6 @@ function getMetadataProperty(metadata: ts.Node, propertyName: string): ts.Proper return property; } -function addServerRoutes(options: AppShellOptions): Rule { - return async (host: Tree) => { - // The workspace gets updated so this needs to be reloaded - const workspace = await getWorkspace(host); - const project = workspace.projects.get(options.project); - if (!project) { - throw new SchematicsException(`Invalid project name (${options.project})`); - } - - const modulePath = getServerModulePath(host, project.sourceRoot || 'src', 'main.server.ts'); - if (modulePath === null) { - throw new SchematicsException('Server module not found.'); - } - - let moduleSource = getSourceFile(host, modulePath); - if (!isImported(moduleSource, 'Routes', '@angular/router')) { - const recorder = host.beginUpdate(modulePath); - const routesChange = insertImport(moduleSource, modulePath, 'Routes', '@angular/router'); - if (routesChange) { - applyToUpdateRecorder(recorder, [routesChange]); - } - - const imports = getSourceNodes(moduleSource) - .filter((node) => node.kind === ts.SyntaxKind.ImportDeclaration) - .sort((a, b) => a.getStart() - b.getStart()); - const insertPosition = imports[imports.length - 1].getEnd(); - const routeText = `\n\nconst routes: Routes = [ { path: '${APP_SHELL_ROUTE}', component: AppShell }];`; - recorder.insertRight(insertPosition, routeText); - host.commitUpdate(recorder); - } - - moduleSource = getSourceFile(host, modulePath); - if (!isImported(moduleSource, 'RouterModule', '@angular/router')) { - const recorder = host.beginUpdate(modulePath); - const routerModuleChange = insertImport( - moduleSource, - modulePath, - 'RouterModule', - '@angular/router', - ); - - if (routerModuleChange) { - applyToUpdateRecorder(recorder, [routerModuleChange]); - } - - const metadataChange = addSymbolToNgModuleMetadata( - moduleSource, - modulePath, - 'imports', - 'RouterModule.forRoot(routes)', - ); - if (metadataChange) { - applyToUpdateRecorder(recorder, metadataChange); - } - host.commitUpdate(recorder); - } - }; -} - -function addStandaloneServerRoute(options: AppShellOptions): Rule { - return async (host: Tree) => { - const workspace = await getWorkspace(host); - const project = workspace.projects.get(options.project); - if (!project) { - throw new SchematicsException(`Project name "${options.project}" doesn't not exist.`); - } - - const configFilePath = join(project.sourceRoot ?? 'src', 'app/app.config.server.ts'); - if (!host.exists(configFilePath)) { - throw new SchematicsException(`Cannot find "${configFilePath}".`); - } - - const recorder = host.beginUpdate(configFilePath); - let configSourceFile = getSourceFile(host, configFilePath); - if (!isImported(configSourceFile, 'ROUTES', '@angular/router')) { - const routesChange = insertImport( - configSourceFile, - configFilePath, - 'ROUTES', - '@angular/router', - ); - - if (routesChange) { - applyToUpdateRecorder(recorder, [routesChange]); - } - } - - configSourceFile = getSourceFile(host, configFilePath); - const providersLiteral = findNodes(configSourceFile, ts.isPropertyAssignment).find( - (n) => ts.isArrayLiteralExpression(n.initializer) && n.name.getText() === 'providers', - )?.initializer as ts.ArrayLiteralExpression | undefined; - if (!providersLiteral) { - throw new SchematicsException( - `Cannot find the "providers" configuration in "${configFilePath}".`, - ); - } - - // Add route to providers literal. - recorder.remove(providersLiteral.getStart(), providersLiteral.getWidth()); - const updatedProvidersString = [ - ...providersLiteral.elements.map((element) => ' ' + element.getText()), - ` { - provide: ROUTES, - multi: true, - useValue: [{ - path: '${APP_SHELL_ROUTE}', - component: AppShell - }] - }\n `, - ]; - - recorder.insertRight(providersLiteral.getStart(), `[\n${updatedProvidersString.join(',\n')}]`); - - applyToUpdateRecorder(recorder, [ - insertImport(configSourceFile, configFilePath, 'AppShell', './app-shell/app-shell'), - ]); - host.commitUpdate(recorder); - }; -} - function addServerRoutingConfig(options: AppShellOptions, isStandalone: boolean): Rule { return async (host: Tree) => { const workspace = await getWorkspace(host); @@ -335,11 +204,6 @@ export default function (options: AppShellOptions): Rule { return chain([ validateProject(browserEntryPoint), schematic('server', options), - ...(isUsingApplicationBuilder(project) - ? [noop()] - : isStandalone - ? [addStandaloneServerRoute(options)] - : [addServerRoutes(options)]), addServerRoutingConfig(options, isStandalone), schematic('component', { name: 'app-shell', diff --git a/packages/schematics/angular/server/index.ts b/packages/schematics/angular/server/index.ts index 6467a1e532fe..1f8ccd7e85aa 100644 --- a/packages/schematics/angular/server/index.ts +++ b/packages/schematics/angular/server/index.ts @@ -14,10 +14,8 @@ import { apply, applyTemplates, chain, - filter, mergeWith, move, - noop, strings, url, } from '@angular-devkit/schematics';