@edynamix/mf-isolation 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAsB,KAAK,uBAAuB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAQ/G,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,uBAAuB,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,KAAK,CAAC;CAClB;AAgBD,MAAM,WAAW,uBAAuB;IAEtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA2CD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,cAAc,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC9C,WAA0B,uBAA4B,KACrD,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAepC,CAAC;AAEF,eAAO,MAAM,kCAAkC,EAAG,CAAU,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,OAAO,kCAAkC,CAAC;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAsBD,eAAO,MAAM,0BAA0B,GAAI,YAAY,uBAAuB,KAAG,QAAQ,CAAC,qBAAqB,CAa9G,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAI,YAAY,uBAAuB,KAAG,MAEnF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,0BAA8C,0BAA0B,KAAG,MA4B7G,CAAC;AAmEF,eAAO,MAAM,wBAAwB,GAAI,UAAU,gBAAgB,KAAG,MAAkD,CAAC;AAEzH,eAAO,MAAM,qBAAqB,GAAI,wBAAkD,6BAA6B,KAAG,MAqCvH,CAAC","sourcesContent":["import { createHash } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport type { Plugin } from 'vite';\nimport { defineMfNavigation, type IMfNavigationDefinition, type IMfNavigationManifest } from './navigation.js';\n\nconst DEFAULT_FILE_NAME = 'navigation.json';\nconst DEFAULT_ASSET_FILE_NAME = 'module-assets.json';\nconst FILE_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*\\.json$/;\nconst MODULE_ID_PATTERN = /^[a-z][a-z0-9-]*$/;\nconst CONTENT_HASHED_ASSET_PATTERN = /(?:^|\\/)[^/]+-[a-zA-Z0-9_-]{8,}\\.[^/]+$/;\n\nexport interface IMfNavigationPluginOptions {\n fileName?: string;\n navigation: IMfNavigationDefinition;\n}\n\nexport interface IMfSharedDependency {\n requiredVersion: string;\n singleton: false;\n}\n\n// The Angular packages are shared entry point by entry point: each one is a flat ESM file importing the others by\n// package name. An entry point stylesheets also resolve (the `sass` root of @angular/material and @angular/cdk, which\n// `@use '@angular/material'` reaches) is left out, because Module Federation would answer the stylesheet with a script.\n// RxJS subpaths reach its internals by relative path: only its two public entry points are shared, each complete, so a\n// page never mixes RxJS internals from two modules' builds.\nconst SHARED_ANGULAR_SCOPE = '@angular/';\n// Only just-in-time compilation needs these, and the modules are compiled ahead of time. Shared, they would put the\n// compiler (with its ShadowCss placeholders) into every module's build; the modules that bootstrap through\n// platformBrowserDynamic keep their own copy, as before.\nconst UNSHARED_ANGULAR_PACKAGES = new Set(['@angular/compiler', '@angular/platform-browser-dynamic']);\nconst SHARED_RXJS_ENTRY_POINTS = ['rxjs', 'rxjs/operators'] as const;\nconst EXACT_VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/;\nconst SCRIPT_ENTRY_CONDITIONS = 'default,types';\n\nexport interface IMfAngularSharedOptions {\n // The directory whose node_modules holds the module's packages; the Vite config's directory by default.\n root?: string;\n}\n\n// The import and re-export statements of a flat ESM file, which start their line; comments mentioning imports do not.\nconst BARE_IMPORT_PATTERN = /^(?:import|export)\\b[^;'\"]*?(?:\\bfrom\\s*)?['\"]([^'\"./][^'\"]*)['\"]/gm;\n\nconst bareImportPackage = (specifier: string): string =>\n specifier\n .split('/')\n .slice(0, specifier.startsWith('@') ? 2 : 1)\n .join('/');\n\n// Module Federation builds a local copy of every shared entry point, used or not, so an entry point is shared only\n// when every package it imports is installed (`@angular/common/upgrade` needs `@angular/upgrade`, which modules do not\n// install, and `@angular/platform-browser/animations` needs `@angular/animations`).\nconst angularScriptEntryPoints = (packageName: string, root: string): string[] => {\n const resolvePackage = createRequire(join(root, 'package.json'));\n const packageJsonPath = resolvePackage.resolve(`${packageName}/package.json`);\n const isInstalled = (dependency: string): boolean => {\n try {\n resolvePackage.resolve(`${dependency}/package.json`);\n return true;\n } catch {\n return false;\n }\n };\n const { exports } = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { exports?: Record<string, unknown> };\n return Object.entries(exports ?? {})\n .filter(([subpath, target]) => {\n if (\n subpath.includes('*') ||\n subpath.split('/').includes('testing') ||\n typeof target !== 'object' ||\n target === null ||\n Object.keys(target).sort().join(',') !== SCRIPT_ENTRY_CONDITIONS\n ) {\n return false;\n }\n const source = readFileSync(join(dirname(packageJsonPath), (target as { default: string }).default), 'utf8');\n return [...source.matchAll(BARE_IMPORT_PATTERN)].every(([, specifier]) => specifier === undefined || isInstalled(bareImportPackage(specifier)));\n })\n .map(([subpath]) => (subpath === '.' ? packageName : `${packageName}/${subpath.slice(2)}`));\n};\n\n/**\n * The Module Federation `shared` configuration of a hosted Angular module: every script entry point of the `@angular/*`\n * packages among the module's dependencies, and RxJS, at the module's own exact versions. Modules on the same versions\n * load these once per page and share them; a module on another version keeps its own copy instead of mixing two\n * Angular versions.\n */\nexport const createMfAngularShared = (\n dependencies: Readonly<Record<string, string>>,\n { root = process.cwd() }: IMfAngularSharedOptions = {},\n): Record<string, IMfSharedDependency> => {\n const shared: Record<string, IMfSharedDependency> = {};\n for (const [name, version] of Object.entries(dependencies).sort(([left], [right]) => left.localeCompare(right))) {\n const isAngular = name.startsWith(SHARED_ANGULAR_SCOPE) && !UNSHARED_ANGULAR_PACKAGES.has(name);\n if (!isAngular && name !== 'rxjs') {\n continue;\n }\n if (!EXACT_VERSION_PATTERN.test(version)) {\n throw new Error(`Shared dependency ${name} must be pinned to an exact version, not \"${version}\".`);\n }\n for (const entryPoint of isAngular ? angularScriptEntryPoints(name, root) : SHARED_RXJS_ENTRY_POINTS) {\n shared[entryPoint] = { requiredVersion: version, singleton: false };\n }\n }\n return shared;\n};\n\nexport const MF_ASSET_MANIFEST_CONTRACT_VERSION = 1 as const;\n\nexport interface IMfAssetManifest {\n assets: readonly string[];\n contractVersion: typeof MF_ASSET_MANIFEST_CONTRACT_VERSION;\n moduleId: string;\n revision: string;\n}\n\nexport interface IMfAssetManifestPluginOptions {\n fileName?: string;\n moduleId: string;\n}\n\ninterface IMfOutputAsset {\n fileName: string;\n source: string | Uint8Array;\n type: 'asset';\n}\n\ninterface IMfOutputChunk {\n code: string;\n fileName: string;\n imports: readonly string[];\n modules: Readonly<Record<string, unknown>>;\n referencedFiles?: readonly string[];\n type: 'chunk';\n viteMetadata?: { importedAssets?: ReadonlySet<string>; importedCss?: ReadonlySet<string> };\n}\n\ntype TMfOutputBundle = Readonly<Record<string, IMfOutputAsset | IMfOutputChunk>>;\n\nconst serializeDefinition = (definition: Readonly<IMfNavigationDefinition>): string => JSON.stringify(definition);\n\nexport const createMfNavigationManifest = (navigation: IMfNavigationDefinition): Readonly<IMfNavigationManifest> => {\n const definition = defineMfNavigation(navigation);\n const revision = createHash('sha256').update(serializeDefinition(definition)).digest('hex');\n\n return Object.freeze({\n applicationId: definition.applicationId,\n contractVersion: definition.contractVersion,\n items: definition.items,\n label: definition.label,\n landingPath: definition.landingPath,\n moduleId: definition.moduleId,\n revision,\n });\n};\n\nexport const serializeMfNavigationManifest = (navigation: IMfNavigationDefinition): string => {\n return `${JSON.stringify(createMfNavigationManifest(navigation), null, 2)}\\n`;\n};\n\nexport const mfNavigationPlugin = ({ fileName = DEFAULT_FILE_NAME, navigation }: IMfNavigationPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend navigation fileName must be a safe JSON file name.');\n }\n\n const source = serializeMfNavigationManifest(navigation);\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-navigation',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n const requestPath = request.url?.split('?', 1)[0];\n if (requestPath !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(source);\n });\n },\n generateBundle() {\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n\nconst isLifecycleModule = (moduleId: string): boolean => /(?:^|\\/)src\\/lifecycle(?:-impl)?\\.[cm]?[jt]sx?$/.test(moduleId.replaceAll('\\\\', '/'));\n\nconst addChunkDependencies = (bundle: TMfOutputBundle, fileName: string, assets: Set<string>): void => {\n if (assets.has(fileName)) {\n return;\n }\n\n const output = bundle[fileName];\n if (output?.type !== 'chunk') {\n return;\n }\n\n assets.add(fileName);\n for (const importedFileName of output.imports) {\n addChunkDependencies(bundle, importedFileName, assets);\n }\n\n const metadata = output.viteMetadata;\n for (const referencedFileName of [...(metadata?.importedAssets ?? []), ...(metadata?.importedCss ?? []), ...(output.referencedFiles ?? [])]) {\n if (bundle[referencedFileName]) {\n assets.add(referencedFileName);\n }\n }\n};\n\nconst outputBytes = (output: IMfOutputAsset | IMfOutputChunk): string | Uint8Array => (output.type === 'chunk' ? output.code : output.source);\n\nconst createMfAssetManifest = (moduleId: string, bundle: TMfOutputBundle): Readonly<IMfAssetManifest> => {\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const lifecycleChunks = Object.values(bundle).filter(\n (output): output is IMfOutputChunk => output.type === 'chunk' && Object.keys(output.modules).some(isLifecycleModule),\n );\n if (lifecycleChunks.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit a lifecycle chunk.`);\n }\n\n const discoveredAssets = new Set<string>();\n for (const chunk of lifecycleChunks) {\n addChunkDependencies(bundle, chunk.fileName, discoveredAssets);\n }\n const assets = [...discoveredAssets].filter((fileName) => CONTENT_HASHED_ASSET_PATTERN.test(fileName)).sort();\n if (assets.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit content-hashed lifecycle assets.`);\n }\n\n const revisionHash = createHash('sha256');\n for (const fileName of assets) {\n const output = bundle[fileName];\n if (!output) {\n throw new Error(`Microfrontend ${moduleId} asset ${fileName} is missing from the output bundle.`);\n }\n revisionHash.update(fileName).update('\\0').update(outputBytes(output)).update('\\0');\n }\n\n return Object.freeze({\n assets: Object.freeze(assets),\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: revisionHash.digest('hex'),\n });\n};\n\nexport const serializeMfAssetManifest = (manifest: IMfAssetManifest): string => `${JSON.stringify(manifest, null, 2)}\\n`;\n\nexport const mfAssetManifestPlugin = ({ fileName = DEFAULT_ASSET_FILE_NAME, moduleId }: IMfAssetManifestPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend asset fileName must be a safe JSON file name.');\n }\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const developmentManifest = serializeMfAssetManifest({\n assets: [],\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: 'development',\n });\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-assets',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n if (request.url?.split('?', 1)[0] !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Access-Control-Allow-Origin', '*');\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(developmentManifest);\n });\n },\n generateBundle(_options, bundle) {\n const source = serializeMfAssetManifest(createMfAssetManifest(moduleId, bundle as unknown as TMfOutputBundle));\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n"]}
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAsB,KAAK,uBAAuB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAQ/G,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,uBAAuB,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,KAAK,CAAC;CAClB;AAgBD,MAAM,WAAW,uBAAuB;IAEtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAuED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,cAAc,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC9C,WAA0B,uBAA4B,KACrD,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAepC,CAAC;AAEF,eAAO,MAAM,kCAAkC,EAAG,CAAU,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,OAAO,kCAAkC,CAAC;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAsBD,eAAO,MAAM,0BAA0B,GAAI,YAAY,uBAAuB,KAAG,QAAQ,CAAC,qBAAqB,CAa9G,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAI,YAAY,uBAAuB,KAAG,MAEnF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,0BAA8C,0BAA0B,KAAG,MA4B7G,CAAC;AAmEF,eAAO,MAAM,wBAAwB,GAAI,UAAU,gBAAgB,KAAG,MAAkD,CAAC;AAEzH,eAAO,MAAM,qBAAqB,GAAI,wBAAkD,6BAA6B,KAAG,MAqCvH,CAAC","sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport type { Plugin } from 'vite';\nimport { defineMfNavigation, type IMfNavigationDefinition, type IMfNavigationManifest } from './navigation.js';\n\nconst DEFAULT_FILE_NAME = 'navigation.json';\nconst DEFAULT_ASSET_FILE_NAME = 'module-assets.json';\nconst FILE_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*\\.json$/;\nconst MODULE_ID_PATTERN = /^[a-z][a-z0-9-]*$/;\nconst CONTENT_HASHED_ASSET_PATTERN = /(?:^|\\/)[^/]+-[a-zA-Z0-9_-]{8,}\\.[^/]+$/;\n\nexport interface IMfNavigationPluginOptions {\n fileName?: string;\n navigation: IMfNavigationDefinition;\n}\n\nexport interface IMfSharedDependency {\n requiredVersion: string;\n singleton: false;\n}\n\n// The Angular packages are shared entry point by entry point: each one is a flat ESM file importing the others by\n// package name. An entry point stylesheets also resolve (the `sass` root of @angular/material and @angular/cdk, which\n// `@use '@angular/material'` reaches) is left out, because Module Federation would answer the stylesheet with a script.\n// RxJS subpaths reach its internals by relative path: only its two public entry points are shared, each complete, so a\n// page never mixes RxJS internals from two modules' builds.\nconst SHARED_ANGULAR_SCOPE = '@angular/';\n// Only just-in-time compilation needs these, and the modules are compiled ahead of time. Shared, they would put the\n// compiler (with its ShadowCss placeholders) into every module's build; the modules that bootstrap through\n// platformBrowserDynamic keep their own copy, as before.\nconst UNSHARED_ANGULAR_PACKAGES = new Set(['@angular/compiler', '@angular/platform-browser-dynamic']);\nconst SHARED_RXJS_ENTRY_POINTS = ['rxjs', 'rxjs/operators'] as const;\nconst EXACT_VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/;\nconst SCRIPT_ENTRY_CONDITIONS = 'default,types';\n\nexport interface IMfAngularSharedOptions {\n // The directory whose node_modules holds the module's packages; the Vite config's directory by default.\n root?: string;\n}\n\n// The import and re-export statements of a flat ESM file, which start their line; comments mentioning imports do not.\nconst BARE_IMPORT_PATTERN = /^(?:import|export)\\b[^;'\"]*?(?:\\bfrom\\s*)?['\"]([^'\"./][^'\"]*)['\"]/gm;\nconst RELATIVE_IMPORT_PATTERN = /^(?:import|export)\\b[^;'\"]*?(?:\\bfrom\\s*)?['\"](\\.\\.?\\/[^'\"]*)['\"]/gm;\n\nconst bareImportPackage = (specifier: string): string =>\n specifier\n .split('/')\n .slice(0, specifier.startsWith('@') ? 2 : 1)\n .join('/');\n\n// The packages an entry point's local copy would contain: what its file imports, and what the files it imports by\n// relative path (its own chunks) import in turn.\nconst importedPackages = (entryFile: string): Set<string> => {\n const packages = new Set<string>();\n const visited = new Set<string>();\n const visit = (file: string): void => {\n if (visited.has(file) || !existsSync(file)) {\n return;\n }\n visited.add(file);\n const source = readFileSync(file, 'utf8');\n for (const [, specifier] of source.matchAll(BARE_IMPORT_PATTERN)) {\n if (specifier !== undefined) {\n packages.add(bareImportPackage(specifier));\n }\n }\n for (const [, specifier] of source.matchAll(RELATIVE_IMPORT_PATTERN)) {\n if (specifier !== undefined) {\n visit(join(dirname(file), specifier));\n }\n }\n };\n visit(entryFile);\n return packages;\n};\n\n// Module Federation builds a local copy of every shared entry point, used or not, so an entry point is shared only\n// when every package it imports is installed (`@angular/common/upgrade` needs `@angular/upgrade`, which modules do not\n// install, and `@angular/platform-browser/animations` needs `@angular/animations`) and none of them is a package left\n// unshared (the build-time `@angular/localize/tools` reaches the compiler through its own chunks).\nconst angularScriptEntryPoints = (packageName: string, root: string): string[] => {\n const resolvePackage = createRequire(join(root, 'package.json'));\n const packageJsonPath = resolvePackage.resolve(`${packageName}/package.json`);\n const isInstalled = (dependency: string): boolean => {\n try {\n resolvePackage.resolve(`${dependency}/package.json`);\n return true;\n } catch {\n return false;\n }\n };\n const { exports } = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { exports?: Record<string, unknown> };\n return Object.entries(exports ?? {})\n .filter(([subpath, target]) => {\n if (\n subpath.includes('*') ||\n subpath.split('/').includes('testing') ||\n typeof target !== 'object' ||\n target === null ||\n Object.keys(target).sort().join(',') !== SCRIPT_ENTRY_CONDITIONS\n ) {\n return false;\n }\n const entryFile = join(dirname(packageJsonPath), (target as { default: string }).default);\n return [...importedPackages(entryFile)].every((dependency) => isInstalled(dependency) && !UNSHARED_ANGULAR_PACKAGES.has(dependency));\n })\n .map(([subpath]) => (subpath === '.' ? packageName : `${packageName}/${subpath.slice(2)}`));\n};\n\n/**\n * The Module Federation `shared` configuration of a hosted Angular module: every script entry point of the `@angular/*`\n * packages among the module's dependencies, and RxJS, at the module's own exact versions. Modules on the same versions\n * load these once per page and share them; a module on another version keeps its own copy instead of mixing two\n * Angular versions.\n */\nexport const createMfAngularShared = (\n dependencies: Readonly<Record<string, string>>,\n { root = process.cwd() }: IMfAngularSharedOptions = {},\n): Record<string, IMfSharedDependency> => {\n const shared: Record<string, IMfSharedDependency> = {};\n for (const [name, version] of Object.entries(dependencies).sort(([left], [right]) => left.localeCompare(right))) {\n const isAngular = name.startsWith(SHARED_ANGULAR_SCOPE) && !UNSHARED_ANGULAR_PACKAGES.has(name);\n if (!isAngular && name !== 'rxjs') {\n continue;\n }\n if (!EXACT_VERSION_PATTERN.test(version)) {\n throw new Error(`Shared dependency ${name} must be pinned to an exact version, not \"${version}\".`);\n }\n for (const entryPoint of isAngular ? angularScriptEntryPoints(name, root) : SHARED_RXJS_ENTRY_POINTS) {\n shared[entryPoint] = { requiredVersion: version, singleton: false };\n }\n }\n return shared;\n};\n\nexport const MF_ASSET_MANIFEST_CONTRACT_VERSION = 1 as const;\n\nexport interface IMfAssetManifest {\n assets: readonly string[];\n contractVersion: typeof MF_ASSET_MANIFEST_CONTRACT_VERSION;\n moduleId: string;\n revision: string;\n}\n\nexport interface IMfAssetManifestPluginOptions {\n fileName?: string;\n moduleId: string;\n}\n\ninterface IMfOutputAsset {\n fileName: string;\n source: string | Uint8Array;\n type: 'asset';\n}\n\ninterface IMfOutputChunk {\n code: string;\n fileName: string;\n imports: readonly string[];\n modules: Readonly<Record<string, unknown>>;\n referencedFiles?: readonly string[];\n type: 'chunk';\n viteMetadata?: { importedAssets?: ReadonlySet<string>; importedCss?: ReadonlySet<string> };\n}\n\ntype TMfOutputBundle = Readonly<Record<string, IMfOutputAsset | IMfOutputChunk>>;\n\nconst serializeDefinition = (definition: Readonly<IMfNavigationDefinition>): string => JSON.stringify(definition);\n\nexport const createMfNavigationManifest = (navigation: IMfNavigationDefinition): Readonly<IMfNavigationManifest> => {\n const definition = defineMfNavigation(navigation);\n const revision = createHash('sha256').update(serializeDefinition(definition)).digest('hex');\n\n return Object.freeze({\n applicationId: definition.applicationId,\n contractVersion: definition.contractVersion,\n items: definition.items,\n label: definition.label,\n landingPath: definition.landingPath,\n moduleId: definition.moduleId,\n revision,\n });\n};\n\nexport const serializeMfNavigationManifest = (navigation: IMfNavigationDefinition): string => {\n return `${JSON.stringify(createMfNavigationManifest(navigation), null, 2)}\\n`;\n};\n\nexport const mfNavigationPlugin = ({ fileName = DEFAULT_FILE_NAME, navigation }: IMfNavigationPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend navigation fileName must be a safe JSON file name.');\n }\n\n const source = serializeMfNavigationManifest(navigation);\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-navigation',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n const requestPath = request.url?.split('?', 1)[0];\n if (requestPath !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(source);\n });\n },\n generateBundle() {\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n\nconst isLifecycleModule = (moduleId: string): boolean => /(?:^|\\/)src\\/lifecycle(?:-impl)?\\.[cm]?[jt]sx?$/.test(moduleId.replaceAll('\\\\', '/'));\n\nconst addChunkDependencies = (bundle: TMfOutputBundle, fileName: string, assets: Set<string>): void => {\n if (assets.has(fileName)) {\n return;\n }\n\n const output = bundle[fileName];\n if (output?.type !== 'chunk') {\n return;\n }\n\n assets.add(fileName);\n for (const importedFileName of output.imports) {\n addChunkDependencies(bundle, importedFileName, assets);\n }\n\n const metadata = output.viteMetadata;\n for (const referencedFileName of [...(metadata?.importedAssets ?? []), ...(metadata?.importedCss ?? []), ...(output.referencedFiles ?? [])]) {\n if (bundle[referencedFileName]) {\n assets.add(referencedFileName);\n }\n }\n};\n\nconst outputBytes = (output: IMfOutputAsset | IMfOutputChunk): string | Uint8Array => (output.type === 'chunk' ? output.code : output.source);\n\nconst createMfAssetManifest = (moduleId: string, bundle: TMfOutputBundle): Readonly<IMfAssetManifest> => {\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const lifecycleChunks = Object.values(bundle).filter(\n (output): output is IMfOutputChunk => output.type === 'chunk' && Object.keys(output.modules).some(isLifecycleModule),\n );\n if (lifecycleChunks.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit a lifecycle chunk.`);\n }\n\n const discoveredAssets = new Set<string>();\n for (const chunk of lifecycleChunks) {\n addChunkDependencies(bundle, chunk.fileName, discoveredAssets);\n }\n const assets = [...discoveredAssets].filter((fileName) => CONTENT_HASHED_ASSET_PATTERN.test(fileName)).sort();\n if (assets.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit content-hashed lifecycle assets.`);\n }\n\n const revisionHash = createHash('sha256');\n for (const fileName of assets) {\n const output = bundle[fileName];\n if (!output) {\n throw new Error(`Microfrontend ${moduleId} asset ${fileName} is missing from the output bundle.`);\n }\n revisionHash.update(fileName).update('\\0').update(outputBytes(output)).update('\\0');\n }\n\n return Object.freeze({\n assets: Object.freeze(assets),\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: revisionHash.digest('hex'),\n });\n};\n\nexport const serializeMfAssetManifest = (manifest: IMfAssetManifest): string => `${JSON.stringify(manifest, null, 2)}\\n`;\n\nexport const mfAssetManifestPlugin = ({ fileName = DEFAULT_ASSET_FILE_NAME, moduleId }: IMfAssetManifestPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend asset fileName must be a safe JSON file name.');\n }\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const developmentManifest = serializeMfAssetManifest({\n assets: [],\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: 'development',\n });\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-assets',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n if (request.url?.split('?', 1)[0] !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Access-Control-Allow-Origin', '*');\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(developmentManifest);\n });\n },\n generateBundle(_options, bundle) {\n const source = serializeMfAssetManifest(createMfAssetManifest(moduleId, bundle as unknown as TMfOutputBundle));\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n"]}
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { readFileSync } from 'node:fs';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
3
  import { createRequire } from 'node:module';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { defineMfNavigation } from './navigation.js';
