everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
112 lines (110 loc) • 4.34 kB
JavaScript
import { entryUrls } from "./slot.mjs";
//#region src/ui/head.ts
function getThemeInitScript() {
return { children: "(function(){var t=localStorage.getItem('theme');if(t==='dark'){document.documentElement.classList.add('dark');}})();" };
}
function escapeJsonForScript(value) {
return JSON.stringify(value ?? null).replace(/<\/script/gi, "<\\/script").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
}
function getHydrateScript(runtimeConfig, containerName = "ui", hydratePath = "./Hydrate", cspNonce) {
return { children: `
window.__CSP_NONCE__=${cspNonce != null ? escapeJsonForScript(cspNonce) : null};
window.__RUNTIME_CONFIG__=${escapeJsonForScript(runtimeConfig)};
function __hydrate(){
if (window.__EVERYTHING_DEV_HYDRATE_PROMISE__) {
console.warn('[Hydrate] Already in progress, skipping duplicate call');
return;
}
var container = window['${containerName}'];
if (!container) {
console.warn('[Hydrate] Container not ready yet, waiting...');
window.__hydrateRetry = window.__hydrateRetry || 0;
if (window.__hydrateRetry < 10) {
window.__hydrateRetry++;
setTimeout(__hydrate, 100);
return;
}
console.error('[Hydrate] Container not found after 10 retries');
return;
}
console.log('[Hydrate] Container available, starting init...');
container.init({}).then(function(){
return container.get('${hydratePath}');
}).then(function(mod){
return mod().hydrate();
}).catch(function(e){
console.error('[Hydrate] Failed:', e);
window.__EVERYTHING_DEV_HYDRATE_PROMISE__ = undefined;
});
}
if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',__hydrate);}else{__hydrate();}
`.trim() };
}
function getRemoteScripts(options) {
const { runtimeConfig, containerName, hydratePath, integrity, cspNonce } = options;
const slot = {
name: "ui",
url: runtimeConfig?.assetsUrl?.replace(/\/$/, ""),
entryUrl: runtimeConfig?.ui?.entryUrl,
integrity
};
const entryScript = {
src: entryUrls(slot, runtimeConfig?.env ?? "production").web,
crossOrigin: "anonymous"
};
if (integrity) entryScript.integrity = integrity;
return [entryScript, getHydrateScript(runtimeConfig, containerName, hydratePath, cspNonce)];
}
/**
* Preload hints for the composed plugin-UI remotes (`ui.compose`). Without
* them each remote entry is discovered only after the core remoteEntry
* executes and hydrate registers remotes — serializing
* document → remoteEntry → manifest → remoteEntry. Attributes must match
* how the MF runtime loads these resources (plain no-cors `<script>` for
* entries, cors `fetch()` for manifests) or the browser refetches.
*
* Server-only: the client render (hydration re-render of head content, or
* the client-shell fallback) runs after the hydrate compose has already
* fetched the manifests and entries — re-injecting the hints then produces
* preloads nothing will ever consume ("preloaded but not used" console
* warnings on every load).
*/
function getRemotePreloadLinks(runtimeConfig) {
if (typeof window !== "undefined") return [];
const remotes = runtimeConfig?.ui?.compose?.remotes ?? [];
const seen = /* @__PURE__ */ new Set();
const links = [];
for (const remote of remotes) {
if (remote.manifestUrl && !seen.has(remote.manifestUrl)) {
seen.add(remote.manifestUrl);
links.push({
rel: "preload",
href: remote.manifestUrl,
as: "fetch",
crossOrigin: "anonymous"
});
}
if (remote.entry && !seen.has(remote.entry)) {
seen.add(remote.entry);
links.push({
rel: "preload",
href: remote.entry,
as: "script",
fetchPriority: "high"
});
}
}
return links;
}
function getBaseStyles() {
return `
*, *::before, *::after { box-sizing: border-box; }
html { height: 100%; height: 100dvh; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; color-scheme: light dark; }
body { min-height: 100%; min-height: 100dvh; margin: 0; background-color: var(--background); color: var(--foreground); -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
#root { min-height: 100vh; }
@supports (min-height: 100dvh) { #root { min-height: 100dvh; } }
`.trim();
}
//#endregion
export { getBaseStyles, getHydrateScript, getRemotePreloadLinks, getRemoteScripts, getThemeInitScript };
//# sourceMappingURL=head.mjs.map