Files
medusa-store/packages/modules-sdk/src/loaders/utils/load-internal.ts
Adrien de Peretti 379c83933e fix(module-sdk): Shared modules loading (#4611)
* WIP

* tests wording

* Create nasty-files-type.md

* cleanup
2023-07-27 12:53:31 +02:00

135 lines
3.6 KiB
TypeScript

import {
Constructor,
InternalModuleDeclaration,
Logger,
MedusaContainer,
MODULE_RESOURCE_TYPE,
MODULE_SCOPE,
ModuleExports,
ModuleResolution,
} from "@medusajs/types"
import { createMedusaContainer } from "@medusajs/utils"
import { asFunction, asValue } from "awilix"
export async function loadInternalModule(
container: MedusaContainer,
resolution: ModuleResolution,
logger: Logger
): Promise<{ error?: Error } | void> {
const registrationName = resolution.definition.registrationName
const { scope, resources } =
resolution.moduleDeclaration as InternalModuleDeclaration
let loadedModule: ModuleExports
try {
// When loading manually, we pass the exports to be loaded, meaning that we do not need to import the package to find
// the exports. This is useful when a package export an initialize function which will bootstrap itself and therefore
// does not need to import the package that is currently being loaded as it would create a
// circular reference.
loadedModule =
resolution.moduleExports ??
(await import(resolution.resolutionPath as string)).default
} catch (error) {
if (
resolution.definition.isRequired &&
resolution.definition.defaultPackage
) {
return {
error: new Error(
`Make sure you have installed the default package: ${resolution.definition.defaultPackage}`
),
}
}
return { error }
}
if (!loadedModule?.service) {
container.register({
[registrationName]: asValue(undefined),
})
return {
error: new Error(
"No service found in module. Make sure your module exports a service."
),
}
}
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 ?? []
if (resources === MODULE_RESOURCE_TYPE.SHARED) {
dependencies.push("manager", "configModule")
}
for (const dependency of dependencies) {
localContainer.register(
dependency,
asFunction(() => {
return container.resolve(dependency, { allowUnregistered: true })
})
)
}
const moduleLoaders = loadedModule?.loaders ?? []
try {
for (const loader of moduleLoaders) {
await loader(
{
container: localContainer,
logger,
options: resolution.options,
},
resolution.moduleDeclaration as InternalModuleDeclaration
)
}
} catch (err) {
container.register({
[registrationName]: asValue(undefined),
})
return {
error: new Error(
`Loaders for module ${resolution.definition.label} failed: ${err.message}`
),
}
}
const moduleService = loadedModule.service
container.register({
[registrationName]: asFunction((cradle) => {
return new moduleService(
localContainer.cradle,
resolution.options,
resolution.moduleDeclaration
)
}).singleton(),
})
}
export async function loadModuleMigrations(
resolution: ModuleResolution
): Promise<[Function | undefined, Function | undefined]> {
let loadedModule: ModuleExports
try {
loadedModule = (await import(resolution.resolutionPath as string)).default
return [loadedModule.runMigrations, loadedModule.revertMigration]
} catch {
return [undefined, undefined]
}
}