@@ -23,13 +23,40 @@ const EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
23
23
  const SCRIPT_ENTRY_CONDITIONS = 'default,types';
24
24
  // The import and re-export statements of a flat ESM file, which start their line; comments mentioning imports do not.
25
25
  const BARE_IMPORT_PATTERN = /^(?:import|export)\b[^;'"]*?(?:\bfrom\s*)?['"]([^'"./][^'"]*)['"]/gm;
26
+ const RELATIVE_IMPORT_PATTERN = /^(?:import|export)\b[^;'"]*?(?:\bfrom\s*)?['"](\.\.?\/[^'"]*)['"]/gm;
26
27
  const bareImportPackage = (specifier) => specifier
27
28
  .split('/')
28
29
  .slice(0, specifier.startsWith('@') ? 2 : 1)
29
30
  .join('/');
31
+ // The packages an entry point's local copy would contain: what its file imports, and what the files it imports by
32
+ // relative path (its own chunks) import in turn.
33
+ const importedPackages = (entryFile) => {
34
+ const packages = new Set();
35
+ const visited = new Set();
36
+ const visit = (file) => {
37
+ if (visited.has(file) || !existsSync(file)) {
38
+ return;
39
+ }
40
+ visited.add(file);
41
+ const source = readFileSync(file, 'utf8');
42
+ for (const [, specifier] of source.matchAll(BARE_IMPORT_PATTERN)) {
43
+ if (specifier !== undefined) {
44
+ packages.add(bareImportPackage(specifier));
45
+ }
46
+ }
47
+ for (const [, specifier] of source.matchAll(RELATIVE_IMPORT_PATTERN)) {
48
+ if (specifier !== undefined) {
49
+ visit(join(dirname(file), specifier));
50
+ }
51
+ }
52
+ };
53
+ visit(entryFile);
54
+ return packages;
55
+ };
30
56
  // Module Federation builds a local copy of every shared entry point, used or not, so an entry point is shared only
31
57
  // when every package it imports is installed (`@angular/common/upgrade` needs `@angular/upgrade`, which modules do not
32
- // install, and `@angular/platform-browser/animations` needs `@angular/animations`).
58
+ // install, and `@angular/platform-browser/animations` needs `@angular/animations`) and none of them is a package left
59
+ // unshared (the build-time `@angular/localize/tools` reaches the compiler through its own chunks).
33
60
  const angularScriptEntryPoints = (packageName, root) => {
34
61
  const resolvePackage = createRequire(join(root, 'package.json'));
35
62
  const packageJsonPath = resolvePackage.resolve(`${packageName}/package.json`);
@@ -52,8 +79,8 @@ const angularScriptEntryPoints = (packageName, root) => {
52
79
  Object.keys(target).sort().join(',') !== SCRIPT_ENTRY_CONDITIONS) {
53
80
  return false;
54
81
  }
55
- const source = readFileSync(join(dirname(packageJsonPath), target.default), 'utf8');
56
- return [...source.matchAll(BARE_IMPORT_PATTERN)].every(([, specifier]) => specifier === undefined || isInstalled(bareImportPackage(specifier)));
82
+ const entryFile = join(dirname(packageJsonPath), target.default);
83
+ return [...importedPackages(entryFile)].every((dependency) => isInstalled(dependency) && !UNSHARED_ANGULAR_PACKAGES.has(dependency));
57
84
  })
