every-plugin
Version:
1 lines • 9.58 kB
Source Map (JSON)
{"version":3,"file":"module-federation.service.mjs","names":[],"sources":["../../../src/runtime/services/module-federation.service.ts"],"sourcesContent":["import { createInstance, getInstance } from \"@module-federation/enhanced/runtime\";\nimport { setGlobalFederationInstance } from \"@module-federation/runtime-core\";\nimport { Effect } from \"effect\";\nimport type { AnyPlugin } from \"../../types\";\nimport { ModuleFederationError } from \"../errors\";\nimport { type CoreSharedDepName, MF_CORE_SHARED_DEPS } from \"../mf-config\";\nimport { getNormalizedRemoteName } from \"./normalize\";\n\ntype RemoteModule = (new () => AnyPlugin) | { default: new () => AnyPlugin };\n\nconst coreModuleLoaders: Record<CoreSharedDepName, () => Promise<unknown>> = {\n \"every-plugin\": () => import(\"every-plugin\"),\n effect: () => import(\"effect\"),\n zod: () => import(\"zod\"),\n \"@orpc/contract\": () => import(\"@orpc/contract\"),\n \"@orpc/server\": () => import(\"@orpc/server\"),\n};\n\nfunction buildSharedConfig(): Record<\n string,\n {\n version: string;\n get: () => Promise<() => unknown>;\n shareConfig: (typeof MF_CORE_SHARED_DEPS)[CoreSharedDepName][\"shareConfig\"];\n }\n> {\n return Object.fromEntries(\n (\n Object.entries(MF_CORE_SHARED_DEPS) as [\n CoreSharedDepName,\n (typeof MF_CORE_SHARED_DEPS)[CoreSharedDepName],\n ][]\n ).map(([name, config]) => {\n const load = coreModuleLoaders[name];\n\n if (!load) {\n throw new Error(`Missing core shared module loader for ${name}`);\n }\n\n return [\n name,\n {\n version: config.version,\n get: () => load().then((mod) => () => mod),\n shareConfig: config.shareConfig,\n },\n ];\n }),\n );\n}\n\nconst createModuleFederationInstance = Effect.cached(\n Effect.sync(() => {\n try {\n const shared = buildSharedConfig();\n let instance = getInstance();\n\n if (!instance) {\n instance = createInstance({\n name: \"host\",\n remotes: [],\n shared,\n });\n\n setGlobalFederationInstance(instance);\n } else {\n instance.registerShared(shared);\n }\n\n return instance;\n } catch (error) {\n throw new Error(`Failed to initialize Module Federation: ${error}`);\n }\n }),\n);\n\nexport class ModuleFederationService extends Effect.Service<ModuleFederationService>()(\n \"ModuleFederationService\",\n {\n effect: Effect.gen(function* () {\n const mf = yield* Effect.flatten(createModuleFederationInstance);\n\n return {\n registerRemote: (pluginId: string, url: string) =>\n Effect.gen(function* () {\n console.log(`[MF] Registering ${pluginId}`);\n\n const remoteName = getNormalizedRemoteName(pluginId);\n const type = url.endsWith(\"/mf-manifest.json\")\n ? (\"manifest\" as const)\n : url.endsWith(\"/remoteEntry.js\")\n ? (\"script\" as const)\n : undefined;\n\n yield* Effect.try({\n try: () =>\n mf.registerRemotes([\n {\n name: remoteName,\n entry: url,\n ...(type ? { type } : {}),\n },\n ]),\n catch: (error): ModuleFederationError =>\n new ModuleFederationError({\n pluginId,\n remoteUrl: url,\n cause: error instanceof Error ? error : new Error(String(error)),\n }),\n });\n\n console.log(`[MF] ✅ Registered ${pluginId}`);\n }),\n\n loadRemoteConstructor: (pluginId: string, url: string) =>\n Effect.gen(function* () {\n const remoteName = getNormalizedRemoteName(pluginId);\n console.log(`[MF] Loading remote ${remoteName}`);\n const modulePath = `${remoteName}/plugin`;\n\n return yield* Effect.tryPromise({\n try: async () => {\n const container = await mf.loadRemote<RemoteModule>(modulePath);\n if (!container) {\n throw new Error(`No container returned for ${modulePath}`);\n }\n\n // Support multiple export patterns: direct function, default export, named exports\n let Constructor: any;\n\n if (typeof container === \"function\") {\n // Direct function export\n Constructor = container;\n } else if (container.default) {\n // Default export\n Constructor = container.default;\n } else {\n // Named export fallback - prioritize exports with 'binding' property (plugin classes)\n Constructor = Object.values(container).find(\n (exp) => typeof exp === \"function\" && (exp as any).binding !== undefined,\n );\n\n // Fallback to any function export if no binding found\n if (!Constructor) {\n Constructor = Object.values(container).find(\n (exp) => typeof exp === \"function\" && exp.prototype?.constructor === exp,\n );\n }\n }\n\n if (!Constructor || typeof Constructor !== \"function\") {\n const containerInfo =\n typeof container === \"object\"\n ? `Available exports: ${Object.keys(container).join(\", \")}`\n : `Container type: ${typeof container}`;\n\n throw new Error(\n `No valid plugin constructor found for '${pluginId}'.\\n` +\n `Supported patterns:\\n` +\n ` - export const YourPlugin = createPlugin({...})\\n` +\n ` - export default createPlugin({...})\\n` +\n `${containerInfo}`,\n );\n }\n\n // Validate it looks like a plugin constructor (has binding property)\n if (!(Constructor as any).binding) {\n const containerInfo =\n typeof container === \"object\"\n ? `Found exports: ${Object.keys(container).join(\", \")}`\n : `Container type: ${typeof container}`;\n\n throw new Error(\n `Invalid plugin constructor for '${pluginId}'. ` +\n `The exported value must be created with createPlugin(). ` +\n `Found a function but it's missing the required 'binding' property.\\n` +\n `${containerInfo}`,\n );\n }\n\n console.log(`[MF] ✅ Loaded constructor for ${pluginId}`);\n return Constructor;\n },\n catch: (error): ModuleFederationError =>\n new ModuleFederationError({\n pluginId,\n remoteUrl: url,\n cause: error instanceof Error ? error : new Error(String(error)),\n }),\n });\n }),\n };\n }),\n },\n) {}\n"],"mappings":";;;;;;;;AAUA,MAAM,oBAAuE;CAC3E,sBAAsB,OAAO;CAC7B,cAAc,OAAO;CACrB,WAAW,OAAO;CAClB,wBAAwB,OAAO;CAC/B,sBAAsB,OAAO;CAC9B;AAED,SAAS,oBAOP;AACA,QAAO,OAAO,YAEV,OAAO,QAAQ,oBAAoB,CAInC,KAAK,CAAC,MAAM,YAAY;EACxB,MAAM,OAAO,kBAAkB;AAE/B,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,yCAAyC,OAAO;AAGlE,SAAO,CACL,MACA;GACE,SAAS,OAAO;GAChB,WAAW,MAAM,CAAC,MAAM,cAAc,IAAI;GAC1C,aAAa,OAAO;GACrB,CACF;GACD,CACH;;AAGH,MAAM,iCAAiC,OAAO,OAC5C,OAAO,WAAW;AAChB,KAAI;EACF,MAAM,SAAS,mBAAmB;EAClC,IAAI,WAAW,aAAa;AAE5B,MAAI,CAAC,UAAU;AACb,cAAW,eAAe;IACxB,MAAM;IACN,SAAS,EAAE;IACX;IACD,CAAC;AAEF,+BAA4B,SAAS;QAErC,UAAS,eAAe,OAAO;AAGjC,SAAO;UACA,OAAO;AACd,QAAM,IAAI,MAAM,2CAA2C,QAAQ;;EAErE,CACH;AAED,IAAa,0BAAb,cAA6C,OAAO,SAAkC,CACpF,2BACA,EACE,QAAQ,OAAO,IAAI,aAAa;CAC9B,MAAM,KAAK,OAAO,OAAO,QAAQ,+BAA+B;AAEhE,QAAO;EACL,iBAAiB,UAAkB,QACjC,OAAO,IAAI,aAAa;AACtB,WAAQ,IAAI,oBAAoB,WAAW;GAE3C,MAAM,aAAa,wBAAwB,SAAS;GACpD,MAAM,OAAO,IAAI,SAAS,oBAAoB,GACzC,aACD,IAAI,SAAS,kBAAkB,GAC5B,WACD;AAEN,UAAO,OAAO,IAAI;IAChB,WACE,GAAG,gBAAgB,CACjB;KACE,MAAM;KACN,OAAO;KACP,GAAI,OAAO,EAAE,MAAM,GAAG,EAAE;KACzB,CACF,CAAC;IACJ,QAAQ,UACN,IAAI,sBAAsB;KACxB;KACA,WAAW;KACX,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;KACjE,CAAC;IACL,CAAC;AAEF,WAAQ,IAAI,qBAAqB,WAAW;IAC5C;EAEJ,wBAAwB,UAAkB,QACxC,OAAO,IAAI,aAAa;GACtB,MAAM,aAAa,wBAAwB,SAAS;AACpD,WAAQ,IAAI,uBAAuB,aAAa;GAChD,MAAM,aAAa,GAAG,WAAW;AAEjC,UAAO,OAAO,OAAO,WAAW;IAC9B,KAAK,YAAY;KACf,MAAM,YAAY,MAAM,GAAG,WAAyB,WAAW;AAC/D,SAAI,CAAC,UACH,OAAM,IAAI,MAAM,6BAA6B,aAAa;KAI5D,IAAI;AAEJ,SAAI,OAAO,cAAc,WAEvB,eAAc;cACL,UAAU,QAEnB,eAAc,UAAU;UACnB;AAEL,oBAAc,OAAO,OAAO,UAAU,CAAC,MACpC,QAAQ,OAAO,QAAQ,cAAe,IAAY,YAAY,OAChE;AAGD,UAAI,CAAC,YACH,eAAc,OAAO,OAAO,UAAU,CAAC,MACpC,QAAQ,OAAO,QAAQ,cAAc,IAAI,WAAW,gBAAgB,IACtE;;AAIL,SAAI,CAAC,eAAe,OAAO,gBAAgB,YAAY;MACrD,MAAM,gBACJ,OAAO,cAAc,WACjB,sBAAsB,OAAO,KAAK,UAAU,CAAC,KAAK,KAAK,KACvD,mBAAmB,OAAO;AAEhC,YAAM,IAAI,MACR,0CAA0C,SAAS,sHAI9C,gBACN;;AAIH,SAAI,CAAE,YAAoB,SAAS;MACjC,MAAM,gBACJ,OAAO,cAAc,WACjB,kBAAkB,OAAO,KAAK,UAAU,CAAC,KAAK,KAAK,KACnD,mBAAmB,OAAO;AAEhC,YAAM,IAAI,MACR,mCAAmC,SAAS,iIAGvC,gBACN;;AAGH,aAAQ,IAAI,iCAAiC,WAAW;AACxD,YAAO;;IAET,QAAQ,UACN,IAAI,sBAAsB;KACxB;KACA,WAAW;KACX,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;KACjE,CAAC;IACL,CAAC;IACF;EACL;EACD,EACH,CACF,CAAC"}