diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/config/src/providers/route.provider.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/config/src/providers/route.provider.ts.template index 91b2d7545c..c890db7305 100644 --- a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/config/src/providers/route.provider.ts.template +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/config/src/providers/route.provider.ts.template @@ -1,7 +1,12 @@ -import { APP_INITIALIZER, Provider } from '@angular/core'; import { eLayoutType, RoutesService } from '@abp/ng.core'; import { e<%= pascal(libraryName) %>RouteNames } from '../enums/route-names'; -import { makeEnvironmentProviders, provideAppInitializer, inject } from '@angular/core'; +import { makeEnvironmentProviders, provideAppInitializer, inject, EnvironmentProviders } from '@angular/core'; + +export const <%= macro(libraryName) %>_ROUTE_PROVIDERS = [ + provideAppInitializer(() => { + configureRoutes(); + }), +]; export function configureRoutes() { const routes = inject(RoutesService); @@ -16,10 +21,10 @@ export function configureRoutes() { ]); } +export const <%= macro(libraryName) %>_PROVIDERS: EnvironmentProviders[] = [ + ...<%= macro(libraryName) %>_ROUTE_PROVIDERS, +]; + export function provide<%= pascal(libraryName) %>Config() { - return makeEnvironmentProviders([ - provideAppInitializer(() => { - configureRoutes(); - }), - ]); + return makeEnvironmentProviders(<%= macro(libraryName) %>_PROVIDERS); } diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/__libraryName@kebab__-routing.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/__libraryName@kebab__.routes.ts.template similarity index 77% rename from npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/__libraryName@kebab__-routing.ts.template rename to npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/__libraryName@kebab__.routes.ts.template index fba42c7882..4fb52f8259 100644 --- a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/__libraryName@kebab__-routing.ts.template +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/__libraryName@kebab__.routes.ts.template @@ -1,6 +1,6 @@ import { Routes } from '@angular/router'; -export const <%= pascal(libraryName) %>Routes: Routes = [ +export const <%= macro(libraryName) %>_ROUTES: Routes = [ { path: '', loadComponent: () => diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/index.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/index.ts.template index aee9705b6f..b954dd6be0 100644 --- a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/index.ts.template +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package-standalone/__libraryName@kebab__/src/lib/index.ts.template @@ -1 +1 @@ -export * from './<%= kebab(libraryName) %>-routing'; +export * from './<%= kebab(libraryName) %>.routes'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts b/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts index 0370640f05..4d3927f015 100644 --- a/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts @@ -16,9 +16,11 @@ import { addRootProvider, addRouteDeclarationToModule, applyWithOverwrite, + findAppRoutesModulePath, findAppRoutesPath, getFirstApplication, getWorkspace, + hasImportInNgModule, hasProviderInStandaloneAppConfig, InsertChange, interpolate, @@ -26,6 +28,7 @@ import { isStandaloneApp, JSONFile, kebab, + macro, pascal, resolveProject, updateWorkspace, @@ -222,17 +225,29 @@ export function importConfigModuleToDefaultProjectAppModule( ) { return async (tree: Tree) => { const projectName = getFirstApplication(tree).name!; + const mainFilePath = await getMainFilePath(tree, projectName); + const isSourceStandalone = isStandaloneApp(tree, mainFilePath); const rules: Rule[] = []; + const providerAlreadyExists = isSourceStandalone + ? await hasProviderInStandaloneAppConfig( + tree, + projectName, + `provide${pascal(packageName)}Config`, + ) + : await hasImportInNgModule( + tree, + projectName, + options.templateType === 'standalone' + ? `provide${pascal(packageName)}Config` + : `${pascal(packageName)}ConfigModule`, + options.templateType === 'standalone' ? 'providers' : 'imports', + ); + if (providerAlreadyExists) { + return; + } + if (options.templateType === 'standalone') { - const providerAlreadyExists = await hasProviderInStandaloneAppConfig( - tree, - projectName, - `provide${pascal(packageName)}Config`, - ); - if (providerAlreadyExists) { - return; - } rules.push( addRootProvider(projectName, code => { const configFn = code.external( @@ -269,6 +284,7 @@ export function addRoutingToAppRoutingModule( const isSourceStandalone = isStandaloneApp(tree, mainFilePath); const pascalName = pascal(packageName); + const macroName = macro(packageName); const routePath = `${kebab(packageName)}`; const moduleName = `${pascalName}Module`; @@ -284,7 +300,7 @@ export function addRoutingToAppRoutingModule( const source = ts.createSourceFile(appRoutesPath, content, ts.ScriptTarget.Latest, true); const routeExpr = options.templateType === 'standalone' - ? `() => import('${routePath}').then(m => m.${pascalName}Routes)` + ? `() => import('${routePath}').then(m => m.${macroName}_ROUTES)` : `() => import('${routePath}').then(m => m.${moduleName}.forLazy())`; const routeToAdd = `{ path: '${routePath}', loadChildren: ${routeExpr} }`; const change = addRouteToRoutesArray(source, 'routes', routeToAdd); @@ -295,7 +311,12 @@ export function addRoutingToAppRoutingModule( tree.commitUpdate(recorder); } } else { - const appRoutingModulePath = `${project?.sourceRoot}/app/app-routing.module.ts`; + const appRoutingModulePath = await findAppRoutesModulePath(tree, mainFilePath); + + if (!appRoutingModulePath) { + throw new SchematicsException(`Cannot find routing module: ${appRoutingModulePath}`); + } + const appRoutingModule = tree.read(appRoutingModulePath); if (!appRoutingModule) { return; @@ -313,7 +334,7 @@ export function addRoutingToAppRoutingModule( ); const importStatement = options.templateType === 'standalone' - ? `() => import('${routePath}').then(m => m.${pascalName}Routes)` + ? `() => import('${routePath}').then(m => m.${macroName}_ROUTES)` : `() => import('${routePath}').then(m => m.${moduleName}.forLazy())`; const routeDefinition = `{ path: '${routePath}', loadChildren: ${importStatement} }`; const change = addRouteDeclarationToModule(source, routePath, routeDefinition); @@ -339,7 +360,7 @@ export function addRouteToRoutesArray( stmt.declarationList.declarations.some( decl => ts.isVariableDeclaration(decl) && - decl.name.getText() === arrayName && + (decl.name.getText() === arrayName || decl.name.getText() === arrayName.toUpperCase()) && decl.initializer !== undefined && ts.isArrayLiteralExpression(decl.initializer), ), diff --git a/npm/ng-packs/packages/schematics/src/utils/ng-module.ts b/npm/ng-packs/packages/schematics/src/utils/ng-module.ts index ac960cd8d0..30dafd427b 100644 --- a/npm/ng-packs/packages/schematics/src/utils/ng-module.ts +++ b/npm/ng-packs/packages/schematics/src/utils/ng-module.ts @@ -3,6 +3,8 @@ import { getMainFilePath } from './angular/standalone/util'; import * as ts from 'typescript'; import { getAppModulePath, getDecoratorMetadata, getMetadataField } from './angular'; import { createSourceFile } from '../commands/change-theme/index'; +import { normalize, Path } from '@angular-devkit/core'; +import * as path from 'path'; export const hasImportInNgModule = async ( host: Tree, @@ -46,3 +48,53 @@ export const hasImportInNgModule = async ( return elements.some(f => f.getText().match(metadataFn)); }; + +export async function findAppRoutesModulePath( + tree: Tree, + mainFilePath: string, +): Promise { + const appModulePath = getAppModulePath(tree, mainFilePath); + if (!appModulePath || !tree.exists(appModulePath)) return null; + + const buffer = tree.read(appModulePath); + if (!buffer) return null; + + const source = ts.createSourceFile( + appModulePath, + buffer.toString('utf-8'), + ts.ScriptTarget.Latest, + true, + ); + + for (const stmt of source.statements) { + if (!ts.isImportDeclaration(stmt)) continue; + + const importClause = stmt.importClause; + if (!importClause?.namedBindings || !ts.isNamedImports(importClause.namedBindings)) continue; + + const isRoutesImport = importClause.namedBindings.elements.some( + el => el.name.getText() === 'AppRoutingModule', + ); + if (!isRoutesImport || !ts.isStringLiteral(stmt.moduleSpecifier)) continue; + + let importPath = stmt.moduleSpecifier.text; + + if (!importPath.endsWith('.ts')) { + importPath += '.ts'; + } + + const configDir = path.dirname(appModulePath); + const resolvedFsPath = path.resolve(configDir, importPath); + const workspaceRelativePath = path.relative(process.cwd(), resolvedFsPath).replace(/\\/g, '/'); + + const normalizedPath = normalize(workspaceRelativePath); + + if (!tree.exists(normalizedPath)) { + throw new Error(`Cannot find routes file: ${normalizedPath}`); + } + + return normalizedPath; + } + + return null; +}