@edynamix/mf-isolation 0.0.15 → 0.0.16

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":"AACA,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,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 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 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":"AACA,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,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 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 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
@@ -63,7 +63,7 @@ const addChunkDependencies = (bundle, fileName, assets) => {
63
63
  addChunkDependencies(bundle, importedFileName, assets);
64
64
  }
65
65
  const metadata = output.viteMetadata;
66
- for (const referencedFileName of [...(metadata?.importedAssets ?? []), ...(metadata?.importedCss ?? []), ...output.referencedFiles]) {
66
+ for (const referencedFileName of [...(metadata?.importedAssets ?? []), ...(metadata?.importedCss ?? []), ...(output.referencedFiles ?? [])]) {
67
67
  if (bundle[referencedFileName]) {
68
68
  assets.add(referencedFileName);
69
69
  }
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 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 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 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 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.15",
3
+ "version": "0.0.16",
4
4
  "description": "CSS and overlay isolation helpers for eDynamix microfrontends.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",