feat(medusa, modules-sdk, types, utils): Re work modules loading and remove legacy functions (#5496)

This commit is contained in:
Adrien de Peretti
2023-11-02 17:59:13 +01:00
committed by GitHub
parent ca411e54eb
commit 154c9b43bd
39 changed files with 616 additions and 393 deletions

View File

@@ -3,6 +3,5 @@ export * from "./definitions"
export * from "./loaders"
export * from "./medusa-app"
export * from "./medusa-module"
export * from "./module-helper"
export * from "./remote-link"
export * from "./remote-query"

View File

@@ -4,8 +4,8 @@ import {
MODULE_SCOPE,
ModuleDefinition,
} from "@medusajs/types"
import MODULE_DEFINITIONS from "../../definitions"
import { registerModules } from "../register-modules"
import { ModulesDefinition } from "../../definitions"
import { registerMedusaModule } from "../register-modules"
const RESOLVED_PACKAGE = "@medusajs/test-service-resolved"
jest.mock("resolve-cwd", () => jest.fn(() => RESOLVED_PACKAGE))
@@ -30,13 +30,18 @@ describe("module definitions loader", () => {
jest.clearAllMocks()
// Clear module definitions
MODULE_DEFINITIONS.splice(0, MODULE_DEFINITIONS.length)
const allProperties = Object.getOwnPropertyNames(ModulesDefinition)
allProperties.forEach((property) => {
delete ModulesDefinition[property]
})
})
it("Resolves module with default definition given empty config", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition })
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({})
const res = registerMedusaModule(defaultDefinition.key)
expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({
@@ -53,9 +58,11 @@ describe("module definitions loader", () => {
describe("boolean config", () => {
it("Resolves module with no resolution path when given false", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition })
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({ [defaultDefinition.key]: false })
const res = registerMedusaModule(defaultDefinition.key, false)
expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({
@@ -68,10 +75,12 @@ describe("module definitions loader", () => {
it("Fails to resolve module with no resolution path when given false for a required module", () => {
expect.assertions(1)
MODULE_DEFINITIONS.push({ ...defaultDefinition, isRequired: true })
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: { ...defaultDefinition, isRequired: true },
})
try {
registerModules({ [defaultDefinition.key]: false })
registerMedusaModule(defaultDefinition.key, false)
} catch (err) {
expect(err.message).toEqual(
`Module: ${defaultDefinition.label} is required`
@@ -87,9 +96,11 @@ describe("module definitions loader", () => {
isRequired: true,
}
MODULE_DEFINITIONS.push(definition)
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: definition,
})
const res = registerModules({})
const res = registerMedusaModule(defaultDefinition.key)
expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({
@@ -106,12 +117,15 @@ describe("module definitions loader", () => {
describe("string config", () => {
it("Resolves module with default definition given empty config", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition })
const res = registerModules({
[defaultDefinition.key]: defaultDefinition.defaultPackage,
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerMedusaModule(
defaultDefinition.key,
defaultDefinition.defaultPackage
)
expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({
resolutionPath: RESOLVED_PACKAGE,
@@ -128,16 +142,16 @@ describe("module definitions loader", () => {
describe("object config", () => {
it("Resolves resolution path and provides empty options when none are provided", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition })
const res = registerModules({
[defaultDefinition.key]: {
scope: MODULE_SCOPE.INTERNAL,
resolve: defaultDefinition.defaultPackage,
resources: MODULE_RESOURCE_TYPE.ISOLATED,
} as InternalModuleDeclaration,
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerMedusaModule(defaultDefinition.key, {
scope: MODULE_SCOPE.INTERNAL,
resolve: defaultDefinition.defaultPackage,
resources: MODULE_RESOURCE_TYPE.ISOLATED,
} as InternalModuleDeclaration)
expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({
resolutionPath: RESOLVED_PACKAGE,
@@ -153,12 +167,12 @@ describe("module definitions loader", () => {
})
it("Resolves default resolution path and provides options when only options are provided", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition })
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({
[defaultDefinition.key]: {
options: { test: 123 },
},
const res = registerMedusaModule(defaultDefinition.key, {
options: { test: 123 },
} as any)
expect(res[defaultDefinition.key]).toEqual(
@@ -176,15 +190,15 @@ describe("module definitions loader", () => {
})
it("Resolves resolution path and provides options when only options are provided", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition })
Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({
[defaultDefinition.key]: {
resolve: defaultDefinition.defaultPackage,
options: { test: 123 },
scope: "internal",
resources: "isolated",
},
const res = registerMedusaModule(defaultDefinition.key, {
resolve: defaultDefinition.defaultPackage,
options: { test: 123 },
scope: "internal",
resources: "isolated",
} as any)
expect(res[defaultDefinition.key]).toEqual(

View File

@@ -1,17 +1,14 @@
import {
Logger,
MODULE_SCOPE,
MedusaContainer,
MODULE_SCOPE,
ModuleResolution,
} from "@medusajs/types"
import { asValue } from "awilix"
import { EOL } from "os"
import { ModulesHelper } from "../module-helper"
import { loadInternalModule } from "./utils"
export const moduleHelper = new ModulesHelper()
export const moduleLoader = async ({
container,
moduleResolutions,
@@ -38,17 +35,6 @@ export const moduleLoader = async ({
)
}
}
moduleHelper.setModules(
Object.entries(moduleResolutions).reduce((acc, [k, v]) => {
if (v.resolutionPath) {
acc[k] = v
}
return acc
}, {})
)
container.register("modulesHelper", asValue(moduleHelper))
}
async function loadModule(

View File

@@ -9,57 +9,11 @@ import {
import { isObject } from "@medusajs/utils"
import resolveCwd from "resolve-cwd"
import { MODULE_DEFINITIONS, ModulesDefinition } from "../definitions"
/**
*
* @param modules
* @param isolatedModules Will be removed once the isolated flag is being removed
*/
// TODO: Remove once we have all modules migrated + rename to something like getResolutions
export const registerModules = (
modules?: Record<
string,
| false
| string
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
>,
{ loadLegacyOnly } = { loadLegacyOnly: false }
): Record<string, ModuleResolution> => {
const moduleResolutions = {} as Record<string, ModuleResolution>
const projectModules = modules ?? {}
for (const definition of MODULE_DEFINITIONS) {
// Skip non legacy modules
if (loadLegacyOnly && !definition.isLegacy) {
continue
}
const customConfig = projectModules[definition.key]
const canSkip =
!customConfig && !definition.isRequired && !definition.defaultPackage
const isObj = isObject(customConfig)
if (isObj && customConfig.scope === MODULE_SCOPE.EXTERNAL) {
// TODO: getExternalModuleResolution(...)
if (!canSkip) {
throw new Error("External Modules are not supported yet.")
}
}
moduleResolutions[definition.key] = getInternalModuleResolution(
definition,
customConfig as InternalModuleDeclaration
)
}
return moduleResolutions
}
import { ModulesDefinition } from "../definitions"
export const registerMedusaModule = (
moduleKey: string,
moduleDeclaration:
moduleDeclaration?:
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
| string
| false,
@@ -74,9 +28,17 @@ export const registerMedusaModule = (
throw new Error(`Module: ${moduleKey} is not defined.`)
}
const modDeclaration =
moduleDeclaration ??
(modDefinition?.defaultModuleDeclaration as InternalModuleDeclaration)
if (modDeclaration !== false && !modDeclaration) {
throw new Error(`Module: ${moduleKey} has no declaration.`)
}
if (
isObject(moduleDeclaration) &&
moduleDeclaration?.scope === MODULE_SCOPE.EXTERNAL
isObject(modDeclaration) &&
modDeclaration?.scope === MODULE_SCOPE.EXTERNAL
) {
// TODO: getExternalModuleResolution(...)
throw new Error("External Modules are not supported yet.")

View File

@@ -1,10 +1,8 @@
import {
Constructor,
InternalModuleDeclaration,
Logger,
MODULE_RESOURCE_TYPE,
MODULE_SCOPE,
MedusaContainer,
MODULE_RESOURCE_TYPE,
ModuleExports,
ModuleResolution,
} from "@medusajs/types"
@@ -65,18 +63,6 @@ export async function loadInternalModule(
}
}
if (
scope === MODULE_SCOPE.INTERNAL &&
resources === MODULE_RESOURCE_TYPE.SHARED
) {
const moduleModels = loadedModule?.models || null
if (moduleModels) {
moduleModels.map((val: Constructor<unknown>) => {
container.registerAdd("db_entities", asValue(val))
})
}
}
const localContainer = createMedusaContainer()
const dependencies = resolution?.dependencies ?? []

View File

@@ -40,8 +40,8 @@ export type RunMigrationFn = (
export type MedusaModuleConfig = {
[key: string | Modules]:
| boolean
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
| true
}
export type SharedResources = {

View File

@@ -1,16 +0,0 @@
import { ModuleResolution, ModulesResponse } from "@medusajs/types"
export class ModulesHelper {
private modules_: Record<string, ModuleResolution> = {}
setModules(modules: Record<string, ModuleResolution>) {
this.modules_ = modules
}
get modules(): ModulesResponse {
return Object.values(this.modules_ || {}).map((value) => ({
module: value.definition.key,
resolution: value.resolutionPath,
}))
}
}