everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
102 lines (100 loc) • 3.94 kB
JavaScript
import { computeSriHash } from "./integrity.mjs";
import { createInstance, getInstance } from "@module-federation/enhanced/runtime";
import { setGlobalFederationInstance } from "@module-federation/runtime-core";
//#region src/mf.ts
let mfInstance = null;
function patchManifestFetchForSsrPublicPath(mf) {
if (!mf || !mf.loaderHook?.lifecycle?.fetch?.on) return;
if (mf.__everythingDevPatchedManifestFetch === true) return;
mf.__everythingDevPatchedManifestFetch = true;
mf.loaderHook.lifecycle.fetch.on((url, init) => {
if (typeof url !== "string" || !url.endsWith("/mf-manifest.json")) return;
return fetch(url, init).then((res) => res.json()).then((json) => {
json.metaData = json.metaData ?? {};
json.metaData.ssrPublicPath = json.metaData.ssrPublicPath ?? url.replace(/\/mf-manifest\.json$/, "/");
return new Response(JSON.stringify(json), { headers: { "content-type": "application/json" } });
});
});
}
function installIntegrityFetchHook(mf, registry) {
if (!mf || !mf.loaderHook?.lifecycle?.fetch?.on) {
console.warn("[SRI] MF lifecycle fetch hook not available, skipping integrity-in-pipeline");
return;
}
if (mf.__everythingDevIntegrityHook === true) return;
mf.__everythingDevIntegrityHook = true;
mf.loaderHook.lifecycle.fetch.on((url, init) => {
if (typeof url !== "string") return;
const expectedHash = registry.get(url);
if (!expectedHash) return;
return fetch(url, init).then(async (res) => {
const buffer = Buffer.from(await res.arrayBuffer());
const computed = computeSriHash(buffer);
if (computed !== expectedHash) {
console.error(`[SRI] Integrity check failed in MF fetch pipeline for ${url}\n Expected: ${expectedHash}\n Computed: ${computed}`);
return new Response(`Integrity check failed for ${url}`, {
status: 500,
statusText: "Integrity Check Failed"
});
}
console.log(`[SRI] Integrity verified in pipeline for ${url}`);
return new Response(buffer, {
status: res.status,
statusText: res.statusText,
headers: res.headers
});
});
});
}
function getFederationInstance() {
if (mfInstance) return mfInstance;
const existing = getInstance();
if (existing) {
mfInstance = existing;
setGlobalFederationInstance(mfInstance);
patchManifestFetchForSsrPublicPath(mfInstance);
return mfInstance;
}
mfInstance = createInstance({
name: "host",
remotes: []
});
setGlobalFederationInstance(mfInstance);
patchManifestFetchForSsrPublicPath(mfInstance);
return mfInstance;
}
async function registerRemote(opts) {
const instance = getFederationInstance();
const inferType = () => {
if (opts.type) return opts.type;
if (opts.entry.endsWith("/mf-manifest.json")) return "manifest";
if (opts.entry.endsWith("/remoteEntry.js")) return "script";
return typeof window === "undefined" ? "script" : "manifest";
};
const remoteType = inferType();
instance.registerRemotes([{
name: opts.name,
entry: opts.entry,
type: remoteType
}]);
}
async function loadRemoteModule(specifier, options) {
const instance = getFederationInstance();
if (typeof window === "undefined") await instance.initializeSharing?.("default");
const mod = await instance.loadRemote(specifier, options);
if (!mod) throw new Error(`Failed to load remote module: ${specifier}`);
return mod;
}
async function ensureNodeRuntimePlugin() {
const instance = getFederationInstance();
if (typeof window !== "undefined") return;
if (instance.__nodeRuntimePluginLoaded) return;
const mod = await import("@module-federation/node/runtimePlugin");
const factory = mod?.default ?? mod;
const plugin = typeof factory === "function" ? factory() : null;
if (plugin) instance.registerPlugins([plugin]);
instance.__nodeRuntimePluginLoaded = true;
}
//#endregion
export { ensureNodeRuntimePlugin, getFederationInstance, installIntegrityFetchHook, loadRemoteModule, patchManifestFetchForSsrPublicPath, registerRemote };
//# sourceMappingURL=mf.mjs.map