diff --git a/packages/ui-devkit/package.json b/packages/ui-devkit/package.json index 15485d6e52..dbf9828f13 100644 --- a/packages/ui-devkit/package.json +++ b/packages/ui-devkit/package.json @@ -52,6 +52,8 @@ "@rollup/plugin-node-resolve": "^15.2.1", "@types/fs-extra": "^11.0.1", "@vendure/core": "2.1.0-next.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "rimraf": "^3.0.2", "rollup": "^3.28.1", "rollup-plugin-terser": "^7.0.2", diff --git a/packages/ui-devkit/src/compiler/index.ts b/packages/ui-devkit/src/compiler/index.ts index 8069b608f0..48557f4ca9 100644 --- a/packages/ui-devkit/src/compiler/index.ts +++ b/packages/ui-devkit/src/compiler/index.ts @@ -1,4 +1,3 @@ export * from './compile'; export * from './helpers'; export * from './types'; -export * from './wrappers'; diff --git a/packages/ui-devkit/src/compiler/scaffold.ts b/packages/ui-devkit/src/compiler/scaffold.ts index 503c262fb4..fc2739f99e 100644 --- a/packages/ui-devkit/src/compiler/scaffold.ts +++ b/packages/ui-devkit/src/compiler/scaffold.ts @@ -19,7 +19,6 @@ import { Extension, GlobalStylesExtension, SassVariableOverridesExtension, - SharedUiProvidersExtension, StaticAssetExtension, } from './types'; import { @@ -28,7 +27,6 @@ import { isAdminUiExtension, isGlobalStylesExtension, isSassVariableOverridesExtension, - isSharedUiProvidersExtension, isStaticAssetExtension, isTranslationExtension, logger, @@ -39,10 +37,7 @@ import { export async function setupScaffold(outputPath: string, extensions: Extension[]) { deleteExistingExtensionModules(outputPath); - const adminUiExtensions = extensions.filter( - (e): e is AdminUiExtension | SharedUiProvidersExtension => - isAdminUiExtension(e) || isSharedUiProvidersExtension(e), - ); + const adminUiExtensions = extensions.filter((e): e is AdminUiExtension => isAdminUiExtension(e)); const normalizedExtensions = normalizeExtensions(adminUiExtensions); const modulePathMapping = generateModulePathMapping(normalizedExtensions); @@ -96,7 +91,6 @@ function generateModulePathMapping(extensions: AdminUiExtensionWithId[]) { */ async function copyExtensionModules(outputPath: string, extensions: AdminUiExtensionWithId[]) { const adminUiExtensions = extensions.filter(isAdminUiExtension); - const sharedUiProvidersExtensions = extensions.filter(isSharedUiProvidersExtension); const extensionRoutesSource = generateLazyExtensionRoutes(adminUiExtensions); fs.writeFileSync(path.join(outputPath, EXTENSION_ROUTES_FILE), extensionRoutesSource, 'utf8'); const sharedExtensionModulesSource = generateSharedExtensionModule(extensions); @@ -119,16 +113,6 @@ async function copyExtensionModules(outputPath: string, extensions: AdminUiExten filter: name => name === extension.extensionPath || exclude.every(e => e !== name), }); } - for (const extension of sharedUiProvidersExtensions) { - if (extension.sharedProviders) { - let i = 0; - for (const filePath of extension.sharedProviders) { - const dest = path.join(outputPath, MODULES_OUTPUT_DIR, `${extension.id}_${i}.ts`); - fs.copySync(filePath, dest); - i++; - } - } - } } async function copyStaticAssets(outputPath: string, extensions: Array>) { @@ -190,7 +174,7 @@ export async function copyGlobalStyleFile(outputPath: string, stylePath: string) function generateLazyExtensionRoutes(extensions: AdminUiExtensionWithId[]): string { const routes: string[] = []; for (const extension of extensions) { - for (const module of extension.ngModules) { + for (const module of extension.ngModules ?? []) { if (module.type === 'lazy') { routes.push(` { path: 'extensions/${module.route}', @@ -200,33 +184,38 @@ function generateLazyExtensionRoutes(extensions: AdminUiExtensionWithId[]): stri }`); } } + for (const route of extension.routes ?? []) { + routes.push(` { + path: 'extensions/${route.route}', + loadChildren: () => import('./extensions/${extension.id}/${path.basename(route.filePath, '.ts')}'), + }`); + } } return `export const extensionRoutes = [${routes.join(',\n')}];\n`; } -function generateSharedExtensionModule( - extensions: Array, -) { - const sharedProviderExtensions = extensions.filter((e): e is SharedUiProvidersExtension => - e.hasOwnProperty('sharedProviders'), - ); - const adminUiExtensions = extensions.filter((e): e is AdminUiExtensionWithId => - e.hasOwnProperty('extensionPath'), - ); +function generateSharedExtensionModule(extensions: AdminUiExtensionWithId[]) { + const adminUiExtensions = extensions.filter(isAdminUiExtension); return `import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; ${adminUiExtensions .map(e => e.ngModules - .filter(m => m.type === 'shared') + ?.filter(m => m.type === 'shared') .map(m => `import { ${m.ngModuleName} } from '${getModuleFilePath(e.id, m)}';\n`) .join(''), ) .join('')} -${sharedProviderExtensions +${adminUiExtensions .map((m, i) => - m.sharedProviders - .map((f, j) => `import SharedProviders_${i}_${j} from './extensions/${m.id}_${i}';\n`) + (m.sharedProviders ?? []) + .map( + (f, j) => + `import SharedProviders_${i}_${j} from './extensions/${m.id}/${path.basename( + f, + '.ts', + )}';\n`, + ) .join(''), ) .join('')} @@ -235,13 +224,13 @@ ${sharedProviderExtensions imports: [CommonModule, ${adminUiExtensions .map(e => e.ngModules - .filter(m => m.type === 'shared') + ?.filter(m => m.type === 'shared') .map(m => m.ngModuleName) .join(', '), ) .join(', ')}], - providers: [${sharedProviderExtensions - .map((m, i) => m.sharedProviders.map((f, j) => `...SharedProviders_${i}_${j}`)) + providers: [${adminUiExtensions + .map((m, i) => (m.sharedProviders ?? []).map((f, j) => `...SharedProviders_${i}_${j}`)) .join(', ')}], }) export class SharedExtensionsModule {} diff --git a/packages/ui-devkit/src/compiler/types.ts b/packages/ui-devkit/src/compiler/types.ts index 5aa754e46a..4abe418704 100644 --- a/packages/ui-devkit/src/compiler/types.ts +++ b/packages/ui-devkit/src/compiler/types.ts @@ -5,8 +5,7 @@ export type Extension = | TranslationExtension | StaticAssetExtension | GlobalStylesExtension - | SassVariableOverridesExtension - | SharedUiProvidersExtension; + | SassVariableOverridesExtension; /** * @description @@ -83,19 +82,6 @@ export interface SassVariableOverridesExtension { sassVariableOverrides: string; } -/** - * @description - * Defines an extension which contains only shared providers such as nav menu items, custom form inputs, - * custom detail components, action bar items, custom history entry components. - * - * @docsCategory UiDevkit - * @docsPage AdminUiExtension - */ -export interface SharedUiProvidersExtension { - id: string; - sharedProviders: string[]; -} - /** * @description * Defines extensions to the Admin UI application by specifying additional @@ -112,8 +98,7 @@ export interface SharedUiProvidersExtension { export interface AdminUiExtension extends Partial, Partial, - Partial, - Partial { + Partial { /** * @description * An optional ID for the extension module. Only used internally for generating @@ -132,8 +117,22 @@ export interface AdminUiExtension /** * @description * One or more Angular modules which extend the default Admin UI. + * + * @deprecated use `routes` instead of lazy modules, and `sharedProviders` instead of shared modules. */ - ngModules: Array; + ngModules?: Array; + + /** + * @description + * Defines an extension which contains only shared providers such as nav menu items, custom form inputs, + * custom detail components, action bar items, custom history entry components. + */ + sharedProviders?: string[]; + + routes?: Array<{ + route: string; + filePath: string; + }>; /** * @description diff --git a/packages/ui-devkit/src/compiler/utils.ts b/packages/ui-devkit/src/compiler/utils.ts index 3ade282f18..59d8c33ecb 100644 --- a/packages/ui-devkit/src/compiler/utils.ts +++ b/packages/ui-devkit/src/compiler/utils.ts @@ -12,7 +12,6 @@ import { Extension, GlobalStylesExtension, SassVariableOverridesExtension, - SharedUiProvidersExtension, StaticAssetDefinition, StaticAssetExtension, TranslationExtension, @@ -80,9 +79,7 @@ export async function copyStaticAsset(outputPath: string, staticAssetDef: Static * If not defined by the user, a deterministic ID is generated * from a hash of the extension config. */ -export function normalizeExtensions( - extensions?: Array, -): AdminUiExtensionWithId[] { +export function normalizeExtensions(extensions?: AdminUiExtension[]): AdminUiExtensionWithId[] { return (extensions || []).map(e => { let id = e.id; if (!id) { @@ -95,8 +92,6 @@ export function normalizeExtensions( staticAssets: [], translations: {}, globalStyles: [], - extensionPath: '', - ngModules: [], ...e, id, }; @@ -107,10 +102,6 @@ export function isAdminUiExtension(input: Extension): input is AdminUiExtension return input.hasOwnProperty('extensionPath'); } -export function isSharedUiProvidersExtension(input: Extension): input is SharedUiProvidersExtension { - return input.hasOwnProperty('sharedProviders'); -} - export function isTranslationExtension(input: Extension): input is TranslationExtension { return input.hasOwnProperty('translations'); } diff --git a/packages/ui-devkit/src/compiler/wrappers.ts b/packages/ui-devkit/src/compiler/wrappers.ts deleted file mode 100644 index 108b3a320d..0000000000 --- a/packages/ui-devkit/src/compiler/wrappers.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { normalizeString } from '@vendure/common/lib/normalize-string'; -import path from 'path'; - -import { SharedUiProvidersExtension } from './types'; - -export function uiExtensions(options: { id?: string; files: string | string[] }): SharedUiProvidersExtension { - const files = Array.isArray(options.files) ? options.files : [options.files]; - return { - id: options.id || getIdFromFilePath(files[0]), - sharedProviders: files, - }; -} - -function getIdFromFilePath(filePath: string): string { - const { dir, name } = path.parse(filePath); - const parts = safelySplitFilePath(dir).slice(-3); - const id = normalizeString([...parts, name].join('_'), '_'); - return id; -} - -function safelySplitFilePath(filePath: string) { - try { - const normalizedPath = path.normalize(filePath); - const directoryParts = normalizedPath.split(path.sep); - return directoryParts.filter(part => part !== '.' && part !== '..'); - } catch (error) { - // eslint-disable-next-line no-console - console.error('An error occurred while splitting the file path:', error); - return []; - } -}