From f8b4a651688a6bb66435598b55e34dcfc9629d30 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Thu, 23 May 2024 22:33:38 +0200 Subject: [PATCH] feat: Load custom link definitions (#7430) **What** Load custom links from the projects --- .../__tests__/resolve-plugins-links.spec.ts | 73 +++++++++++++++++++ .../loaders/helpers/resolve-plugins-links.ts | 49 +++++++++++++ packages/medusa/src/loaders/index.ts | 2 + packages/medusa/src/loaders/medusa-app.ts | 17 +++++ 4 files changed, 141 insertions(+) create mode 100644 packages/medusa/src/loaders/__tests__/resolve-plugins-links.spec.ts create mode 100644 packages/medusa/src/loaders/helpers/resolve-plugins-links.ts diff --git a/packages/medusa/src/loaders/__tests__/resolve-plugins-links.spec.ts b/packages/medusa/src/loaders/__tests__/resolve-plugins-links.spec.ts new file mode 100644 index 0000000000..3e82fa0942 --- /dev/null +++ b/packages/medusa/src/loaders/__tests__/resolve-plugins-links.spec.ts @@ -0,0 +1,73 @@ +import { mkdirSync, rmSync, writeFileSync } from "fs" +import { resolve } from "path" +import { resolvePluginsLinks } from "../helpers/resolve-plugins-links" +import { createMedusaContainer } from "@medusajs/utils" +import { asValue } from "awilix" + +const distTestTargetDirectorPath = resolve(__dirname, "__links__") + +const getFolderTestTargetDirectoryPath = (folderName: string): string => { + return resolve(distTestTargetDirectorPath, folderName) +} + +describe("resolve plugins links", () => { + beforeEach(() => { + jest.resetModules() + jest.clearAllMocks() + + rmSync(distTestTargetDirectorPath, { recursive: true, force: true }) + + mkdirSync(getFolderTestTargetDirectoryPath("links"), { + mode: "777", + recursive: true, + }) + }) + + afterAll(() => { + rmSync(distTestTargetDirectorPath, { recursive: true, force: true }) + }) + + it("should load the custom links from the links directory", async () => { + writeFileSync( + resolve(getFolderTestTargetDirectoryPath("links"), "link.js"), + ` + export default { + isLink: true + } + ` + ) + + writeFileSync( + resolve(getFolderTestTargetDirectoryPath("links"), "empty-link.js"), + ` + export default 'string' + ` + ) + + const loggerMock = { warn: jest.fn() } + const container = createMedusaContainer() + container.register({ + logger: asValue(loggerMock), + }) + + const links = await resolvePluginsLinks( + [ + { + resolve: distTestTargetDirectorPath, + }, + ], + container + ) + + expect(loggerMock.warn).toHaveBeenCalledTimes(1) + expect(loggerMock.warn).toHaveBeenCalledWith( + `Links file ${distTestTargetDirectorPath}/links/empty-link.js does not export a default object` + ) + + expect(links).toEqual([ + { + isLink: true, + }, + ]) + }) +}) diff --git a/packages/medusa/src/loaders/helpers/resolve-plugins-links.ts b/packages/medusa/src/loaders/helpers/resolve-plugins-links.ts new file mode 100644 index 0000000000..cd9e485e5a --- /dev/null +++ b/packages/medusa/src/loaders/helpers/resolve-plugins-links.ts @@ -0,0 +1,49 @@ +import { glob } from "glob" +import { + MedusaContainer, + ModuleJoinerConfig, + PluginDetails, +} from "@medusajs/types" +import { ContainerRegistrationKeys, isObject } from "@medusajs/utils" + +/** + * import files from the links directory to retrieve the links to be loaded + * @param plugins + * @param container + */ +export async function resolvePluginsLinks( + plugins: PluginDetails[], + container: MedusaContainer +): Promise { + const logger = + container.resolve(ContainerRegistrationKeys.LOGGER, { + allowUnregistered: true, + }) ?? console + return ( + await Promise.all( + plugins.map(async (pluginDetails) => { + const files = glob.sync( + `${pluginDetails.resolve}/links/*.{ts,js,mjs,mts}`, + { + ignore: ["**/*.d.ts", "**/*.map"], + } + ) + return ( + await Promise.all( + files.map(async (file) => { + const import_ = await import(file) + if (import_.default && !isObject(import_.default)) { + logger.warn( + `Links file ${file} does not export a default object` + ) + return + } + + return import_.default + }) + ) + ).filter(Boolean) + }) + ) + ).flat(Infinity) +} diff --git a/packages/medusa/src/loaders/index.ts b/packages/medusa/src/loaders/index.ts index df3b0f92ef..bcba11652d 100644 --- a/packages/medusa/src/loaders/index.ts +++ b/packages/medusa/src/loaders/index.ts @@ -19,6 +19,7 @@ import { SubscriberLoader } from "./helpers/subscribers" import Logger from "./logger" import loadMedusaApp from "./medusa-app" import registerPgConnection from "./pg-connection" +import { resolvePluginsLinks } from "./helpers/resolve-plugins-links" type Options = { directory: string @@ -138,6 +139,7 @@ export default async ({ onApplicationPrepareShutdown: medusaAppOnApplicationPrepareShutdown, } = await loadMedusaApp({ container, + linkModules: await resolvePluginsLinks(plugins, container), }) const entrypointsShutdown = await loadEntrypoints( diff --git a/packages/medusa/src/loaders/medusa-app.ts b/packages/medusa/src/loaders/medusa-app.ts index a2bf7b9429..95af463adc 100644 --- a/packages/medusa/src/loaders/medusa-app.ts +++ b/packages/medusa/src/loaders/medusa-app.ts @@ -2,6 +2,7 @@ import { MedusaApp, MedusaAppMigrateDown, MedusaAppMigrateUp, + MedusaAppOptions, MedusaAppOutput, ModulesDefinition, } from "@medusajs/modules-sdk" @@ -60,11 +61,13 @@ async function runMedusaAppMigrations({ configModule, container, revert = false, + linkModules, }: { configModule: { modules?: CommonTypes.ConfigModule["modules"] projectConfig: CommonTypes.ConfigModule["projectConfig"] } + linkModules?: MedusaAppOptions["linkModules"] container: MedusaContainer revert?: boolean }): Promise { @@ -93,6 +96,7 @@ async function runMedusaAppMigrations({ await MedusaAppMigrateDown({ modulesConfig: configModules, sharedContainer: container, + linkModules, sharedResourcesConfig, injectedDependencies, }) @@ -100,6 +104,7 @@ async function runMedusaAppMigrations({ await MedusaAppMigrateUp({ modulesConfig: configModules, sharedContainer: container, + linkModules, sharedResourcesConfig, injectedDependencies, }) @@ -108,6 +113,7 @@ async function runMedusaAppMigrations({ export async function migrateMedusaApp({ configModule, + linkModules, container, }: { configModule: { @@ -115,15 +121,18 @@ export async function migrateMedusaApp({ projectConfig: CommonTypes.ConfigModule["projectConfig"] } container: MedusaContainer + linkModules?: MedusaAppOptions["linkModules"] }): Promise { await runMedusaAppMigrations({ configModule, container, + linkModules, }) } export async function revertMedusaApp({ configModule, + linkModules, container, }: { configModule: { @@ -131,19 +140,23 @@ export async function revertMedusaApp({ projectConfig: CommonTypes.ConfigModule["projectConfig"] } container: MedusaContainer + linkModules?: MedusaAppOptions["linkModules"] }): Promise { await runMedusaAppMigrations({ configModule, container, revert: true, + linkModules, }) } export const loadMedusaApp = async ( { container, + linkModules, }: { container: MedusaContainer + linkModules?: MedusaAppOptions["linkModules"] }, config = { registerInContainer: true } ): Promise => { @@ -177,6 +190,7 @@ export const loadMedusaApp = async ( workerMode: configModule.projectConfig.worker_mode, modulesConfig: configModules, sharedContainer: container, + linkModules, sharedResourcesConfig, injectedDependencies, }) @@ -221,6 +235,7 @@ export const loadMedusaApp = async ( */ export async function runModulesLoader({ configModule, + linkModules, container, }: { configModule: { @@ -228,6 +243,7 @@ export async function runModulesLoader({ projectConfig: CommonTypes.ConfigModule["projectConfig"] } container: MedusaContainer + linkModules?: MedusaAppOptions["linkModules"] }): Promise { const injectedDependencies = { [ContainerRegistrationKeys.PG_CONNECTION]: container.resolve( @@ -251,6 +267,7 @@ export async function runModulesLoader({ await MedusaApp({ modulesConfig: configModules, sharedContainer: container, + linkModules, sharedResourcesConfig, injectedDependencies, loaderOnly: true,