UNPKG

@esmx/core

Version:

A high-performance microfrontend framework supporting Vue, React, Preact, Solid, and Svelte with SSR and Module Linking capabilities.

113 lines (112 loc) 3.68 kB
import { pathWithoutIndex } from "./path-without-index.mjs"; export function createImportsMap(manifests, getFile) { const imports = {}; manifests.forEach((manifest) => { Object.entries(manifest.exports).forEach(([, exportItem]) => { const file = getFile(manifest.name, exportItem.file); imports[exportItem.identifier] = file; }); }); pathWithoutIndex(imports); return imports; } export function createScopesMap(imports, manifests, getScope) { const scopes = {}; manifests.forEach((manifest) => { if (!manifest.scopes) { return; } Object.entries(manifest.scopes).forEach(([scopeName, specifierMap]) => { const scopedImports = {}; Object.entries(specifierMap).forEach( ([specifierName, identifier]) => { scopedImports[specifierName] = imports[identifier] ?? identifier; } ); const scopePath = imports[`${manifest.name}/${scopeName}`] ?? `/${scopeName}`; const scopeKey = getScope(manifest.name, scopePath); scopes[scopeKey] = scopedImports; }); }); return scopes; } export function fixImportMapNestedScopes(importMap) { Object.entries(importMap.scopes).sort(([pathA], [pathB]) => { const depthA = pathA.split("/").length; const depthB = pathB.split("/").length; return depthA - depthB; }).forEach(([scopePath, scopeMappings]) => { Object.values(importMap.imports).forEach((importPath) => { if (importPath.startsWith(scopePath)) { importMap.scopes[importPath] = { ...importMap.scopes[importPath], ...scopeMappings }; } }); Reflect.deleteProperty(importMap.scopes, scopePath); }); return importMap; } export function compressImportMap(importMap) { const compressed = { imports: { ...importMap.imports }, scopes: {} }; const counts = {}; Object.values(importMap.scopes).forEach((scopeMappings) => { Object.entries(scopeMappings).forEach(([specifier, target]) => { if (Object.hasOwn(importMap.imports, specifier)) return; counts[specifier] ??= {}; counts[specifier][target] = (counts[specifier][target] ?? 0) + 1; }); }); Object.entries(counts).forEach(([specifier, targetCounts]) => { const entries = Object.entries(targetCounts); let best = null; let secondBestCount = 0; for (const [t, c] of entries) { if (!best || c > best[1]) { secondBestCount = best ? Math.max(secondBestCount, best[1]) : secondBestCount; best = [t, c]; } else { secondBestCount = Math.max(secondBestCount, c); } } if (best && best[1] > secondBestCount) { compressed.imports[specifier] = best[0]; } }); Object.entries(importMap.scopes).forEach(([scopePath, scopeMappings]) => { const filtered = {}; Object.entries(scopeMappings).forEach(([specifier, target]) => { const globalTarget = compressed.imports[specifier]; if (globalTarget === target) { return; } filtered[specifier] = target; }); if (Object.keys(filtered).length > 0) { compressed.scopes[scopePath] = filtered; } }); const hasScopes = Object.keys(compressed.scopes).length > 0; return hasScopes ? compressed : { imports: compressed.imports }; } export function createImportMap({ manifests, getFile, getScope }) { const imports = createImportsMap(manifests, getFile); const scopes = createScopesMap(imports, manifests, getScope); return { imports, scopes }; } export function createClientImportMap(options) { const base = createImportMap(options); const fixed = fixImportMapNestedScopes(base); return compressImportMap(fixed); }