diff --git a/packages/ui-devkit/scaffold/src/app.routes.ts b/packages/ui-devkit/scaffold/src/app.routes.ts index a6074e326c..7b34d93ac2 100644 --- a/packages/ui-devkit/scaffold/src/app.routes.ts +++ b/packages/ui-devkit/scaffold/src/app.routes.ts @@ -14,6 +14,10 @@ export const routes: Route[] = [ breadcrumb: _('breadcrumb.dashboard'), }, children: [ + // Defining the extension routes before the built-in routes allows + // the extension routes to take precedence over the built-in routes, enabling + // the extensions to override built-in functionality. + ...extensionRoutes, { path: '', pathMatch: 'full', @@ -43,7 +47,6 @@ export const routes: Route[] = [ path: 'system', loadChildren: () => import('@vendure/admin-ui/system').then(m => m.SystemModule), }, - ...extensionRoutes, ], }, ]; diff --git a/packages/ui-devkit/src/compiler/scaffold.ts b/packages/ui-devkit/src/compiler/scaffold.ts index a97ee31cc1..d32a46a3fe 100644 --- a/packages/ui-devkit/src/compiler/scaffold.ts +++ b/packages/ui-devkit/src/compiler/scaffold.ts @@ -183,8 +183,9 @@ function generateLazyExtensionRoutes(extensions: AdminUiExtensionWithId[]): stri } } for (const route of extension.routes ?? []) { + const prefix = route.prefix === '' ? '' : `${route.prefix ?? 'extensions'}/`; routes.push(` { - path: 'extensions/${route.route}', + path: '${prefix}${route.route}', loadChildren: () => import('./extensions/${extension.id}/${path.basename(route.filePath, '.ts')}'), }`); } diff --git a/packages/ui-devkit/src/compiler/types.ts b/packages/ui-devkit/src/compiler/types.ts index 533d2e58db..10f980becd 100644 --- a/packages/ui-devkit/src/compiler/types.ts +++ b/packages/ui-devkit/src/compiler/types.ts @@ -136,8 +136,28 @@ export interface AdminUiExtension * relative to the `extensionPath` which exports an array of Angular route definitions. */ routes?: Array<{ + /** + * @description + * The name of the route. This will be used as the path in the URL. + */ route: string; + /** + * @description + * The path to the file which exports an array of Angular route definitions. + */ filePath: string; + /** + * @description + * All extensions will be mounted under the `/extensions/` route. This option allows you to specify a + * custom prefix rather than `/extensions/`. For example, setting this to `custom` would cause the extension + * to be mounted at `/custom/` instead. + * + * A common use case for this is to mount the extension at the root of the Admin UI, by setting this to an empty string. + * This is useful when the extension is intended to replace the default Admin UI, rather than extend it. + * + * @since 2.2.0 + */ + prefix?: string; }>; /**