58
85
  .map(([subpath]) => (subpath === '.' ? packageName : `${packageName}/${subpath.slice(2)}`));
59
86
  };
package/dist/vite.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.js","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport type { Plugin } from 'vite';\nimport { defineMfNavigation, type IMfNavigationDefinition, type IMfNavigationManifest } from './navigation.js';\n\nconst DEFAULT_FILE_NAME = 'navigation.json';\nconst DEFAULT_ASSET_FILE_NAME = 'module-assets.json';\nconst FILE_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*\\.json$/;\nconst MODULE_ID_PATTERN = /^[a-z][a-z0-9-]*$/;\nconst CONTENT_HASHED_ASSET_PATTERN = /(?:^|\\/)[^/]+-[a-zA-Z0-9_-]{8,}\\.[^/]+$/;\n\nexport interface IMfNavigationPluginOptions {\n fileName?: string;\n navigation: IMfNavigationDefinition;\n}\n\nexport interface IMfSharedDependency {\n requiredVersion: string;\n singleton: false;\n}\n\n// The Angular packages are shared entry point by entry point: each one is a flat ESM file importing the others by\n// package name. An entry point stylesheets also resolve (the `sass` root of @angular/material and @angular/cdk, which\n// `@use '@angular/material'` reaches) is left out, because Module Federation would answer the stylesheet with a script.\n// RxJS subpaths reach its internals by relative path: only its two public entry points are shared, each complete, so a\n// page never mixes RxJS internals from two modules' builds.\nconst SHARED_ANGULAR_SCOPE = '@angular/';\n// Only just-in-time compilation needs these, and the modules are compiled ahead of time. Shared, they would put the\n// compiler (with its ShadowCss placeholders) into every module's build; the modules that bootstrap through\n// platformBrowserDynamic keep their own copy, as before.\nconst UNSHARED_ANGULAR_PACKAGES = new Set(['@angular/compiler', '@angular/platform-browser-dynamic']);\nconst SHARED_RXJS_ENTRY_POINTS = ['rxjs', 'rxjs/operators'] as const;\nconst EXACT_VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/;\nconst SCRIPT_ENTRY_CONDITIONS = 'default,types';\n\nexport interface IMfAngularSharedOptions {\n // The directory whose node_modules holds the module's packages; the Vite config's directory by default.\n root?: string;\n}\n\n// The import and re-export statements of a flat ESM file, which start their line; comments mentioning imports do not.\nconst BARE_IMPORT_PATTERN = /^(?:import|export)\\b[^;'\"]*?(?:\\bfrom\\s*)?['\"]([^'\"./][^'\"]*)['\"]/gm;\n\nconst bareImportPackage = (specifier: string): string =>\n specifier\n .split('/')\n .slice(0, specifier.startsWith('@') ? 2 : 1)\n .join('/');\n\n// Module Federation builds a local copy of every shared entry point, used or not, so an entry point is shared only\n// when every package it imports is installed (`@angular/common/upgrade` needs `@angular/upgrade`, which modules do not\n// install, and `@angular/platform-browser/animations` needs `@angular/animations`).\nconst angularScriptEntryPoints = (packageName: string, root: string): string[] => {\n const resolvePackage = createRequire(join(root, 'package.json'));\n const packageJsonPath = resolvePackage.resolve(`${packageName}/package.json`);\n const isInstalled = (dependency: string): boolean => {\n try {\n resolvePackage.resolve(`${dependency}/package.json`);\n return true;\n } catch {\n return false;\n }\n };\n const { exports } = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { exports?: Record<string, unknown> };\n return Object.entries(exports ?? {})\n .filter(([subpath, target]) => {\n if (\n subpath.includes('*') ||\n subpath.split('/').includes('testing') ||\n typeof target !== 'object' ||\n target === null ||\n Object.keys(target).sort().join(',') !== SCRIPT_ENTRY_CONDITIONS\n ) {\n return false;\n }\n const source = readFileSync(join(dirname(packageJsonPath), (target as { default: string }).default), 'utf8');\n return [...source.matchAll(BARE_IMPORT_PATTERN)].every(([, specifier]) => specifier === undefined || isInstalled(bareImportPackage(specifier)));\n })\n .map(([subpath]) => (subpath === '.' ? packageName : `${packageName}/${subpath.slice(2)}`));\n};\n\n/**\n * The Module Federation `shared` configuration of a hosted Angular module: every script entry point of the `@angular/*`\n * packages among the module's dependencies, and RxJS, at the module's own exact versions. Modules on the same versions\n * load these once per page and share them; a module on another version keeps its own copy instead of mixing two\n * Angular versions.\n */\nexport const createMfAngularShared = (\n dependencies: Readonly<Record<string, string>>,\n { root = process.cwd() }: IMfAngularSharedOptions = {},\n): Record<string, IMfSharedDependency> => {\n const shared: Record<string, IMfSharedDependency> = {};\n for (const [name, version] of Object.entries(dependencies).sort(([left], [right]) => left.localeCompare(right))) {\n const isAngular = name.startsWith(SHARED_ANGULAR_SCOPE) && !UNSHARED_ANGULAR_PACKAGES.has(name);\n if (!isAngular && name !== 'rxjs') {\n continue;\n }\n if (!EXACT_VERSION_PATTERN.test(version)) {\n throw new Error(`Shared dependency ${name} must be pinned to an exact version, not \"${version}\".`);\n }\n for (const entryPoint of isAngular ? angularScriptEntryPoints(name, root) : SHARED_RXJS_ENTRY_POINTS) {\n shared[entryPoint] = { requiredVersion: version, singleton: false };\n }\n }\n return shared;\n};\n\nexport const MF_ASSET_MANIFEST_CONTRACT_VERSION = 1 as const;\n\nexport interface IMfAssetManifest {\n assets: readonly string[];\n contractVersion: typeof MF_ASSET_MANIFEST_CONTRACT_VERSION;\n moduleId: string;\n revision: string;\n}\n\nexport interface IMfAssetManifestPluginOptions {\n fileName?: string;\n moduleId: string;\n}\n\ninterface IMfOutputAsset {\n fileName: string;\n source: string | Uint8Array;\n type: 'asset';\n}\n\ninterface IMfOutputChunk {\n code: string;\n fileName: string;\n imports: readonly string[];\n modules: Readonly<Record<string, unknown>>;\n referencedFiles?: readonly string[];\n type: 'chunk';\n viteMetadata?: { importedAssets?: ReadonlySet<string>; importedCss?: ReadonlySet<string> };\n}\n\ntype TMfOutputBundle = Readonly<Record<string, IMfOutputAsset | IMfOutputChunk>>;\n\nconst serializeDefinition = (definition: Readonly<IMfNavigationDefinition>): string => JSON.stringify(definition);\n\nexport const createMfNavigationManifest = (navigation: IMfNavigationDefinition): Readonly<IMfNavigationManifest> => {\n const definition = defineMfNavigation(navigation);\n const revision = createHash('sha256').update(serializeDefinition(definition)).digest('hex');\n\n return Object.freeze({\n applicationId: definition.applicationId,\n contractVersion: definition.contractVersion,\n items: definition.items,\n label: definition.label,\n landingPath: definition.landingPath,\n moduleId: definition.moduleId,\n revision,\n });\n};\n\nexport const serializeMfNavigationManifest = (navigation: IMfNavigationDefinition): string => {\n return `${JSON.stringify(createMfNavigationManifest(navigation), null, 2)}\\n`;\n};\n\nexport const mfNavigationPlugin = ({ fileName = DEFAULT_FILE_NAME, navigation }: IMfNavigationPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend navigation fileName must be a safe JSON file name.');\n }\n\n const source = serializeMfNavigationManifest(navigation);\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-navigation',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n const requestPath = request.url?.split('?', 1)[0];\n if (requestPath !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(source);\n });\n },\n generateBundle() {\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n\nconst isLifecycleModule = (moduleId: string): boolean => /(?:^|\\/)src\\/lifecycle(?:-impl)?\\.[cm]?[jt]sx?$/.test(moduleId.replaceAll('\\\\', '/'));\n\nconst addChunkDependencies = (bundle: TMfOutputBundle, fileName: string, assets: Set<string>): void => {\n if (assets.has(fileName)) {\n return;\n }\n\n const output = bundle[fileName];\n if (output?.type !== 'chunk') {\n return;\n }\n\n assets.add(fileName);\n for (const importedFileName of output.imports) {\n addChunkDependencies(bundle, importedFileName, assets);\n }\n\n const metadata = output.viteMetadata;\n for (const referencedFileName of [...(metadata?.importedAssets ?? []), ...(metadata?.importedCss ?? []), ...(output.referencedFiles ?? [])]) {\n if (bundle[referencedFileName]) {\n assets.add(referencedFileName);\n }\n }\n};\n\nconst outputBytes = (output: IMfOutputAsset | IMfOutputChunk): string | Uint8Array => (output.type === 'chunk' ? output.code : output.source);\n\nconst createMfAssetManifest = (moduleId: string, bundle: TMfOutputBundle): Readonly<IMfAssetManifest> => {\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const lifecycleChunks = Object.values(bundle).filter(\n (output): output is IMfOutputChunk => output.type === 'chunk' && Object.keys(output.modules).some(isLifecycleModule),\n );\n if (lifecycleChunks.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit a lifecycle chunk.`);\n }\n\n const discoveredAssets = new Set<string>();\n for (const chunk of lifecycleChunks) {\n addChunkDependencies(bundle, chunk.fileName, discoveredAssets);\n }\n const assets = [...discoveredAssets].filter((fileName) => CONTENT_HASHED_ASSET_PATTERN.test(fileName)).sort();\n if (assets.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit content-hashed lifecycle assets.`);\n }\n\n const revisionHash = createHash('sha256');\n for (const fileName of assets) {\n const output = bundle[fileName];\n if (!output) {\n throw new Error(`Microfrontend ${moduleId} asset ${fileName} is missing from the output bundle.`);\n }\n revisionHash.update(fileName).update('\\0').update(outputBytes(output)).update('\\0');\n }\n\n return Object.freeze({\n assets: Object.freeze(assets),\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: revisionHash.digest('hex'),\n });\n};\n\nexport const serializeMfAssetManifest = (manifest: IMfAssetManifest): string => `${JSON.stringify(manifest, null, 2)}\\n`;\n\nexport const mfAssetManifestPlugin = ({ fileName = DEFAULT_ASSET_FILE_NAME, moduleId }: IMfAssetManifestPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend asset fileName must be a safe JSON file name.');\n }\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const developmentManifest = serializeMfAssetManifest({\n assets: [],\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: 'development',\n });\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-assets',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n if (request.url?.split('?', 1)[0] !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Access-Control-Allow-Origin', '*');\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(developmentManifest);\n });\n },\n generateBundle(_options, bundle) {\n const source = serializeMfAssetManifest(createMfAssetManifest(moduleId, bundle as unknown as TMfOutputBundle));\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n"]}
1
+ {"version":3,"file":"vite.js","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport type { Plugin } from 'vite';\nimport { defineMfNavigation, type IMfNavigationDefinition, type IMfNavigationManifest } from './navigation.js';\n\nconst DEFAULT_FILE_NAME = 'navigation.json';\nconst DEFAULT_ASSET_FILE_NAME = 'module-assets.json';\nconst FILE_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*\\.json$/;\nconst MODULE_ID_PATTERN = /^[a-z][a-z0-9-]*$/;\nconst CONTENT_HASHED_ASSET_PATTERN = /(?:^|\\/)[^/]+-[a-zA-Z0-9_-]{8,}\\.[^/]+$/;\n\nexport interface IMfNavigationPluginOptions {\n fileName?: string;\n navigation: IMfNavigationDefinition;\n}\n\nexport interface IMfSharedDependency {\n requiredVersion: string;\n singleton: false;\n}\n\n// The Angular packages are shared entry point by entry point: each one is a flat ESM file importing the others by\n// package name. An entry point stylesheets also resolve (the `sass` root of @angular/material and @angular/cdk, which\n// `@use '@angular/material'` reaches) is left out, because Module Federation would answer the stylesheet with a script.\n// RxJS subpaths reach its internals by relative path: only its two public entry points are shared, each complete, so a\n// page never mixes RxJS internals from two modules' builds.\nconst SHARED_ANGULAR_SCOPE = '@angular/';\n// Only just-in-time compilation needs these, and the modules are compiled ahead of time. Shared, they would put the\n// compiler (with its ShadowCss placeholders) into every module's build; the modules that bootstrap through\n// platformBrowserDynamic keep their own copy, as before.\nconst UNSHARED_ANGULAR_PACKAGES = new Set(['@angular/compiler', '@angular/platform-browser-dynamic']);\nconst SHARED_RXJS_ENTRY_POINTS = ['rxjs', 'rxjs/operators'] as const;\nconst EXACT_VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/;\nconst SCRIPT_ENTRY_CONDITIONS = 'default,types';\n\nexport interface IMfAngularSharedOptions {\n // The directory whose node_modules holds the module's packages; the Vite config's directory by default.\n root?: string;\n}\n\n// The import and re-export statements of a flat ESM file, which start their line; comments mentioning imports do not.\nconst BARE_IMPORT_PATTERN = /^(?:import|export)\\b[^;'\"]*?(?:\\bfrom\\s*)?['\"]([^'\"./][^'\"]*)['\"]/gm;\nconst RELATIVE_IMPORT_PATTERN = /^(?:import|export)\\b[^;'\"]*?(?:\\bfrom\\s*)?['\"](\\.\\.?\\/[^'\"]*)['\"]/gm;\n\nconst bareImportPackage = (specifier: string): string =>\n specifier\n .split('/')\n .slice(0, specifier.startsWith('@') ? 2 : 1)\n .join('/');\n\n// The packages an entry point's local copy would contain: what its file imports, and what the files it imports by\n// relative path (its own chunks) import in turn.\nconst importedPackages = (entryFile: string): Set<string> => {\n const packages = new Set<string>();\n const visited = new Set<string>();\n const visit = (file: string): void => {\n if (visited.has(file) || !existsSync(file)) {\n return;\n }\n visited.add(file);\n const source = readFileSync(file, 'utf8');\n for (const [, specifier] of source.matchAll(BARE_IMPORT_PATTERN)) {\n if (specifier !== undefined) {\n packages.add(bareImportPackage(specifier));\n }\n }\n for (const [, specifier] of source.matchAll(RELATIVE_IMPORT_PATTERN)) {\n if (specifier !== undefined) {\n visit(join(dirname(file), specifier));\n }\n }\n };\n visit(entryFile);\n return packages;\n};\n\n// Module Federation builds a local copy of every shared entry point, used or not, so an entry point is shared only\n// when every package it imports is installed (`@angular/common/upgrade` needs `@angular/upgrade`, which modules do not\n// install, and `@angular/platform-browser/animations` needs `@angular/animations`) and none of them is a package left\n// unshared (the build-time `@angular/localize/tools` reaches the compiler through its own chunks).\nconst angularScriptEntryPoints = (packageName: string, root: string): string[] => {\n const resolvePackage = createRequire(join(root, 'package.json'));\n const packageJsonPath = resolvePackage.resolve(`${packageName}/package.json`);\n const isInstalled = (dependency: string): boolean => {\n try {\n resolvePackage.resolve(`${dependency}/package.json`);\n return true;\n } catch {\n return false;\n }\n };\n const { exports } = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { exports?: Record<string, unknown> };\n return Object.entries(exports ?? {})\n .filter(([subpath, target]) => {\n if (\n subpath.includes('*') ||\n subpath.split('/').includes('testing') ||\n typeof target !== 'object' ||\n target === null ||\n Object.keys(target).sort().join(',') !== SCRIPT_ENTRY_CONDITIONS\n ) {\n return false;\n }\n const entryFile = join(dirname(packageJsonPath), (target as { default: string }).default);\n return [...importedPackages(entryFile)].every((dependency) => isInstalled(dependency) && !UNSHARED_ANGULAR_PACKAGES.has(dependency));\n })\n .map(([subpath]) => (subpath === '.' ? packageName : `${packageName}/${subpath.slice(2)}`));\n};\n\n/**\n * The Module Federation `shared` configuration of a hosted Angular module: every script entry point of the `@angular/*`\n * packages among the module's dependencies, and RxJS, at the module's own exact versions. Modules on the same versions\n * load these once per page and share them; a module on another version keeps its own copy instead of mixing two\n * Angular versions.\n */\nexport const createMfAngularShared = (\n dependencies: Readonly<Record<string, string>>,\n { root = process.cwd() }: IMfAngularSharedOptions = {},\n): Record<string, IMfSharedDependency> => {\n const shared: Record<string, IMfSharedDependency> = {};\n for (const [name, version] of Object.entries(dependencies).sort(([left], [right]) => left.localeCompare(right))) {\n const isAngular = name.startsWith(SHARED_ANGULAR_SCOPE) && !UNSHARED_ANGULAR_PACKAGES.has(name);\n if (!isAngular && name !== 'rxjs') {\n continue;\n }\n if (!EXACT_VERSION_PATTERN.test(version)) {\n throw new Error(`Shared dependency ${name} must be pinned to an exact version, not \"${version}\".`);\n }\n for (const entryPoint of isAngular ? angularScriptEntryPoints(name, root) : SHARED_RXJS_ENTRY_POINTS) {\n shared[entryPoint] = { requiredVersion: version, singleton: false };\n }\n }\n return shared;\n};\n\nexport const MF_ASSET_MANIFEST_CONTRACT_VERSION = 1 as const;\n\nexport interface IMfAssetManifest {\n assets: readonly string[];\n contractVersion: typeof MF_ASSET_MANIFEST_CONTRACT_VERSION;\n moduleId: string;\n revision: string;\n}\n\nexport interface IMfAssetManifestPluginOptions {\n fileName?: string;\n moduleId: string;\n}\n\ninterface IMfOutputAsset {\n fileName: string;\n source: string | Uint8Array;\n type: 'asset';\n}\n\ninterface IMfOutputChunk {\n code: string;\n fileName: string;\n imports: readonly string[];\n modules: Readonly<Record<string, unknown>>;\n referencedFiles?: readonly string[];\n type: 'chunk';\n viteMetadata?: { importedAssets?: ReadonlySet<string>; importedCss?: ReadonlySet<string> };\n}\n\ntype TMfOutputBundle = Readonly<Record<string, IMfOutputAsset | IMfOutputChunk>>;\n\nconst serializeDefinition = (definition: Readonly<IMfNavigationDefinition>): string => JSON.stringify(definition);\n\nexport const createMfNavigationManifest = (navigation: IMfNavigationDefinition): Readonly<IMfNavigationManifest> => {\n const definition = defineMfNavigation(navigation);\n const revision = createHash('sha256').update(serializeDefinition(definition)).digest('hex');\n\n return Object.freeze({\n applicationId: definition.applicationId,\n contractVersion: definition.contractVersion,\n items: definition.items,\n label: definition.label,\n landingPath: definition.landingPath,\n moduleId: definition.moduleId,\n revision,\n });\n};\n\nexport const serializeMfNavigationManifest = (navigation: IMfNavigationDefinition): string => {\n return `${JSON.stringify(createMfNavigationManifest(navigation), null, 2)}\\n`;\n};\n\nexport const mfNavigationPlugin = ({ fileName = DEFAULT_FILE_NAME, navigation }: IMfNavigationPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend navigation fileName must be a safe JSON file name.');\n }\n\n const source = serializeMfNavigationManifest(navigation);\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-navigation',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n const requestPath = request.url?.split('?', 1)[0];\n if (requestPath !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(source);\n });\n },\n generateBundle() {\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n\nconst isLifecycleModule = (moduleId: string): boolean => /(?:^|\\/)src\\/lifecycle(?:-impl)?\\.[cm]?[jt]sx?$/.test(moduleId.replaceAll('\\\\', '/'));\n\nconst addChunkDependencies = (bundle: TMfOutputBundle, fileName: string, assets: Set<string>): void => {\n if (assets.has(fileName)) {\n return;\n }\n\n const output = bundle[fileName];\n if (output?.type !== 'chunk') {\n return;\n }\n\n assets.add(fileName);\n for (const importedFileName of output.imports) {\n addChunkDependencies(bundle, importedFileName, assets);\n }\n\n const metadata = output.viteMetadata;\n for (const referencedFileName of [...(metadata?.importedAssets ?? []), ...(metadata?.importedCss ?? []), ...(output.referencedFiles ?? [])]) {\n if (bundle[referencedFileName]) {\n assets.add(referencedFileName);\n }\n }\n};\n\nconst outputBytes = (output: IMfOutputAsset | IMfOutputChunk): string | Uint8Array => (output.type === 'chunk' ? output.code : output.source);\n\nconst createMfAssetManifest = (moduleId: string, bundle: TMfOutputBundle): Readonly<IMfAssetManifest> => {\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const lifecycleChunks = Object.values(bundle).filter(\n (output): output is IMfOutputChunk => output.type === 'chunk' && Object.keys(output.modules).some(isLifecycleModule),\n );\n if (lifecycleChunks.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit a lifecycle chunk.`);\n }\n\n const discoveredAssets = new Set<string>();\n for (const chunk of lifecycleChunks) {\n addChunkDependencies(bundle, chunk.fileName, discoveredAssets);\n }\n const assets = [...discoveredAssets].filter((fileName) => CONTENT_HASHED_ASSET_PATTERN.test(fileName)).sort();\n if (assets.length === 0) {\n throw new Error(`Microfrontend ${moduleId} did not emit content-hashed lifecycle assets.`);\n }\n\n const revisionHash = createHash('sha256');\n for (const fileName of assets) {\n const output = bundle[fileName];\n if (!output) {\n throw new Error(`Microfrontend ${moduleId} asset ${fileName} is missing from the output bundle.`);\n }\n revisionHash.update(fileName).update('\\0').update(outputBytes(output)).update('\\0');\n }\n\n return Object.freeze({\n assets: Object.freeze(assets),\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: revisionHash.digest('hex'),\n });\n};\n\nexport const serializeMfAssetManifest = (manifest: IMfAssetManifest): string => `${JSON.stringify(manifest, null, 2)}\\n`;\n\nexport const mfAssetManifestPlugin = ({ fileName = DEFAULT_ASSET_FILE_NAME, moduleId }: IMfAssetManifestPluginOptions): Plugin => {\n if (!FILE_NAME_PATTERN.test(fileName)) {\n throw new Error('Microfrontend asset fileName must be a safe JSON file name.');\n }\n if (!MODULE_ID_PATTERN.test(moduleId)) {\n throw new Error('Microfrontend asset moduleId must use lowercase letters, numbers, and hyphens.');\n }\n\n const developmentManifest = serializeMfAssetManifest({\n assets: [],\n contractVersion: MF_ASSET_MANIFEST_CONTRACT_VERSION,\n moduleId,\n revision: 'development',\n });\n const publicPath = `/${fileName}`;\n\n return {\n name: 'edynamix-mf-assets',\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n if (request.url?.split('?', 1)[0] !== publicPath) {\n next();\n return;\n }\n\n response.statusCode = 200;\n response.setHeader('Access-Control-Allow-Origin', '*');\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Content-Type', 'application/json; charset=utf-8');\n response.end(developmentManifest);\n });\n },\n generateBundle(_options, bundle) {\n const source = serializeMfAssetManifest(createMfAssetManifest(moduleId, bundle as unknown as TMfOutputBundle));\n this.emitFile({ fileName, source, type: 'asset' });\n },\n };\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edynamix/mf-isolation",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "CSS and overlay isolation helpers for eDynamix microfrontends.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",