diff --git a/packages/core/e2e/fixtures/test-plugins.ts b/packages/core/e2e/fixtures/test-plugins.ts index df23b68e38..5ed76b3e18 100644 --- a/packages/core/e2e/fixtures/test-plugins.ts +++ b/packages/core/e2e/fixtures/test-plugins.ts @@ -96,6 +96,26 @@ export class TestShopPluginResolver { }) export class TestAPIExtensionPlugin {} +@Resolver() +export class TestLazyResolver { + @Query() + lazy() { + return 'sleeping'; + } +} + +@VendurePlugin({ + shopApiExtensions: { + resolvers: () => [TestLazyResolver], + schema: () => gql` + extend type Query { + lazy: String! + } + `, + }, +}) +export class TestLazyExtensionPlugin {} + @Injectable() export class NameService { getNames(): string[] { diff --git a/packages/core/e2e/plugin.e2e-spec.ts b/packages/core/e2e/plugin.e2e-spec.ts index c98342e33f..c6ad0cef37 100644 --- a/packages/core/e2e/plugin.e2e-spec.ts +++ b/packages/core/e2e/plugin.e2e-spec.ts @@ -7,6 +7,7 @@ import { ConfigService } from '../src/config/config.service'; import { TEST_SETUP_TIMEOUT_MS } from './config/test-config'; import { TestAPIExtensionPlugin, + TestLazyExtensionPlugin, TestPluginWithAllLifecycleHooks, TestPluginWithConfigAndBootstrap, TestPluginWithProvider, @@ -41,6 +42,7 @@ describe('Plugins', () => { TestPluginWithConfigAndBootstrap.setup(bootstrapMockFn), TestAPIExtensionPlugin, TestPluginWithProvider, + TestLazyExtensionPlugin, ], }, ); @@ -85,6 +87,15 @@ describe('Plugins', () => { expect(result.baz).toEqual(['quux']); }); + it('allows lazy evaluation of API extension', async () => { + const result = await shopClient.query(gql` + query { + lazy + } + `); + expect(result.lazy).toEqual('sleeping'); + }); + it('generates ListQueryOptions for api extensions', async () => { const result = await adminClient.query(gql` query { diff --git a/packages/core/src/api/config/configure-graphql-module.ts b/packages/core/src/api/config/configure-graphql-module.ts index 41fae669bc..443ad6ece9 100644 --- a/packages/core/src/api/config/configure-graphql-module.ts +++ b/packages/core/src/api/config/configure-graphql-module.ts @@ -164,7 +164,7 @@ async function createGraphQLOptions( let schema = buildSchema(typeDefs); getPluginAPIExtensions(configService.plugins, apiType) - .map(e => e.schema) + .map(e => (typeof e.schema === 'function' ? e.schema() : e.schema)) .filter(notNullOrUndefined) .forEach(documentNode => (schema = extendSchema(schema, documentNode))); schema = generateListOptions(schema); diff --git a/packages/core/src/plugin/plugin-metadata.ts b/packages/core/src/plugin/plugin-metadata.ts index f749804845..29b39a6f7b 100644 --- a/packages/core/src/plugin/plugin-metadata.ts +++ b/packages/core/src/plugin/plugin-metadata.ts @@ -69,12 +69,16 @@ export function graphQLResolversFor( plugin: Type | DynamicModule, apiType: 'shop' | 'admin', ): Array> { - const apiExtensions = + const apiExtensions: APIExtensionDefinition = apiType === 'shop' ? reflectMetadata(plugin, PLUGIN_METADATA.SHOP_API_EXTENSIONS) : reflectMetadata(plugin, PLUGIN_METADATA.ADMIN_API_EXTENSIONS); - return apiExtensions ? apiExtensions.resolvers : []; + return apiExtensions + ? typeof apiExtensions.resolvers === 'function' + ? apiExtensions.resolvers() + : apiExtensions.resolvers + : []; } function reflectMetadata(metatype: Type | DynamicModule, metadataKey: string) { diff --git a/packages/core/src/plugin/vendure-plugin.ts b/packages/core/src/plugin/vendure-plugin.ts index 11a2764862..fbd6325f31 100644 --- a/packages/core/src/plugin/vendure-plugin.ts +++ b/packages/core/src/plugin/vendure-plugin.ts @@ -70,13 +70,13 @@ export interface APIExtensionDefinition { * }`; * ``` */ - schema?: DocumentNode; + schema?: DocumentNode | (() => DocumentNode); /** * @description * An array of resolvers for the schema extensions. Should be defined as [Nestjs GraphQL resolver](https://docs.nestjs.com/graphql/resolvers-map) * classes, i.e. using the Nest `\@Resolver()` decorator etc. */ - resolvers: Array>; + resolvers: Array> | (() => Array>); } /**