@vercel/microfrontends 1.4.0-canary.5 → 1.4.0-canary.7

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,"sources":["../../src/config/microfrontends/utils/find-config.ts","../../src/config/constants.ts","../../src/config/microfrontends/utils/infer-microfrontends-location.ts","../../src/config/errors.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { join } from 'node:path';\nimport { CONFIGURATION_FILENAMES } from '../../constants';\n\nexport function findConfig({ dir }: { dir: string }): string | null {\n for (const filename of CONFIGURATION_FILENAMES) {\n const maybeConfig = join(dir, filename);\n if (fs.existsSync(maybeConfig)) {\n return maybeConfig;\n }\n }\n\n return null;\n}\n","export const CONFIGURATION_FILENAMES = [\n 'microfrontends.jsonc',\n 'microfrontends.json',\n] as const;\n","import { dirname } from 'node:path';\nimport { readFileSync } from 'node:fs';\nimport { parse } from 'jsonc-parser';\nimport fg from 'fast-glob';\nimport type { Config } from '../../schema/types';\nimport { CONFIGURATION_FILENAMES } from '../../constants';\nimport { MicrofrontendError } from '../../errors';\n\n// cache the path to default configuration to avoid having to walk the file system multiple times\nconst configCache: Record<string, string> = {};\n\ninterface FindDefaultMicrofrontendPackageArgs {\n repositoryRoot: string;\n applicationName: string;\n}\n\n/**\n * Given a repository root and a package name, find the path to the package.json file with the\n * given name.\n *\n * This method uses globby to find all package.json files and then reads them in parallel\n */\nfunction findPackageWithMicrofrontendsConfig({\n repositoryRoot,\n applicationName,\n}: FindDefaultMicrofrontendPackageArgs): string | null {\n try {\n // eslint-disable-next-line import/no-named-as-default-member\n const microfrontendsJsonPaths = fg.globSync(\n `**/{${CONFIGURATION_FILENAMES.join(',')}}`,\n {\n cwd: repositoryRoot,\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n ignore: ['**/node_modules/**', '**/.git/**'],\n },\n );\n\n const matchingPaths: string[] = [];\n for (const microfrontendsJsonPath of microfrontendsJsonPaths) {\n try {\n const microfrontendsJsonContent = readFileSync(\n microfrontendsJsonPath,\n 'utf-8',\n );\n const microfrontendsJson = parse(microfrontendsJsonContent) as Config;\n\n if (microfrontendsJson.applications[applicationName]) {\n matchingPaths.push(microfrontendsJsonPath);\n } else {\n for (const [_, app] of Object.entries(\n microfrontendsJson.applications,\n )) {\n if (app.packageName === applicationName) {\n matchingPaths.push(microfrontendsJsonPath);\n }\n }\n }\n } catch (error) {\n // malformed json most likely, skip this file\n }\n }\n\n if (matchingPaths.length > 1) {\n throw new MicrofrontendError(\n `Found multiple \\`microfrontends.json\\` files in the repository referencing the application \"${applicationName}\", but only one is allowed.\\n${matchingPaths.join('\\n • ')}`,\n { type: 'config', subtype: 'inference_failed' },\n );\n }\n\n if (matchingPaths.length === 0) {\n throw new MicrofrontendError(\n `Could not find a \\`microfrontends.json\\` file in the repository that contains \"applications.${applicationName}\". Microfrontends defined in separate repositories are not supported yet.`,\n { type: 'config', subtype: 'inference_failed' },\n );\n }\n\n const [packageJsonPath] = matchingPaths as [string];\n return dirname(packageJsonPath);\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Given a repository root and a package name, find the path to the package directory with\n * a microfrontends config that contains the given name in its applications.\n */\nexport function inferMicrofrontendsLocation(\n opts: FindDefaultMicrofrontendPackageArgs,\n): string {\n // cache this with name to support multiple configurations in the same repository\n const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;\n\n // Check if we have a cached result\n if (configCache[cacheKey]) {\n return configCache[cacheKey];\n }\n\n const result = findPackageWithMicrofrontendsConfig(opts);\n\n if (!result) {\n throw new MicrofrontendError(\n `Could not infer the location of the \\`microfrontends.json\\` file for application \"${opts.applicationName}\" starting in directory \"${opts.repositoryRoot}\".`,\n { type: 'config', subtype: 'inference_failed' },\n );\n }\n\n // Cache the result\n configCache[cacheKey] = result;\n return result;\n}\n","export type MicrofrontendErrorType =\n | 'config'\n | 'packageJson'\n | 'vercelJson'\n | 'application'\n | 'unknown';\n\nexport type MicrofrontendErrorSubtype =\n | 'not_found'\n | 'inference_failed'\n | 'not_found_in_env'\n | 'invalid_asset_prefix'\n | 'invalid_main_path'\n | 'does_not_match_schema'\n | 'unable_to_read_file'\n | 'unsupported_validation_env'\n | 'unsupported_version'\n | 'invalid_path'\n | 'invalid_permissions'\n | 'invalid_syntax'\n | 'missing_microfrontend_config_path'\n | 'unsupported_operation';\n\n// A mapping of error types to their subtypes.\ninterface TypeToSubtype {\n application:\n | 'invalid_asset_prefix'\n | 'invalid_path'\n | 'multiple_package_managers'\n | 'not_found';\n config:\n | 'conflicting_paths'\n | 'depcrecated_field'\n | 'does_not_match_schema'\n | 'invalid_main_path'\n | 'invalid_preview_deployment_suffix'\n | 'multiple_default_applications'\n | 'no_default_application'\n | 'not_found_in_env'\n | 'not_found'\n | 'inference_failed'\n | 'unable_to_read_file'\n | 'invalid_syntax'\n | 'invalid_permissions'\n | 'unsupported_operation'\n | 'unsupported_validation_env'\n | 'unsupported_version';\n packageJson:\n | 'missing_field_name'\n | 'unable_to_read_file'\n | 'invalid_permissions'\n | 'invalid_syntax';\n vercelJson:\n | 'missing_field_microfrontend_config_path'\n | 'unable_to_read_file'\n | 'invalid_permissions'\n | 'invalid_syntax';\n unknown: never;\n}\n\nexport type MicrofrontendErrorSource =\n | '@vercel/microfrontends'\n | '@vercel/microfrontends/next'\n | 'fs'\n | 'ajv';\n\nexport interface MicrofrontendErrorOptions<T extends MicrofrontendErrorType> {\n cause?: unknown;\n source?: MicrofrontendErrorSource;\n type?: T;\n subtype?: TypeToSubtype[T];\n}\n\ninterface HandleOptions {\n fileName?: string;\n}\n\nexport class MicrofrontendError<\n T extends MicrofrontendErrorType = 'unknown',\n> extends Error {\n public source: MicrofrontendErrorSource;\n public type: T;\n public subtype?: TypeToSubtype[T];\n\n constructor(message: string, opts?: MicrofrontendErrorOptions<T>) {\n super(message, { cause: opts?.cause });\n this.name = 'MicrofrontendsError';\n this.source = opts?.source ?? '@vercel/microfrontends';\n this.type = opts?.type ?? ('unknown' as T);\n this.subtype = opts?.subtype;\n Error.captureStackTrace(this, MicrofrontendError);\n }\n\n isKnown(): boolean {\n return this.type !== 'unknown';\n }\n\n isUnknown(): boolean {\n return !this.isKnown();\n }\n\n /**\n * Converts an error to a MicrofrontendsError.\n * @param original - The original error to convert.\n * @returns The converted MicrofrontendsError.\n */\n static convert(\n original: Error,\n opts?: HandleOptions,\n ): MicrofrontendError<MicrofrontendErrorType> {\n if (opts?.fileName) {\n const err = MicrofrontendError.convertFSError(original, opts.fileName);\n if (err) {\n return err;\n }\n }\n\n if (\n original.message.includes(\n 'Code generation from strings disallowed for this context',\n )\n ) {\n return new MicrofrontendError(original.message, {\n type: 'config',\n subtype: 'unsupported_validation_env',\n source: 'ajv',\n });\n }\n\n // unknown catch-all\n return new MicrofrontendError(original.message);\n }\n\n static convertFSError(\n original: Error,\n fileName: string,\n ): MicrofrontendError<MicrofrontendErrorType> | null {\n if (original instanceof Error && 'code' in original) {\n if (original.code === 'ENOENT') {\n return new MicrofrontendError(`Could not find \"${fileName}\"`, {\n type: 'config',\n subtype: 'unable_to_read_file',\n source: 'fs',\n });\n }\n if (original.code === 'EACCES') {\n return new MicrofrontendError(\n `Permission denied while accessing \"${fileName}\"`,\n {\n type: 'config',\n subtype: 'invalid_permissions',\n source: 'fs',\n },\n );\n }\n }\n\n if (original instanceof SyntaxError) {\n return new MicrofrontendError(\n `Failed to parse \"${fileName}\": Invalid JSON format.`,\n {\n type: 'config',\n subtype: 'invalid_syntax',\n source: 'fs',\n },\n );\n }\n\n return null;\n }\n\n /**\n * Handles an unknown error and returns a MicrofrontendsError instance.\n * @param err - The error to handle.\n * @returns A MicrofrontendsError instance.\n */\n static handle(\n err: unknown,\n opts?: HandleOptions,\n ): MicrofrontendError<MicrofrontendErrorType> {\n if (err instanceof MicrofrontendError) {\n return err as MicrofrontendError<MicrofrontendErrorType>;\n }\n\n // handle Error instances\n if (err instanceof Error) {\n return MicrofrontendError.convert(err, opts);\n }\n\n // handle object errors\n if (typeof err === 'object' && err !== null) {\n if ('message' in err && typeof err.message === 'string') {\n return MicrofrontendError.convert(new Error(err.message), opts);\n }\n }\n\n return new MicrofrontendError('An unknown error occurred');\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/config/microfrontends/utils/find-config.ts","../../src/config/constants.ts","../../src/config/microfrontends/utils/infer-microfrontends-location.ts","../../src/config/errors.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { join } from 'node:path';\nimport { CONFIGURATION_FILENAMES } from '../../constants';\n\nexport function findConfig({ dir }: { dir: string }): string | null {\n for (const filename of CONFIGURATION_FILENAMES) {\n const maybeConfig = join(dir, filename);\n if (fs.existsSync(maybeConfig)) {\n return maybeConfig;\n }\n }\n\n return null;\n}\n","export const CONFIGURATION_FILENAMES = [\n 'microfrontends.jsonc',\n 'microfrontends.json',\n] as const;\n","import { dirname } from 'node:path';\nimport { readFileSync } from 'node:fs';\nimport { parse } from 'jsonc-parser';\nimport fg from 'fast-glob';\nimport type { Config } from '../../schema/types';\nimport { CONFIGURATION_FILENAMES } from '../../constants';\nimport { MicrofrontendError } from '../../errors';\n\n// cache the path to default configuration to avoid having to walk the file system multiple times\nconst configCache: Record<string, string> = {};\n\ninterface FindDefaultMicrofrontendPackageArgs {\n repositoryRoot: string;\n applicationName: string;\n}\n\n/**\n * Given a repository root and a package name, find the path to the package.json file with the\n * given name.\n *\n * This method uses globby to find all package.json files and then reads them in parallel\n */\nfunction findPackageWithMicrofrontendsConfig({\n repositoryRoot,\n applicationName,\n}: FindDefaultMicrofrontendPackageArgs): string | null {\n try {\n // eslint-disable-next-line import/no-named-as-default-member\n const microfrontendsJsonPaths = fg.globSync(\n `**/{${CONFIGURATION_FILENAMES.join(',')}}`,\n {\n cwd: repositoryRoot,\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n ignore: ['**/node_modules/**', '**/.git/**'],\n },\n );\n\n const matchingPaths: string[] = [];\n for (const microfrontendsJsonPath of microfrontendsJsonPaths) {\n try {\n const microfrontendsJsonContent = readFileSync(\n microfrontendsJsonPath,\n 'utf-8',\n );\n const microfrontendsJson = parse(microfrontendsJsonContent) as Config;\n\n if (microfrontendsJson.applications[applicationName]) {\n matchingPaths.push(microfrontendsJsonPath);\n } else {\n for (const [_, app] of Object.entries(\n microfrontendsJson.applications,\n )) {\n if (app.packageName === applicationName) {\n matchingPaths.push(microfrontendsJsonPath);\n }\n }\n }\n } catch (error) {\n // malformed json most likely, skip this file\n }\n }\n\n if (matchingPaths.length > 1) {\n throw new MicrofrontendError(\n `Found multiple \\`microfrontends.json\\` files in the repository referencing the application \"${applicationName}\", but only one is allowed.\\n${matchingPaths.join('\\n • ')}`,\n { type: 'config', subtype: 'inference_failed' },\n );\n }\n\n if (matchingPaths.length === 0) {\n throw new MicrofrontendError(\n `Could not find a \\`microfrontends.json\\` file in the repository that contains \"applications.${applicationName}\". If your Vercel Microfrontends configuration is not in this repository, you can use the Vercel CLI to pull the Vercel Microfrontends configuration using the \"vercel microfrontends pull\" command, or you can specify the path manually using the VC_MICROFRONTENDS_CONFIG environment variable. If you suspect this is thrown in error, please reach out to the Vercel team.`,\n { type: 'config', subtype: 'inference_failed' },\n );\n }\n\n const [packageJsonPath] = matchingPaths as [string];\n return dirname(packageJsonPath);\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Given a repository root and a package name, find the path to the package directory with\n * a microfrontends config that contains the given name in its applications.\n */\nexport function inferMicrofrontendsLocation(\n opts: FindDefaultMicrofrontendPackageArgs,\n): string {\n // cache this with name to support multiple configurations in the same repository\n const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;\n\n // Check if we have a cached result\n if (configCache[cacheKey]) {\n return configCache[cacheKey];\n }\n\n const result = findPackageWithMicrofrontendsConfig(opts);\n\n if (!result) {\n throw new MicrofrontendError(\n `Could not infer the location of the \\`microfrontends.json\\` file for application \"${opts.applicationName}\" starting in directory \"${opts.repositoryRoot}\".`,\n { type: 'config', subtype: 'inference_failed' },\n );\n }\n\n // Cache the result\n configCache[cacheKey] = result;\n return result;\n}\n","export type MicrofrontendErrorType =\n | 'config'\n | 'packageJson'\n | 'vercelJson'\n | 'application'\n | 'unknown';\n\nexport type MicrofrontendErrorSubtype =\n | 'not_found'\n | 'inference_failed'\n | 'not_found_in_env'\n | 'invalid_asset_prefix'\n | 'invalid_main_path'\n | 'does_not_match_schema'\n | 'unable_to_read_file'\n | 'unsupported_validation_env'\n | 'unsupported_version'\n | 'invalid_path'\n | 'invalid_permissions'\n | 'invalid_syntax'\n | 'missing_microfrontend_config_path'\n | 'unsupported_operation';\n\n// A mapping of error types to their subtypes.\ninterface TypeToSubtype {\n application:\n | 'invalid_asset_prefix'\n | 'invalid_path'\n | 'multiple_package_managers'\n | 'not_found';\n config:\n | 'conflicting_paths'\n | 'depcrecated_field'\n | 'does_not_match_schema'\n | 'invalid_main_path'\n | 'invalid_preview_deployment_suffix'\n | 'multiple_default_applications'\n | 'no_default_application'\n | 'not_found_in_env'\n | 'not_found'\n | 'inference_failed'\n | 'unable_to_read_file'\n | 'invalid_syntax'\n | 'invalid_permissions'\n | 'unsupported_operation'\n | 'unsupported_validation_env'\n | 'unsupported_version';\n packageJson:\n | 'missing_field_name'\n | 'unable_to_read_file'\n | 'invalid_permissions'\n | 'invalid_syntax';\n vercelJson:\n | 'missing_field_microfrontend_config_path'\n | 'unable_to_read_file'\n | 'invalid_permissions'\n | 'invalid_syntax';\n unknown: never;\n}\n\nexport type MicrofrontendErrorSource =\n | '@vercel/microfrontends'\n | '@vercel/microfrontends/next'\n | 'fs'\n | 'ajv';\n\nexport interface MicrofrontendErrorOptions<T extends MicrofrontendErrorType> {\n cause?: unknown;\n source?: MicrofrontendErrorSource;\n type?: T;\n subtype?: TypeToSubtype[T];\n}\n\ninterface HandleOptions {\n fileName?: string;\n}\n\nexport class MicrofrontendError<\n T extends MicrofrontendErrorType = 'unknown',\n> extends Error {\n public source: MicrofrontendErrorSource;\n public type: T;\n public subtype?: TypeToSubtype[T];\n\n constructor(message: string, opts?: MicrofrontendErrorOptions<T>) {\n super(message, { cause: opts?.cause });\n this.name = 'MicrofrontendsError';\n this.source = opts?.source ?? '@vercel/microfrontends';\n this.type = opts?.type ?? ('unknown' as T);\n this.subtype = opts?.subtype;\n Error.captureStackTrace(this, MicrofrontendError);\n }\n\n isKnown(): boolean {\n return this.type !== 'unknown';\n }\n\n isUnknown(): boolean {\n return !this.isKnown();\n }\n\n /**\n * Converts an error to a MicrofrontendsError.\n * @param original - The original error to convert.\n * @returns The converted MicrofrontendsError.\n */\n static convert(\n original: Error,\n opts?: HandleOptions,\n ): MicrofrontendError<MicrofrontendErrorType> {\n if (opts?.fileName) {\n const err = MicrofrontendError.convertFSError(original, opts.fileName);\n if (err) {\n return err;\n }\n }\n\n if (\n original.message.includes(\n 'Code generation from strings disallowed for this context',\n )\n ) {\n return new MicrofrontendError(original.message, {\n type: 'config',\n subtype: 'unsupported_validation_env',\n source: 'ajv',\n });\n }\n\n // unknown catch-all\n return new MicrofrontendError(original.message);\n }\n\n static convertFSError(\n original: Error,\n fileName: string,\n ): MicrofrontendError<MicrofrontendErrorType> | null {\n if (original instanceof Error && 'code' in original) {\n if (original.code === 'ENOENT') {\n return new MicrofrontendError(`Could not find \"${fileName}\"`, {\n type: 'config',\n subtype: 'unable_to_read_file',\n source: 'fs',\n });\n }\n if (original.code === 'EACCES') {\n return new MicrofrontendError(\n `Permission denied while accessing \"${fileName}\"`,\n {\n type: 'config',\n subtype: 'invalid_permissions',\n source: 'fs',\n },\n );\n }\n }\n\n if (original instanceof SyntaxError) {\n return new MicrofrontendError(\n `Failed to parse \"${fileName}\": Invalid JSON format.`,\n {\n type: 'config',\n subtype: 'invalid_syntax',\n source: 'fs',\n },\n );\n }\n\n return null;\n }\n\n /**\n * Handles an unknown error and returns a MicrofrontendsError instance.\n * @param err - The error to handle.\n * @returns A MicrofrontendsError instance.\n */\n static handle(\n err: unknown,\n opts?: HandleOptions,\n ): MicrofrontendError<MicrofrontendErrorType> {\n if (err instanceof MicrofrontendError) {\n return err as MicrofrontendError<MicrofrontendErrorType>;\n }\n\n // handle Error instances\n if (err instanceof Error) {\n return MicrofrontendError.convert(err, opts);\n }\n\n // handle object errors\n if (typeof err === 'object' && err !== null) {\n if ('message' in err && typeof err.message === 'string') {\n return MicrofrontendError.convert(new Error(err.message), opts);\n }\n }\n\n return new MicrofrontendError('An unknown error occurred');\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- "use strict";var W=Object.create;var E=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,j=Object.prototype.hasOwnProperty;var Q=(e,t)=>{for(var n in t)E(e,n,{get:t[n],enumerable:!0})},_=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of G(t))!j.call(e,r)&&r!==n&&E(e,r,{get:()=>t[r],enumerable:!(o=q(t,r))||o.enumerable});return e};var M=(e,t,n)=>(n=e!=null?W(K(e)):{},_(t||!e||!e.__esModule?E(n,"default",{value:e,enumerable:!0}):n,e)),Y=e=>_(E({},"__esModule",{value:!0}),e);var fe={};Q(fe,{Image:()=>U,Link:()=>Z,PrefetchCrossZoneLinks:()=>ie,PrefetchCrossZoneLinksContext:()=>P,PrefetchCrossZoneLinksProvider:()=>re,useZoneForHref:()=>H});module.exports=Y(fe);var m=require("react"),S=M(require("next/link.js"),1);var u=require("react");var R=require("path-to-regexp"),O=new Map,ee=e=>{let t=O.get(e);if(t)return t;let n=(0,R.pathToRegexp)(e);return O.set(e,n),n},l=class{constructor(t,n){this.pathCache={};if(this.serialized=t,n?.removeFlaggedPaths)for(let o of Object.values(t.applications))o.routing&&(o.routing=o.routing.filter(r=>!r.flag));this.applications=t.applications}static fromEnv(t,n){if(!t)throw new Error("Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?");return new l(JSON.parse(t),n)}isEqual(t){return this===t||JSON.stringify(this.applications)===JSON.stringify(t.applications)}getApplicationNameForPath(t){if(!t.startsWith("/"))throw new Error("Path must start with a /");if(this.pathCache[t])return this.pathCache[t];let n=new URL(t,"https://example.com").pathname;for(let[r,a]of Object.entries(this.applications))if(a.routing){for(let i of a.routing)for(let s of i.paths)if(ee(s).test(n))return this.pathCache[t]=r,r}let o=Object.entries(this.applications).find(([,r])=>r.default);return o?(this.pathCache[t]=o[0],o[0]):null}serialize(){return this.serialized}};var F=new Map,T=new Map,te=e=>JSON.stringify({removeFlaggedPaths:e?.removeFlaggedPaths||!1}),I=(e,t)=>{let n=te(t),o=F.get(e||"");if(!o)o=new Map,F.set(e||"",o);else{let a=o.get(n);if(a)return a}let r=l.fromEnv(e,t);return o.set(n,r),r},x=null,L=null;async function ne(){try{let e=await fetch("/.well-known/vercel/microfrontends/client-config");if(e.status!==200)return null;let t=await e.json(),n=new l(t.config);return L=n,n}catch{return null}}function d(e,{removeFlaggedPathsFromDefault:t}={}){let[n,o]=(0,u.useState)(()=>L??I(e,{removeFlaggedPaths:t})),r=(0,u.useMemo)(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"||L)return!1;let s=T.get(e||"");if(s!==void 0)return s;let g=I(e),C=Object.values(g.applications).some($=>$.routing?.some(V=>V.flag));return T.set(e||"",C),!!C},[e]),[a,i]=(0,u.useState)(r);return(0,u.useEffect)(()=>{r&&(x||(x=ne()),x.then(s=>{s&&o(g=>g.isEqual(s)?g:s)}).finally(()=>{i(!1)}))},[e,n.applications,r]),{clientConfig:n,isLoading:a}}var c=require("react"),p=require("react/jsx-runtime"),P=(0,c.createContext)({prefetchHref:()=>{}});function re({children:e}){let[t,n]=(0,c.useState)(new Set),o=(0,c.useRef)(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),r=(0,c.useCallback)(i=>{(0,c.startTransition)(()=>{n(s=>s.has(i)?s:new Set(s).add(i))})},[]),a=(0,c.useMemo)(()=>({prefetchHref:r}),[r]);return o.current?(0,p.jsxs)(P.Provider,{value:a,children:[e,[...t].map(i=>(0,p.jsx)("link",{as:"fetch",href:i,rel:"preload"},i))]}):(0,p.jsx)(p.Fragment,{children:e})}var h=require("react"),w=M(require("next/script.js"),1);var A=require("react/jsx-runtime"),y="data-prefetch",f={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${y}]`},b={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}}]},oe={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}},{selector_matches:f.prefetch}]};function k(e){if(!e)return!0;if("checkVisibility"in e)return e.checkVisibility({opacityProperty:!0});let t=e,n=window.getComputedStyle(t);return n.display==="none"||n.visibility==="hidden"||n.opacity==="0"?!1:k(t.parentElement)}function ie(){let{isLoading:e}=d(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[t,n]=(0,h.useState)([]);return(0,h.useEffect)(()=>{if(e)return;let r=new IntersectionObserver(a=>{a.forEach(i=>{i.isIntersecting&&!i.target.hasAttribute(y)&&k(i.target)&&i.target.setAttribute(y,"true")})},{root:null,rootMargin:"0px",threshold:.1});return t.forEach(a=>r.observe(a)),()=>{r.disconnect()}},[e,t]),(0,h.useEffect)(()=>{if(e)return;let r=new MutationObserver(a=>{a.some(s=>s.type==="childList"&&s.addedNodes.length>0||s.type==="attributes"&&s.attributeName==="href")&&n(Array.from(document.querySelectorAll(`a${f.anyZone}:not(${f.prefetch}):not(${f.sameZone}):not(${f.external})`)))});return r.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{r.disconnect()}},[e]),e?null:(0,A.jsx)(w.default,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:b},{eagerness:"immediate",where:oe}],prerender:[{eagerness:"conservative",where:b}]})},id:"prefetch-zones-links",type:"speculationrules"})}var v=require("react/jsx-runtime"),se=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function H(e){let{clientConfig:t,isLoading:n}=d(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),{isRelativePath:o,zoneOfHref:r}=(0,m.useMemo)(()=>{let i=typeof e=="string"&&e.startsWith("/");return{isRelativePath:i,zoneOfHref:i?t.getApplicationNameForPath(e):null}},[t,e]);return typeof e=="string"&&!e.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:r,isDifferentZone:!o||(r?se!==r:!1),isLoading:n}}var Z=(0,m.forwardRef)(({children:e,...t},n)=>{let{prefetchHref:o}=(0,m.useContext)(P),{zoneOfHref:r,isDifferentZone:a,isLoading:i}=H(t.href);function s(){t.href&&o(t.href)}if(a&&r!==null){let{prefetch:g,...C}=t;return(0,v.jsx)("a",{...C,"data-zone":r,onFocus:t.prefetch!==!1?s:void 0,onMouseOver:t.prefetch!==!1?s:void 0,children:e})}return(0,v.jsx)(S.default,{...t,"data-zone":r?"same":"null",prefetch:t.prefetch??(i?!1:void 0),ref:n,children:e})});Z.displayName="MicrofrontendsLink";var z=require("react"),B=require("next/dist/client/image-component.js"),J=require("next/image.js");var ae="vc-ap";function D({name:e}){if(!e)throw new Error("Name is required to generate an asset prefix");return`${ae}-${e}`}var X=require("react/jsx-runtime"),N=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION,ce=(e,t)=>()=>`/${e}${t}`,U=(0,z.forwardRef)(({...e},t)=>{let{clientConfig:n}=d(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),o=N&&!n.applications[N]?.default?D({name:N}):null,{props:{src:r}}=(0,J.getImageProps)(e);return(0,X.jsx)(B.Image,{loader:o?ce(o,r):void 0,...e,ref:t})});U.displayName="MicrofrontendsImage";0&&(module.exports={Image,Link,PrefetchCrossZoneLinks,PrefetchCrossZoneLinksContext,PrefetchCrossZoneLinksProvider,useZoneForHref});
2
+ "use strict";var z=Object.create;var m=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,U=Object.prototype.hasOwnProperty;var X=(e,t)=>{for(var n in t)m(e,n,{get:t[n],enumerable:!0})},M=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of B(t))!U.call(e,r)&&r!==n&&m(e,r,{get:()=>t[r],enumerable:!(o=J(t,r))||o.enumerable});return e};var _=(e,t,n)=>(n=e!=null?z(V(e)):{},M(t||!e||!e.__esModule?m(n,"default",{value:e,enumerable:!0}):n,e)),W=e=>M(m({},"__esModule",{value:!0}),e);var ee={};X(ee,{Link:()=>Z,PrefetchCrossZoneLinks:()=>Q,PrefetchCrossZoneLinksContext:()=>P,PrefetchCrossZoneLinksProvider:()=>G,useZoneForHref:()=>H});module.exports=W(ee);var g=require("react"),A=_(require("next/link.js"),1);var u=require("react");var N=require("path-to-regexp"),O=new Map,$=e=>{let t=O.get(e);if(t)return t;let n=(0,N.pathToRegexp)(e);return O.set(e,n),n},f=class{constructor(t,n){this.pathCache={};if(this.serialized=t,n?.removeFlaggedPaths)for(let o of Object.values(t.applications))o.routing&&(o.routing=o.routing.filter(r=>!r.flag));this.applications=t.applications}static fromEnv(t,n){if(!t)throw new Error("Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?");return new f(JSON.parse(t),n)}isEqual(t){return this===t||JSON.stringify(this.applications)===JSON.stringify(t.applications)}getApplicationNameForPath(t){if(!t.startsWith("/"))throw new Error("Path must start with a /");if(this.pathCache[t])return this.pathCache[t];let n=new URL(t,"https://example.com").pathname;for(let[r,a]of Object.entries(this.applications))if(a.routing){for(let i of a.routing)for(let s of i.paths)if($(s).test(n))return this.pathCache[t]=r,r}let o=Object.entries(this.applications).find(([,r])=>r.default);return o?(this.pathCache[t]=o[0],o[0]):null}serialize(){return this.serialized}};var R=new Map,b=new Map,K=e=>JSON.stringify({removeFlaggedPaths:e?.removeFlaggedPaths||!1}),k=(e,t)=>{let n=K(t),o=R.get(e||"");if(!o)o=new Map,R.set(e||"",o);else{let a=o.get(n);if(a)return a}let r=f.fromEnv(e,t);return o.set(n,r),r},y=null,L=null;async function q(){try{let e=await fetch("/.well-known/vercel/microfrontends/client-config");if(e.status!==200)return null;let t=await e.json(),n=new f(t.config);return L=n,n}catch{return null}}function E(e,{removeFlaggedPathsFromDefault:t}={}){let[n,o]=(0,u.useState)(()=>L??k(e,{removeFlaggedPaths:t})),r=(0,u.useMemo)(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"||L)return!1;let s=b.get(e||"");if(s!==void 0)return s;let d=k(e),C=Object.values(d.applications).some(I=>I.routing?.some(D=>D.flag));return b.set(e||"",C),!!C},[e]),[a,i]=(0,u.useState)(r);return(0,u.useEffect)(()=>{r&&(y||(y=q()),y.then(s=>{s&&o(d=>d.isEqual(s)?d:s)}).finally(()=>{i(!1)}))},[e,n.applications,r]),{clientConfig:n,isLoading:a}}var c=require("react"),p=require("react/jsx-runtime"),P=(0,c.createContext)({prefetchHref:()=>{}});function G({children:e}){let[t,n]=(0,c.useState)(new Set),o=(0,c.useRef)(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),r=(0,c.useCallback)(i=>{(0,c.startTransition)(()=>{n(s=>s.has(i)?s:new Set(s).add(i))})},[]),a=(0,c.useMemo)(()=>({prefetchHref:r}),[r]);return o.current?(0,p.jsxs)(P.Provider,{value:a,children:[e,[...t].map(i=>(0,p.jsx)("link",{as:"fetch",href:i,rel:"preload"},i))]}):(0,p.jsx)(p.Fragment,{children:e})}var h=require("react"),S=_(require("next/script.js"),1);var T=require("react/jsx-runtime"),v="data-prefetch",l={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${v}]`},w={and:[{href_matches:"/*"},{selector_matches:l.anyZone},{not:{selector_matches:l.sameZone}},{not:{selector_matches:l.external}}]},j={and:[{href_matches:"/*"},{selector_matches:l.anyZone},{not:{selector_matches:l.sameZone}},{not:{selector_matches:l.external}},{selector_matches:l.prefetch}]};function F(e){if(!e)return!0;if("checkVisibility"in e)return e.checkVisibility({opacityProperty:!0});let t=e,n=window.getComputedStyle(t);return n.display==="none"||n.visibility==="hidden"||n.opacity==="0"?!1:F(t.parentElement)}function Q(){let{isLoading:e}=E(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[t,n]=(0,h.useState)([]);return(0,h.useEffect)(()=>{if(e)return;let r=new IntersectionObserver(a=>{a.forEach(i=>{i.isIntersecting&&!i.target.hasAttribute(v)&&F(i.target)&&i.target.setAttribute(v,"true")})},{root:null,rootMargin:"0px",threshold:.1});return t.forEach(a=>r.observe(a)),()=>{r.disconnect()}},[e,t]),(0,h.useEffect)(()=>{if(e)return;let r=new MutationObserver(a=>{a.some(s=>s.type==="childList"&&s.addedNodes.length>0||s.type==="attributes"&&s.attributeName==="href")&&n(Array.from(document.querySelectorAll(`a${l.anyZone}:not(${l.prefetch}):not(${l.sameZone}):not(${l.external})`)))});return r.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{r.disconnect()}},[e]),e?null:(0,T.jsx)(S.default,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:w},{eagerness:"immediate",where:j}],prerender:[{eagerness:"conservative",where:w}]})},id:"prefetch-zones-links",type:"speculationrules"})}var x=require("react/jsx-runtime"),Y=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function H(e){let{clientConfig:t,isLoading:n}=E(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),{isRelativePath:o,zoneOfHref:r}=(0,g.useMemo)(()=>{let i=typeof e=="string"&&e.startsWith("/");return{isRelativePath:i,zoneOfHref:i?t.getApplicationNameForPath(e):null}},[t,e]);return typeof e=="string"&&!e.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:r,isDifferentZone:!o||(r?Y!==r:!1),isLoading:n}}var Z=(0,g.forwardRef)(({children:e,...t},n)=>{let{prefetchHref:o}=(0,g.useContext)(P),{zoneOfHref:r,isDifferentZone:a,isLoading:i}=H(t.href);function s(){t.href&&o(t.href)}if(a&&r!==null){let{prefetch:d,...C}=t;return(0,x.jsx)("a",{...C,"data-zone":r,onFocus:t.prefetch!==!1?s:void 0,onMouseOver:t.prefetch!==!1?s:void 0,children:e})}return(0,x.jsx)(A.default,{...t,"data-zone":r?"same":"null",prefetch:t.prefetch??(i?!1:void 0),ref:n,children:e})});Z.displayName="MicrofrontendsLink";0&&(module.exports={Link,PrefetchCrossZoneLinks,PrefetchCrossZoneLinksContext,PrefetchCrossZoneLinksProvider,useZoneForHref});
3
3
  //# sourceMappingURL=client.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/next/client/index.ts","../../src/next/client/link/microfrontends-link.tsx","../../src/config/react/use-client-config.ts","../../src/config/microfrontends-config/client/index.ts","../../src/next/client/prefetch/prefetch-cross-zone-links-context.tsx","../../src/next/client/prefetch/prefetch-cross-zone-links.tsx","../../src/next/client/image/microfrontends-image.tsx","../../src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts"],"sourcesContent":["export * from './link';\nexport * from './prefetch';\nexport * from './image';\n","import type { AnchorHTMLAttributes } from 'react';\nimport { forwardRef, useContext, useMemo } from 'react';\nimport NextLink, {\n type LinkProps as ExternalNextLinkProps,\n} from 'next/link.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\nimport { PrefetchCrossZoneLinksContext } from '../prefetch';\n\ninterface BaseProps {\n children: React.ReactNode;\n href: string;\n}\n\n// fix for tsc inlining LinkProps from next\n// https://github.com/microsoft/TypeScript/issues/37151#issuecomment-756232934\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\ninterface NextLinkProps extends ExternalNextLinkProps {}\nexport type LinkProps = BaseProps &\n Omit<NextLinkProps, keyof BaseProps> &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseProps>;\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nexport function useZoneForHref(href: LinkProps['href'] | undefined): {\n zoneOfHref: string | null;\n isDifferentZone: boolean;\n isLoading: boolean;\n} {\n const { clientConfig, isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n {\n removeFlaggedPathsFromDefault: true,\n },\n );\n const { isRelativePath, zoneOfHref } = useMemo(() => {\n const isRelative = typeof href === 'string' && href.startsWith('/');\n return {\n isRelativePath: isRelative,\n zoneOfHref: isRelative\n ? clientConfig.getApplicationNameForPath(href)\n : null,\n };\n }, [clientConfig, href]);\n\n if (typeof href === 'string' && !href.length) {\n return {\n zoneOfHref: null,\n isDifferentZone: false,\n isLoading: false,\n };\n }\n const isDifferentZone =\n !isRelativePath || (zoneOfHref ? CURRENT_ZONE !== zoneOfHref : false);\n return { zoneOfHref, isDifferentZone, isLoading };\n}\n\n/**\n * A Link component that works with microfrontend set-ups and will prefetch the\n * cross zone links automatically.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ children, ...props }, ref): JSX.Element => {\n const { prefetchHref } = useContext(PrefetchCrossZoneLinksContext);\n const { zoneOfHref, isDifferentZone, isLoading } = useZoneForHref(\n props.href,\n );\n\n function onHoverPrefetch(): void {\n if (!props.href) {\n return;\n }\n prefetchHref(props.href);\n }\n\n if (isDifferentZone && zoneOfHref !== null) {\n const { prefetch: _, ...rest } = props;\n return (\n <a\n {...rest}\n data-zone={zoneOfHref}\n onFocus={props.prefetch !== false ? onHoverPrefetch : undefined}\n onMouseOver={props.prefetch !== false ? onHoverPrefetch : undefined}\n >\n {children}\n </a>\n );\n }\n\n return (\n <NextLink\n {...props}\n data-zone={!zoneOfHref ? 'null' : 'same'}\n prefetch={props.prefetch ?? (isLoading ? false : undefined)}\n ref={ref}\n >\n {children}\n </NextLink>\n );\n },\n);\nLink.displayName = 'MicrofrontendsLink';\n","'use client';\n\nimport { useState, useEffect, useMemo } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\nimport type { MicrofrontendConfigClientOptions } from '../microfrontends-config/client';\n\nconst clientCache = new Map<string, Map<string, MicrofrontendConfigClient>>();\nconst cachedHasDynamicPaths = new Map<string, boolean>();\n\nconst getOptsKey = (opts?: MicrofrontendConfigClientOptions): string => {\n return JSON.stringify({\n removeFlaggedPaths: opts?.removeFlaggedPaths || false,\n });\n};\n\nconst getClient = (\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n) => {\n const optsKey = getOptsKey(opts);\n let configCache = clientCache.get(config || '');\n if (!configCache) {\n configCache = new Map();\n clientCache.set(config || '', configCache);\n } else {\n const existing = configCache.get(optsKey);\n if (existing) {\n return existing;\n }\n }\n\n const client = MicrofrontendConfigClient.fromEnv(config, opts);\n configCache.set(optsKey, client);\n return client;\n};\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n null;\n\nlet cachedServerClient: MicrofrontendConfigClient | null = null;\n\nasync function fetchClientConfigFromServer(): Promise<MicrofrontendConfigClient | null> {\n try {\n const response = await fetch(\n '/.well-known/vercel/microfrontends/client-config',\n );\n if (response.status !== 200) {\n return null;\n }\n const responseJson = (await response.json()) as WellKnownClientData;\n const client = new MicrofrontendConfigClient(responseJson.config);\n cachedServerClient = client;\n return client;\n } catch (err) {\n return null;\n }\n}\n\n/**\n * Hook to use the client microfrontends configuration. This hook will resolve\n * dynamic paths by fetching the configuration from the server if necessary,\n * allowing the server to specify the values for dynamic paths.\n */\nexport function useClientConfig(\n config: string | undefined,\n {\n removeFlaggedPathsFromDefault,\n }: {\n removeFlaggedPathsFromDefault?: boolean;\n } = {},\n): {\n clientConfig: MicrofrontendConfigClient;\n isLoading: boolean;\n} {\n const [clientConfig, setClientConfig] = useState<MicrofrontendConfigClient>(\n () =>\n cachedServerClient ??\n getClient(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const canLoad = useMemo(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n return false;\n }\n // If we've already fetched the server config and it's resolved, we don't need\n // to enter the loading state at all\n if (cachedServerClient) return false;\n // If we've already checked this config for dynamic paths, we can use the\n // cached result from before instead of reevaluating.\n const existing = cachedHasDynamicPaths.get(config || '');\n if (existing !== undefined) return existing;\n // Since we may remove flagged paths from the client config above, we need\n // to use the original client config to determine if the config has any\n // dynamic paths.\n const originalClientConfig = getClient(config);\n // As an optimization, only fetch the config from the server if the\n // microfrontends configuration has any dynamic paths. If it doesn't,\n // then the server won't return any different values.\n const hasDynamicPaths = Object.values(\n originalClientConfig.applications,\n ).some((app) => app.routing?.some((group) => group.flag));\n cachedHasDynamicPaths.set(config || '', hasDynamicPaths);\n if (!hasDynamicPaths) {\n return false;\n }\n return true;\n }, [config]);\n const [isLoading, setIsLoading] = useState(canLoad);\n useEffect(() => {\n if (!canLoad) return;\n if (!cachedServerClientConfigPromise) {\n cachedServerClientConfigPromise = fetchClientConfigFromServer();\n }\n void cachedServerClientConfigPromise\n .then((newConfig) => {\n if (newConfig) {\n setClientConfig((prevConfig) => {\n return prevConfig.isEqual(newConfig) ? prevConfig : newConfig;\n });\n }\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [config, clientConfig.applications, canLoad]);\n\n return { clientConfig, isLoading };\n}\n\nexport function resetCachedServerClientConfigPromise(): void {\n cachedServerClientConfigPromise = null;\n}\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\nexport interface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nconst regexpCache = new Map<string, RegExp>();\nconst getRegexp = (path: string): RegExp => {\n const existing = regexpCache.get(path);\n if (existing) {\n return existing;\n }\n\n const regexp = pathToRegexp(path);\n regexpCache.set(path, regexp);\n return regexp;\n};\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error(\n 'Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?',\n );\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n this === other ||\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = getRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import React, {\n createContext,\n useCallback,\n useRef,\n useMemo,\n useState,\n startTransition,\n} from 'react';\n\nexport interface PrefetchCrossZoneLinksContext {\n prefetchHref: (href: string) => void;\n}\n\nexport const PrefetchCrossZoneLinksContext =\n createContext<PrefetchCrossZoneLinksContext>({\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n prefetchHref: () => {},\n });\n\nexport function PrefetchCrossZoneLinksProvider({\n children,\n}: {\n children: React.ReactNode;\n}): JSX.Element | null {\n const [seenHrefs, setSeenHrefs] = useState(new Set<string>());\n const isSafariOrFirefox = useRef(\n typeof navigator !== 'undefined' &&\n (navigator.userAgent.includes('Firefox') ||\n (navigator.userAgent.includes('Safari') &&\n !navigator.userAgent.includes('Chrome'))),\n );\n\n // This useCallback must not have any dependencies because if it changes\n // its value, every component that uses this context will rerender.\n const prefetchHref = useCallback((href: string): void => {\n // It's not critical that we render the new preload `<link>` elements\n // immediately. We want to batch together `prefetchHref` calls that\n // occur in one synchronous pass and only render once after they've all\n // called this callback.\n startTransition(() => {\n setSeenHrefs((prevHrefs) => {\n if (prevHrefs.has(href)) return prevHrefs;\n return new Set(prevHrefs).add(href);\n });\n });\n }, []);\n\n const value = useMemo(() => ({ prefetchHref }), [prefetchHref]);\n\n if (!isSafariOrFirefox.current) {\n return <>{children}</>;\n }\n\n return (\n <PrefetchCrossZoneLinksContext.Provider value={value}>\n {children}\n {[...seenHrefs].map((href) => (\n <link as=\"fetch\" href={href} key={href} rel=\"preload\" />\n ))}\n </PrefetchCrossZoneLinksContext.Provider>\n );\n}\n","import { useEffect, useState } from 'react';\nimport Script from 'next/script.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\n\nconst PREFETCH_ATTR = 'data-prefetch';\nconst DATA_ATTR_SELECTORS = {\n anyZone: '[data-zone]',\n external: '[data-zone=\"null\"]',\n sameZone: '[data-zone=\"same\"]',\n prefetch: `[${PREFETCH_ATTR}]`,\n} as const;\n\nconst PREFETCH_ON_HOVER_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n ],\n};\n\nconst PREFETCH_WHEN_VISIBLE_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n { selector_matches: DATA_ATTR_SELECTORS.prefetch },\n ],\n};\n\nfunction checkVisibility(element: Element | null): boolean {\n if (!element) return true;\n\n if ('checkVisibility' in element) {\n return element.checkVisibility({ opacityProperty: true });\n }\n\n // hack to get around TS thinking element is never;\n const el = element as Element;\n const style = window.getComputedStyle(el);\n\n if (\n style.display === 'none' ||\n style.visibility === 'hidden' ||\n style.opacity === '0'\n ) {\n return false;\n }\n\n return checkVisibility(el.parentElement);\n}\n\nexport function PrefetchCrossZoneLinks(): JSX.Element | null {\n const { isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n const [links, setLinks] = useState<HTMLAnchorElement[]>([]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Intersection observer to add the data-prefetch attribute to cross-zone\n * links that have yet to be prefetched and are visible.\n */\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (\n entry.isIntersecting &&\n !entry.target.hasAttribute(PREFETCH_ATTR) &&\n // lazy perform the visibility check for nodes that are intersecting the viewport\n // and have not been prefetched.\n checkVisibility(entry.target)\n ) {\n entry.target.setAttribute(PREFETCH_ATTR, 'true');\n }\n });\n },\n {\n root: null,\n rootMargin: '0px',\n threshold: 0.1,\n },\n );\n\n links.forEach((link) => observer.observe(link));\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading, links]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Mutation observer to notify when new nodes have entered/exited the document\n * or an href has changed.\n */\n const observer = new MutationObserver((mutations) => {\n const hasChanged = mutations.some((mutation) => {\n return (\n (mutation.type === 'childList' && mutation.addedNodes.length > 0) ||\n (mutation.type === 'attributes' && mutation.attributeName === 'href')\n );\n });\n\n if (hasChanged) {\n // Whenever there's a change, add all cross-zone links that haven't been\n // prefetched.\n setLinks(\n Array.from(\n document.querySelectorAll<HTMLAnchorElement>(\n `a${DATA_ATTR_SELECTORS.anyZone}:not(${DATA_ATTR_SELECTORS.prefetch}):not(${DATA_ATTR_SELECTORS.sameZone}):not(${DATA_ATTR_SELECTORS.external})`,\n ),\n ),\n );\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading]);\n\n // Wait till the zone-config loads to take into consideration any\n // flagged routes.\n if (isLoading) {\n return null;\n }\n\n // Prefetch links with moderate eagerness by default, immediately when marked \"data-prefetch\".\n // Prerender links with conservative eagerness by default, immediately when marked \"data-prefetch\".\n const speculationRules = {\n prefetch: [\n {\n eagerness: 'moderate',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n {\n eagerness: 'immediate',\n where: PREFETCH_WHEN_VISIBLE_PREDICATES,\n },\n ],\n prerender: [\n {\n eagerness: 'conservative',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n ],\n };\n\n return (\n <Script\n dangerouslySetInnerHTML={{\n __html: JSON.stringify(speculationRules),\n }}\n id=\"prefetch-zones-links\"\n type=\"speculationrules\"\n />\n );\n}\n","import { forwardRef } from 'react';\n// There is a bug when compiling in Pages Router that accessing the default export\n// from next/image.js causes a \"Element type is invalid\" error in React. :shrug:\nimport { Image as NextImage } from 'next/dist/client/image-component.js';\nimport { getImageProps, type ImageLoader } from 'next/image.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\nimport { generateAssetPrefixFromName } from '../../../config/microfrontends-config/isomorphic/utils/generate-asset-prefix';\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nconst loaderWithAssetPrefix =\n (assetPrefix: string, src: string): ImageLoader =>\n () =>\n `/${assetPrefix}${src}`;\n\n/**\n * A Image component that prefixes microfrontend child zones with the asset prefix\n * to ensure the image request is routed to the correct zone.\n */\nexport const Image: typeof NextImage = forwardRef(\n ({ ...props }, ref): JSX.Element => {\n const { clientConfig } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n\n const assetPrefix =\n CURRENT_ZONE && !clientConfig.applications[CURRENT_ZONE]?.default\n ? generateAssetPrefixFromName({ name: CURRENT_ZONE })\n : null;\n\n const {\n props: { src },\n } = getImageProps(props);\n\n return (\n <NextImage\n loader={\n assetPrefix ? loaderWithAssetPrefix(assetPrefix, src) : undefined\n }\n {...props}\n ref={ref}\n />\n );\n },\n);\nImage.displayName = 'MicrofrontendsImage';\n","const PREFIX = 'vc-ap';\n\nexport function generateAssetPrefixFromName({\n name,\n}: {\n name: string;\n}): string {\n if (!name) {\n throw new Error('Name is required to generate an asset prefix');\n }\n\n return `${PREFIX}-${name}`;\n}\n"],"mappings":"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","names":["client_exports","__export","Image","Link","PrefetchCrossZoneLinks","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","useZoneForHref","__toCommonJS","import_react","import_link","import_react","import_path_to_regexp","regexpCache","getRegexp","path","existing","regexp","MicrofrontendConfigClient","config","opts","app","match","other","pathname","name","application","group","childPath","defaultApplication","clientCache","cachedHasDynamicPaths","getOptsKey","opts","getClient","config","optsKey","configCache","existing","client","MicrofrontendConfigClient","cachedServerClientConfigPromise","cachedServerClient","fetchClientConfigFromServer","response","responseJson","useClientConfig","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","canLoad","originalClientConfig","hasDynamicPaths","app","group","isLoading","setIsLoading","newConfig","prevConfig","import_react","import_jsx_runtime","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","prefetchHref","href","prevHrefs","value","import_react","import_script","import_jsx_runtime","PREFETCH_ATTR","DATA_ATTR_SELECTORS","PREFETCH_ON_HOVER_PREDICATES","PREFETCH_WHEN_VISIBLE_PREDICATES","checkVisibility","element","el","style","PrefetchCrossZoneLinks","isLoading","useClientConfig","links","setLinks","observer","entries","entry","link","mutations","mutation","Script","import_jsx_runtime","CURRENT_ZONE","useZoneForHref","href","clientConfig","isLoading","useClientConfig","isRelativePath","zoneOfHref","isRelative","Link","children","props","ref","prefetchHref","PrefetchCrossZoneLinksContext","isDifferentZone","onHoverPrefetch","_","rest","NextLink","import_react","import_image_component","import_image","PREFIX","generateAssetPrefixFromName","name","import_jsx_runtime","CURRENT_ZONE","loaderWithAssetPrefix","assetPrefix","src","Image","props","ref","clientConfig","useClientConfig","generateAssetPrefixFromName","NextImage"]}
1
+ {"version":3,"sources":["../../src/next/client/index.ts","../../src/next/client/link/microfrontends-link.tsx","../../src/config/react/use-client-config.ts","../../src/config/microfrontends-config/client/index.ts","../../src/next/client/prefetch/prefetch-cross-zone-links-context.tsx","../../src/next/client/prefetch/prefetch-cross-zone-links.tsx"],"sourcesContent":["export * from './link';\nexport * from './prefetch';\n","import type { AnchorHTMLAttributes } from 'react';\nimport { forwardRef, useContext, useMemo } from 'react';\nimport NextLink, {\n type LinkProps as ExternalNextLinkProps,\n} from 'next/link.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\nimport { PrefetchCrossZoneLinksContext } from '../prefetch';\n\ninterface BaseProps {\n children: React.ReactNode;\n href: string;\n}\n\n// fix for tsc inlining LinkProps from next\n// https://github.com/microsoft/TypeScript/issues/37151#issuecomment-756232934\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\ninterface NextLinkProps extends ExternalNextLinkProps {}\nexport type LinkProps = BaseProps &\n Omit<NextLinkProps, keyof BaseProps> &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseProps>;\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nexport function useZoneForHref(href: LinkProps['href'] | undefined): {\n zoneOfHref: string | null;\n isDifferentZone: boolean;\n isLoading: boolean;\n} {\n const { clientConfig, isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n {\n removeFlaggedPathsFromDefault: true,\n },\n );\n const { isRelativePath, zoneOfHref } = useMemo(() => {\n const isRelative = typeof href === 'string' && href.startsWith('/');\n return {\n isRelativePath: isRelative,\n zoneOfHref: isRelative\n ? clientConfig.getApplicationNameForPath(href)\n : null,\n };\n }, [clientConfig, href]);\n\n if (typeof href === 'string' && !href.length) {\n return {\n zoneOfHref: null,\n isDifferentZone: false,\n isLoading: false,\n };\n }\n const isDifferentZone =\n !isRelativePath || (zoneOfHref ? CURRENT_ZONE !== zoneOfHref : false);\n return { zoneOfHref, isDifferentZone, isLoading };\n}\n\n/**\n * A Link component that works with microfrontend set-ups and will prefetch the\n * cross zone links automatically.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ children, ...props }, ref): JSX.Element => {\n const { prefetchHref } = useContext(PrefetchCrossZoneLinksContext);\n const { zoneOfHref, isDifferentZone, isLoading } = useZoneForHref(\n props.href,\n );\n\n function onHoverPrefetch(): void {\n if (!props.href) {\n return;\n }\n prefetchHref(props.href);\n }\n\n if (isDifferentZone && zoneOfHref !== null) {\n const { prefetch: _, ...rest } = props;\n return (\n <a\n {...rest}\n data-zone={zoneOfHref}\n onFocus={props.prefetch !== false ? onHoverPrefetch : undefined}\n onMouseOver={props.prefetch !== false ? onHoverPrefetch : undefined}\n >\n {children}\n </a>\n );\n }\n\n return (\n <NextLink\n {...props}\n data-zone={!zoneOfHref ? 'null' : 'same'}\n prefetch={props.prefetch ?? (isLoading ? false : undefined)}\n ref={ref}\n >\n {children}\n </NextLink>\n );\n },\n);\nLink.displayName = 'MicrofrontendsLink';\n","'use client';\n\nimport { useState, useEffect, useMemo } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\nimport type { MicrofrontendConfigClientOptions } from '../microfrontends-config/client';\n\nconst clientCache = new Map<string, Map<string, MicrofrontendConfigClient>>();\nconst cachedHasDynamicPaths = new Map<string, boolean>();\n\nconst getOptsKey = (opts?: MicrofrontendConfigClientOptions): string => {\n return JSON.stringify({\n removeFlaggedPaths: opts?.removeFlaggedPaths || false,\n });\n};\n\nconst getClient = (\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n) => {\n const optsKey = getOptsKey(opts);\n let configCache = clientCache.get(config || '');\n if (!configCache) {\n configCache = new Map();\n clientCache.set(config || '', configCache);\n } else {\n const existing = configCache.get(optsKey);\n if (existing) {\n return existing;\n }\n }\n\n const client = MicrofrontendConfigClient.fromEnv(config, opts);\n configCache.set(optsKey, client);\n return client;\n};\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n null;\n\nlet cachedServerClient: MicrofrontendConfigClient | null = null;\n\nasync function fetchClientConfigFromServer(): Promise<MicrofrontendConfigClient | null> {\n try {\n const response = await fetch(\n '/.well-known/vercel/microfrontends/client-config',\n );\n if (response.status !== 200) {\n return null;\n }\n const responseJson = (await response.json()) as WellKnownClientData;\n const client = new MicrofrontendConfigClient(responseJson.config);\n cachedServerClient = client;\n return client;\n } catch (err) {\n return null;\n }\n}\n\n/**\n * Hook to use the client microfrontends configuration. This hook will resolve\n * dynamic paths by fetching the configuration from the server if necessary,\n * allowing the server to specify the values for dynamic paths.\n */\nexport function useClientConfig(\n config: string | undefined,\n {\n removeFlaggedPathsFromDefault,\n }: {\n removeFlaggedPathsFromDefault?: boolean;\n } = {},\n): {\n clientConfig: MicrofrontendConfigClient;\n isLoading: boolean;\n} {\n const [clientConfig, setClientConfig] = useState<MicrofrontendConfigClient>(\n () =>\n cachedServerClient ??\n getClient(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const canLoad = useMemo(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n return false;\n }\n // If we've already fetched the server config and it's resolved, we don't need\n // to enter the loading state at all\n if (cachedServerClient) return false;\n // If we've already checked this config for dynamic paths, we can use the\n // cached result from before instead of reevaluating.\n const existing = cachedHasDynamicPaths.get(config || '');\n if (existing !== undefined) return existing;\n // Since we may remove flagged paths from the client config above, we need\n // to use the original client config to determine if the config has any\n // dynamic paths.\n const originalClientConfig = getClient(config);\n // As an optimization, only fetch the config from the server if the\n // microfrontends configuration has any dynamic paths. If it doesn't,\n // then the server won't return any different values.\n const hasDynamicPaths = Object.values(\n originalClientConfig.applications,\n ).some((app) => app.routing?.some((group) => group.flag));\n cachedHasDynamicPaths.set(config || '', hasDynamicPaths);\n if (!hasDynamicPaths) {\n return false;\n }\n return true;\n }, [config]);\n const [isLoading, setIsLoading] = useState(canLoad);\n useEffect(() => {\n if (!canLoad) return;\n if (!cachedServerClientConfigPromise) {\n cachedServerClientConfigPromise = fetchClientConfigFromServer();\n }\n void cachedServerClientConfigPromise\n .then((newConfig) => {\n if (newConfig) {\n setClientConfig((prevConfig) => {\n return prevConfig.isEqual(newConfig) ? prevConfig : newConfig;\n });\n }\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [config, clientConfig.applications, canLoad]);\n\n return { clientConfig, isLoading };\n}\n\nexport function resetCachedServerClientConfigPromise(): void {\n cachedServerClientConfigPromise = null;\n}\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\nexport interface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nconst regexpCache = new Map<string, RegExp>();\nconst getRegexp = (path: string): RegExp => {\n const existing = regexpCache.get(path);\n if (existing) {\n return existing;\n }\n\n const regexp = pathToRegexp(path);\n regexpCache.set(path, regexp);\n return regexp;\n};\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error(\n 'Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?',\n );\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n this === other ||\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = getRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import React, {\n createContext,\n useCallback,\n useRef,\n useMemo,\n useState,\n startTransition,\n} from 'react';\n\nexport interface PrefetchCrossZoneLinksContext {\n prefetchHref: (href: string) => void;\n}\n\nexport const PrefetchCrossZoneLinksContext =\n createContext<PrefetchCrossZoneLinksContext>({\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n prefetchHref: () => {},\n });\n\nexport function PrefetchCrossZoneLinksProvider({\n children,\n}: {\n children: React.ReactNode;\n}): JSX.Element | null {\n const [seenHrefs, setSeenHrefs] = useState(new Set<string>());\n const isSafariOrFirefox = useRef(\n typeof navigator !== 'undefined' &&\n (navigator.userAgent.includes('Firefox') ||\n (navigator.userAgent.includes('Safari') &&\n !navigator.userAgent.includes('Chrome'))),\n );\n\n // This useCallback must not have any dependencies because if it changes\n // its value, every component that uses this context will rerender.\n const prefetchHref = useCallback((href: string): void => {\n // It's not critical that we render the new preload `<link>` elements\n // immediately. We want to batch together `prefetchHref` calls that\n // occur in one synchronous pass and only render once after they've all\n // called this callback.\n startTransition(() => {\n setSeenHrefs((prevHrefs) => {\n if (prevHrefs.has(href)) return prevHrefs;\n return new Set(prevHrefs).add(href);\n });\n });\n }, []);\n\n const value = useMemo(() => ({ prefetchHref }), [prefetchHref]);\n\n if (!isSafariOrFirefox.current) {\n return <>{children}</>;\n }\n\n return (\n <PrefetchCrossZoneLinksContext.Provider value={value}>\n {children}\n {[...seenHrefs].map((href) => (\n <link as=\"fetch\" href={href} key={href} rel=\"preload\" />\n ))}\n </PrefetchCrossZoneLinksContext.Provider>\n );\n}\n","import { useEffect, useState } from 'react';\nimport Script from 'next/script.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\n\nconst PREFETCH_ATTR = 'data-prefetch';\nconst DATA_ATTR_SELECTORS = {\n anyZone: '[data-zone]',\n external: '[data-zone=\"null\"]',\n sameZone: '[data-zone=\"same\"]',\n prefetch: `[${PREFETCH_ATTR}]`,\n} as const;\n\nconst PREFETCH_ON_HOVER_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n ],\n};\n\nconst PREFETCH_WHEN_VISIBLE_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n { selector_matches: DATA_ATTR_SELECTORS.prefetch },\n ],\n};\n\nfunction checkVisibility(element: Element | null): boolean {\n if (!element) return true;\n\n if ('checkVisibility' in element) {\n return element.checkVisibility({ opacityProperty: true });\n }\n\n // hack to get around TS thinking element is never;\n const el = element as Element;\n const style = window.getComputedStyle(el);\n\n if (\n style.display === 'none' ||\n style.visibility === 'hidden' ||\n style.opacity === '0'\n ) {\n return false;\n }\n\n return checkVisibility(el.parentElement);\n}\n\nexport function PrefetchCrossZoneLinks(): JSX.Element | null {\n const { isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n const [links, setLinks] = useState<HTMLAnchorElement[]>([]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Intersection observer to add the data-prefetch attribute to cross-zone\n * links that have yet to be prefetched and are visible.\n */\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (\n entry.isIntersecting &&\n !entry.target.hasAttribute(PREFETCH_ATTR) &&\n // lazy perform the visibility check for nodes that are intersecting the viewport\n // and have not been prefetched.\n checkVisibility(entry.target)\n ) {\n entry.target.setAttribute(PREFETCH_ATTR, 'true');\n }\n });\n },\n {\n root: null,\n rootMargin: '0px',\n threshold: 0.1,\n },\n );\n\n links.forEach((link) => observer.observe(link));\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading, links]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Mutation observer to notify when new nodes have entered/exited the document\n * or an href has changed.\n */\n const observer = new MutationObserver((mutations) => {\n const hasChanged = mutations.some((mutation) => {\n return (\n (mutation.type === 'childList' && mutation.addedNodes.length > 0) ||\n (mutation.type === 'attributes' && mutation.attributeName === 'href')\n );\n });\n\n if (hasChanged) {\n // Whenever there's a change, add all cross-zone links that haven't been\n // prefetched.\n setLinks(\n Array.from(\n document.querySelectorAll<HTMLAnchorElement>(\n `a${DATA_ATTR_SELECTORS.anyZone}:not(${DATA_ATTR_SELECTORS.prefetch}):not(${DATA_ATTR_SELECTORS.sameZone}):not(${DATA_ATTR_SELECTORS.external})`,\n ),\n ),\n );\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading]);\n\n // Wait till the zone-config loads to take into consideration any\n // flagged routes.\n if (isLoading) {\n return null;\n }\n\n // Prefetch links with moderate eagerness by default, immediately when marked \"data-prefetch\".\n // Prerender links with conservative eagerness by default, immediately when marked \"data-prefetch\".\n const speculationRules = {\n prefetch: [\n {\n eagerness: 'moderate',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n {\n eagerness: 'immediate',\n where: PREFETCH_WHEN_VISIBLE_PREDICATES,\n },\n ],\n prerender: [\n {\n eagerness: 'conservative',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n ],\n };\n\n return (\n <Script\n dangerouslySetInnerHTML={{\n __html: JSON.stringify(speculationRules),\n }}\n id=\"prefetch-zones-links\"\n type=\"speculationrules\"\n />\n );\n}\n"],"mappings":"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","names":["client_exports","__export","Link","PrefetchCrossZoneLinks","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","useZoneForHref","__toCommonJS","import_react","import_link","import_react","import_path_to_regexp","regexpCache","getRegexp","path","existing","regexp","MicrofrontendConfigClient","config","opts","app","match","other","pathname","name","application","group","childPath","defaultApplication","clientCache","cachedHasDynamicPaths","getOptsKey","opts","getClient","config","optsKey","configCache","existing","client","MicrofrontendConfigClient","cachedServerClientConfigPromise","cachedServerClient","fetchClientConfigFromServer","response","responseJson","useClientConfig","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","canLoad","originalClientConfig","hasDynamicPaths","app","group","isLoading","setIsLoading","newConfig","prevConfig","import_react","import_jsx_runtime","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","prefetchHref","href","prevHrefs","value","import_react","import_script","import_jsx_runtime","PREFETCH_ATTR","DATA_ATTR_SELECTORS","PREFETCH_ON_HOVER_PREDICATES","PREFETCH_WHEN_VISIBLE_PREDICATES","checkVisibility","element","el","style","PrefetchCrossZoneLinks","isLoading","useClientConfig","links","setLinks","observer","entries","entry","link","mutations","mutation","Script","import_jsx_runtime","CURRENT_ZONE","useZoneForHref","href","clientConfig","isLoading","useClientConfig","isRelativePath","zoneOfHref","isRelative","Link","children","props","ref","prefetchHref","PrefetchCrossZoneLinksContext","isDifferentZone","onHoverPrefetch","_","rest","NextLink"]}
@@ -1,7 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import react__default, { AnchorHTMLAttributes } from 'react';
3
3
  import { LinkProps as LinkProps$1 } from 'next/link.js';
4
- import { Image as Image$1 } from 'next/dist/client/image-component.js';
5
4
 
6
5
  interface BaseProps {
7
6
  children: React.ReactNode;
@@ -31,10 +30,4 @@ declare function PrefetchCrossZoneLinksProvider({ children, }: {
31
30
 
32
31
  declare function PrefetchCrossZoneLinks(): JSX.Element | null;
33
32
 
34
- /**
35
- * A Image component that prefixes microfrontend child zones with the asset prefix
36
- * to ensure the image request is routed to the correct zone.
37
- */
38
- declare const Image: typeof Image$1;
39
-
40
- export { Image, Link, LinkProps, PrefetchCrossZoneLinks, PrefetchCrossZoneLinksContext, PrefetchCrossZoneLinksProvider, useZoneForHref };
33
+ export { Link, LinkProps, PrefetchCrossZoneLinks, PrefetchCrossZoneLinksContext, PrefetchCrossZoneLinksProvider, useZoneForHref };
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- import{forwardRef as G,useContext as K,useMemo as j}from"react";import Q from"next/link.js";import{useState as P,useEffect as w,useMemo as k}from"react";import{pathToRegexp as I}from"path-to-regexp";var E=new Map,b=e=>{let t=E.get(e);if(t)return t;let r=I(e);return E.set(e,r),r},f=class{constructor(t,r){this.pathCache={};if(this.serialized=t,r?.removeFlaggedPaths)for(let o of Object.values(t.applications))o.routing&&(o.routing=o.routing.filter(n=>!n.flag));this.applications=t.applications}static fromEnv(t,r){if(!t)throw new Error("Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?");return new f(JSON.parse(t),r)}isEqual(t){return this===t||JSON.stringify(this.applications)===JSON.stringify(t.applications)}getApplicationNameForPath(t){if(!t.startsWith("/"))throw new Error("Path must start with a /");if(this.pathCache[t])return this.pathCache[t];let r=new URL(t,"https://example.com").pathname;for(let[n,a]of Object.entries(this.applications))if(a.routing){for(let i of a.routing)for(let s of i.paths)if(b(s).test(r))return this.pathCache[t]=n,n}let o=Object.entries(this.applications).find(([,n])=>n.default);return o?(this.pathCache[t]=o[0],o[0]):null}serialize(){return this.serialized}};var x=new Map,L=new Map,A=e=>JSON.stringify({removeFlaggedPaths:e?.removeFlaggedPaths||!1}),y=(e,t)=>{let r=A(t),o=x.get(e||"");if(!o)o=new Map,x.set(e||"",o);else{let a=o.get(r);if(a)return a}let n=f.fromEnv(e,t);return o.set(r,n),n},g=null,d=null;async function S(){try{let e=await fetch("/.well-known/vercel/microfrontends/client-config");if(e.status!==200)return null;let t=await e.json(),r=new f(t.config);return d=r,r}catch{return null}}function u(e,{removeFlaggedPathsFromDefault:t}={}){let[r,o]=P(()=>d??y(e,{removeFlaggedPaths:t})),n=k(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"||d)return!1;let s=L.get(e||"");if(s!==void 0)return s;let l=y(e),p=Object.values(l.applications).some(F=>F.routing?.some(T=>T.flag));return L.set(e||"",p),!!p},[e]),[a,i]=P(n);return w(()=>{n&&(g||(g=S()),g.then(s=>{s&&o(l=>l.isEqual(s)?l:s)}).finally(()=>{i(!1)}))},[e,r.applications,n]),{clientConfig:r,isLoading:a}}import{createContext as H,useCallback as Z,useRef as D,useMemo as z,useState as B,startTransition as J}from"react";import{Fragment as U,jsx as v,jsxs as X}from"react/jsx-runtime";var m=H({prefetchHref:()=>{}});function he({children:e}){let[t,r]=B(new Set),o=D(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),n=Z(i=>{J(()=>{r(s=>s.has(i)?s:new Set(s).add(i))})},[]),a=z(()=>({prefetchHref:n}),[n]);return o.current?X(m.Provider,{value:a,children:[e,[...t].map(i=>v("link",{as:"fetch",href:i,rel:"preload"},i))]}):v(U,{children:e})}import{useEffect as N,useState as $}from"react";import V from"next/script.js";import{jsx as q}from"react/jsx-runtime";var h="data-prefetch",c={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${h}]`},_={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}}]},W={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}},{selector_matches:c.prefetch}]};function M(e){if(!e)return!0;if("checkVisibility"in e)return e.checkVisibility({opacityProperty:!0});let t=e,r=window.getComputedStyle(t);return r.display==="none"||r.visibility==="hidden"||r.opacity==="0"?!1:M(t.parentElement)}function ye(){let{isLoading:e}=u(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[t,r]=$([]);return N(()=>{if(e)return;let n=new IntersectionObserver(a=>{a.forEach(i=>{i.isIntersecting&&!i.target.hasAttribute(h)&&M(i.target)&&i.target.setAttribute(h,"true")})},{root:null,rootMargin:"0px",threshold:.1});return t.forEach(a=>n.observe(a)),()=>{n.disconnect()}},[e,t]),N(()=>{if(e)return;let n=new MutationObserver(a=>{a.some(s=>s.type==="childList"&&s.addedNodes.length>0||s.type==="attributes"&&s.attributeName==="href")&&r(Array.from(document.querySelectorAll(`a${c.anyZone}:not(${c.prefetch}):not(${c.sameZone}):not(${c.external})`)))});return n.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{n.disconnect()}},[e]),e?null:q(V,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:_},{eagerness:"immediate",where:W}],prerender:[{eagerness:"conservative",where:_}]})},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as O}from"react/jsx-runtime";var Y=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function ee(e){let{clientConfig:t,isLoading:r}=u(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),{isRelativePath:o,zoneOfHref:n}=j(()=>{let i=typeof e=="string"&&e.startsWith("/");return{isRelativePath:i,zoneOfHref:i?t.getApplicationNameForPath(e):null}},[t,e]);return typeof e=="string"&&!e.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:n,isDifferentZone:!o||(n?Y!==n:!1),isLoading:r}}var te=G(({children:e,...t},r)=>{let{prefetchHref:o}=K(m),{zoneOfHref:n,isDifferentZone:a,isLoading:i}=ee(t.href);function s(){t.href&&o(t.href)}if(a&&n!==null){let{prefetch:l,...p}=t;return O("a",{...p,"data-zone":n,onFocus:t.prefetch!==!1?s:void 0,onMouseOver:t.prefetch!==!1?s:void 0,children:e})}return O(Q,{...t,"data-zone":n?"same":"null",prefetch:t.prefetch??(i?!1:void 0),ref:r,children:e})});te.displayName="MicrofrontendsLink";import{forwardRef as re}from"react";import{Image as oe}from"next/dist/client/image-component.js";import{getImageProps as ie}from"next/image.js";var ne="vc-ap";function R({name:e}){if(!e)throw new Error("Name is required to generate an asset prefix");return`${ne}-${e}`}import{jsx as ce}from"react/jsx-runtime";var C=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION,se=(e,t)=>()=>`/${e}${t}`,ae=re(({...e},t)=>{let{clientConfig:r}=u(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),o=C&&!r.applications[C]?.default?R({name:C}):null,{props:{src:n}}=ie(e);return ce(oe,{loader:o?se(o,n):void 0,...e,ref:t})});ae.displayName="MicrofrontendsImage";export{ae as Image,te as Link,ye as PrefetchCrossZoneLinks,m as PrefetchCrossZoneLinksContext,he as PrefetchCrossZoneLinksProvider,ee as useZoneForHref};
2
+ import{forwardRef as $,useContext as K,useMemo as q}from"react";import G from"next/link.js";import{useState as E,useEffect as w,useMemo as S}from"react";import{pathToRegexp as b}from"path-to-regexp";var m=new Map,k=t=>{let e=m.get(t);if(e)return e;let r=b(t);return m.set(t,r),r},l=class{constructor(e,r){this.pathCache={};if(this.serialized=e,r?.removeFlaggedPaths)for(let o of Object.values(e.applications))o.routing&&(o.routing=o.routing.filter(n=>!n.flag));this.applications=e.applications}static fromEnv(e,r){if(!e)throw new Error("Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?");return new l(JSON.parse(e),r)}isEqual(e){return this===e||JSON.stringify(this.applications)===JSON.stringify(e.applications)}getApplicationNameForPath(e){if(!e.startsWith("/"))throw new Error("Path must start with a /");if(this.pathCache[e])return this.pathCache[e];let r=new URL(e,"https://example.com").pathname;for(let[n,a]of Object.entries(this.applications))if(a.routing){for(let i of a.routing)for(let s of i.paths)if(k(s).test(r))return this.pathCache[e]=n,n}let o=Object.entries(this.applications).find(([,n])=>n.default);return o?(this.pathCache[e]=o[0],o[0]):null}serialize(){return this.serialized}};var P=new Map,y=new Map,F=t=>JSON.stringify({removeFlaggedPaths:t?.removeFlaggedPaths||!1}),L=(t,e)=>{let r=F(e),o=P.get(t||"");if(!o)o=new Map,P.set(t||"",o);else{let a=o.get(r);if(a)return a}let n=l.fromEnv(t,e);return o.set(r,n),n},d=null,g=null;async function T(){try{let t=await fetch("/.well-known/vercel/microfrontends/client-config");if(t.status!==200)return null;let e=await t.json(),r=new l(e.config);return g=r,r}catch{return null}}function p(t,{removeFlaggedPathsFromDefault:e}={}){let[r,o]=E(()=>g??L(t,{removeFlaggedPaths:e})),n=S(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"||g)return!1;let s=y.get(t||"");if(s!==void 0)return s;let f=L(t),u=Object.values(f.applications).some(N=>N.routing?.some(R=>R.flag));return y.set(t||"",u),!!u},[t]),[a,i]=E(n);return w(()=>{n&&(d||(d=T()),d.then(s=>{s&&o(f=>f.isEqual(s)?f:s)}).finally(()=>{i(!1)}))},[t,r.applications,n]),{clientConfig:r,isLoading:a}}import{createContext as A,useCallback as H,useRef as Z,useMemo as I,useState as D,startTransition as z}from"react";import{Fragment as J,jsx as v,jsxs as B}from"react/jsx-runtime";var h=A({prefetchHref:()=>{}});function ae({children:t}){let[e,r]=D(new Set),o=Z(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),n=H(i=>{z(()=>{r(s=>s.has(i)?s:new Set(s).add(i))})},[]),a=I(()=>({prefetchHref:n}),[n]);return o.current?B(h.Provider,{value:a,children:[t,[...e].map(i=>v("link",{as:"fetch",href:i,rel:"preload"},i))]}):v(J,{children:t})}import{useEffect as x,useState as V}from"react";import U from"next/script.js";import{jsx as W}from"react/jsx-runtime";var C="data-prefetch",c={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${C}]`},M={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}}]},X={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}},{selector_matches:c.prefetch}]};function _(t){if(!t)return!0;if("checkVisibility"in t)return t.checkVisibility({opacityProperty:!0});let e=t,r=window.getComputedStyle(e);return r.display==="none"||r.visibility==="hidden"||r.opacity==="0"?!1:_(e.parentElement)}function de(){let{isLoading:t}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=V([]);return x(()=>{if(t)return;let n=new IntersectionObserver(a=>{a.forEach(i=>{i.isIntersecting&&!i.target.hasAttribute(C)&&_(i.target)&&i.target.setAttribute(C,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(a=>n.observe(a)),()=>{n.disconnect()}},[t,e]),x(()=>{if(t)return;let n=new MutationObserver(a=>{a.some(s=>s.type==="childList"&&s.addedNodes.length>0||s.type==="attributes"&&s.attributeName==="href")&&r(Array.from(document.querySelectorAll(`a${c.anyZone}:not(${c.prefetch}):not(${c.sameZone}):not(${c.external})`)))});return n.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{n.disconnect()}},[t]),t?null:W(U,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:M},{eagerness:"immediate",where:X}],prerender:[{eagerness:"conservative",where:M}]})},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as O}from"react/jsx-runtime";var j=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function Q(t){let{clientConfig:e,isLoading:r}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),{isRelativePath:o,zoneOfHref:n}=q(()=>{let i=typeof t=="string"&&t.startsWith("/");return{isRelativePath:i,zoneOfHref:i?e.getApplicationNameForPath(t):null}},[e,t]);return typeof t=="string"&&!t.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:n,isDifferentZone:!o||(n?j!==n:!1),isLoading:r}}var Y=$(({children:t,...e},r)=>{let{prefetchHref:o}=K(h),{zoneOfHref:n,isDifferentZone:a,isLoading:i}=Q(e.href);function s(){e.href&&o(e.href)}if(a&&n!==null){let{prefetch:f,...u}=e;return O("a",{...u,"data-zone":n,onFocus:e.prefetch!==!1?s:void 0,onMouseOver:e.prefetch!==!1?s:void 0,children:t})}return O(G,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(i?!1:void 0),ref:r,children:t})});Y.displayName="MicrofrontendsLink";export{Y as Link,de as PrefetchCrossZoneLinks,h as PrefetchCrossZoneLinksContext,ae as PrefetchCrossZoneLinksProvider,Q as useZoneForHref};
3
3
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/next/client/link/microfrontends-link.tsx","../../src/config/react/use-client-config.ts","../../src/config/microfrontends-config/client/index.ts","../../src/next/client/prefetch/prefetch-cross-zone-links-context.tsx","../../src/next/client/prefetch/prefetch-cross-zone-links.tsx","../../src/next/client/image/microfrontends-image.tsx","../../src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts"],"sourcesContent":["import type { AnchorHTMLAttributes } from 'react';\nimport { forwardRef, useContext, useMemo } from 'react';\nimport NextLink, {\n type LinkProps as ExternalNextLinkProps,\n} from 'next/link.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\nimport { PrefetchCrossZoneLinksContext } from '../prefetch';\n\ninterface BaseProps {\n children: React.ReactNode;\n href: string;\n}\n\n// fix for tsc inlining LinkProps from next\n// https://github.com/microsoft/TypeScript/issues/37151#issuecomment-756232934\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\ninterface NextLinkProps extends ExternalNextLinkProps {}\nexport type LinkProps = BaseProps &\n Omit<NextLinkProps, keyof BaseProps> &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseProps>;\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nexport function useZoneForHref(href: LinkProps['href'] | undefined): {\n zoneOfHref: string | null;\n isDifferentZone: boolean;\n isLoading: boolean;\n} {\n const { clientConfig, isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n {\n removeFlaggedPathsFromDefault: true,\n },\n );\n const { isRelativePath, zoneOfHref } = useMemo(() => {\n const isRelative = typeof href === 'string' && href.startsWith('/');\n return {\n isRelativePath: isRelative,\n zoneOfHref: isRelative\n ? clientConfig.getApplicationNameForPath(href)\n : null,\n };\n }, [clientConfig, href]);\n\n if (typeof href === 'string' && !href.length) {\n return {\n zoneOfHref: null,\n isDifferentZone: false,\n isLoading: false,\n };\n }\n const isDifferentZone =\n !isRelativePath || (zoneOfHref ? CURRENT_ZONE !== zoneOfHref : false);\n return { zoneOfHref, isDifferentZone, isLoading };\n}\n\n/**\n * A Link component that works with microfrontend set-ups and will prefetch the\n * cross zone links automatically.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ children, ...props }, ref): JSX.Element => {\n const { prefetchHref } = useContext(PrefetchCrossZoneLinksContext);\n const { zoneOfHref, isDifferentZone, isLoading } = useZoneForHref(\n props.href,\n );\n\n function onHoverPrefetch(): void {\n if (!props.href) {\n return;\n }\n prefetchHref(props.href);\n }\n\n if (isDifferentZone && zoneOfHref !== null) {\n const { prefetch: _, ...rest } = props;\n return (\n <a\n {...rest}\n data-zone={zoneOfHref}\n onFocus={props.prefetch !== false ? onHoverPrefetch : undefined}\n onMouseOver={props.prefetch !== false ? onHoverPrefetch : undefined}\n >\n {children}\n </a>\n );\n }\n\n return (\n <NextLink\n {...props}\n data-zone={!zoneOfHref ? 'null' : 'same'}\n prefetch={props.prefetch ?? (isLoading ? false : undefined)}\n ref={ref}\n >\n {children}\n </NextLink>\n );\n },\n);\nLink.displayName = 'MicrofrontendsLink';\n","'use client';\n\nimport { useState, useEffect, useMemo } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\nimport type { MicrofrontendConfigClientOptions } from '../microfrontends-config/client';\n\nconst clientCache = new Map<string, Map<string, MicrofrontendConfigClient>>();\nconst cachedHasDynamicPaths = new Map<string, boolean>();\n\nconst getOptsKey = (opts?: MicrofrontendConfigClientOptions): string => {\n return JSON.stringify({\n removeFlaggedPaths: opts?.removeFlaggedPaths || false,\n });\n};\n\nconst getClient = (\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n) => {\n const optsKey = getOptsKey(opts);\n let configCache = clientCache.get(config || '');\n if (!configCache) {\n configCache = new Map();\n clientCache.set(config || '', configCache);\n } else {\n const existing = configCache.get(optsKey);\n if (existing) {\n return existing;\n }\n }\n\n const client = MicrofrontendConfigClient.fromEnv(config, opts);\n configCache.set(optsKey, client);\n return client;\n};\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n null;\n\nlet cachedServerClient: MicrofrontendConfigClient | null = null;\n\nasync function fetchClientConfigFromServer(): Promise<MicrofrontendConfigClient | null> {\n try {\n const response = await fetch(\n '/.well-known/vercel/microfrontends/client-config',\n );\n if (response.status !== 200) {\n return null;\n }\n const responseJson = (await response.json()) as WellKnownClientData;\n const client = new MicrofrontendConfigClient(responseJson.config);\n cachedServerClient = client;\n return client;\n } catch (err) {\n return null;\n }\n}\n\n/**\n * Hook to use the client microfrontends configuration. This hook will resolve\n * dynamic paths by fetching the configuration from the server if necessary,\n * allowing the server to specify the values for dynamic paths.\n */\nexport function useClientConfig(\n config: string | undefined,\n {\n removeFlaggedPathsFromDefault,\n }: {\n removeFlaggedPathsFromDefault?: boolean;\n } = {},\n): {\n clientConfig: MicrofrontendConfigClient;\n isLoading: boolean;\n} {\n const [clientConfig, setClientConfig] = useState<MicrofrontendConfigClient>(\n () =>\n cachedServerClient ??\n getClient(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const canLoad = useMemo(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n return false;\n }\n // If we've already fetched the server config and it's resolved, we don't need\n // to enter the loading state at all\n if (cachedServerClient) return false;\n // If we've already checked this config for dynamic paths, we can use the\n // cached result from before instead of reevaluating.\n const existing = cachedHasDynamicPaths.get(config || '');\n if (existing !== undefined) return existing;\n // Since we may remove flagged paths from the client config above, we need\n // to use the original client config to determine if the config has any\n // dynamic paths.\n const originalClientConfig = getClient(config);\n // As an optimization, only fetch the config from the server if the\n // microfrontends configuration has any dynamic paths. If it doesn't,\n // then the server won't return any different values.\n const hasDynamicPaths = Object.values(\n originalClientConfig.applications,\n ).some((app) => app.routing?.some((group) => group.flag));\n cachedHasDynamicPaths.set(config || '', hasDynamicPaths);\n if (!hasDynamicPaths) {\n return false;\n }\n return true;\n }, [config]);\n const [isLoading, setIsLoading] = useState(canLoad);\n useEffect(() => {\n if (!canLoad) return;\n if (!cachedServerClientConfigPromise) {\n cachedServerClientConfigPromise = fetchClientConfigFromServer();\n }\n void cachedServerClientConfigPromise\n .then((newConfig) => {\n if (newConfig) {\n setClientConfig((prevConfig) => {\n return prevConfig.isEqual(newConfig) ? prevConfig : newConfig;\n });\n }\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [config, clientConfig.applications, canLoad]);\n\n return { clientConfig, isLoading };\n}\n\nexport function resetCachedServerClientConfigPromise(): void {\n cachedServerClientConfigPromise = null;\n}\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\nexport interface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nconst regexpCache = new Map<string, RegExp>();\nconst getRegexp = (path: string): RegExp => {\n const existing = regexpCache.get(path);\n if (existing) {\n return existing;\n }\n\n const regexp = pathToRegexp(path);\n regexpCache.set(path, regexp);\n return regexp;\n};\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error(\n 'Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?',\n );\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n this === other ||\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = getRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import React, {\n createContext,\n useCallback,\n useRef,\n useMemo,\n useState,\n startTransition,\n} from 'react';\n\nexport interface PrefetchCrossZoneLinksContext {\n prefetchHref: (href: string) => void;\n}\n\nexport const PrefetchCrossZoneLinksContext =\n createContext<PrefetchCrossZoneLinksContext>({\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n prefetchHref: () => {},\n });\n\nexport function PrefetchCrossZoneLinksProvider({\n children,\n}: {\n children: React.ReactNode;\n}): JSX.Element | null {\n const [seenHrefs, setSeenHrefs] = useState(new Set<string>());\n const isSafariOrFirefox = useRef(\n typeof navigator !== 'undefined' &&\n (navigator.userAgent.includes('Firefox') ||\n (navigator.userAgent.includes('Safari') &&\n !navigator.userAgent.includes('Chrome'))),\n );\n\n // This useCallback must not have any dependencies because if it changes\n // its value, every component that uses this context will rerender.\n const prefetchHref = useCallback((href: string): void => {\n // It's not critical that we render the new preload `<link>` elements\n // immediately. We want to batch together `prefetchHref` calls that\n // occur in one synchronous pass and only render once after they've all\n // called this callback.\n startTransition(() => {\n setSeenHrefs((prevHrefs) => {\n if (prevHrefs.has(href)) return prevHrefs;\n return new Set(prevHrefs).add(href);\n });\n });\n }, []);\n\n const value = useMemo(() => ({ prefetchHref }), [prefetchHref]);\n\n if (!isSafariOrFirefox.current) {\n return <>{children}</>;\n }\n\n return (\n <PrefetchCrossZoneLinksContext.Provider value={value}>\n {children}\n {[...seenHrefs].map((href) => (\n <link as=\"fetch\" href={href} key={href} rel=\"preload\" />\n ))}\n </PrefetchCrossZoneLinksContext.Provider>\n );\n}\n","import { useEffect, useState } from 'react';\nimport Script from 'next/script.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\n\nconst PREFETCH_ATTR = 'data-prefetch';\nconst DATA_ATTR_SELECTORS = {\n anyZone: '[data-zone]',\n external: '[data-zone=\"null\"]',\n sameZone: '[data-zone=\"same\"]',\n prefetch: `[${PREFETCH_ATTR}]`,\n} as const;\n\nconst PREFETCH_ON_HOVER_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n ],\n};\n\nconst PREFETCH_WHEN_VISIBLE_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n { selector_matches: DATA_ATTR_SELECTORS.prefetch },\n ],\n};\n\nfunction checkVisibility(element: Element | null): boolean {\n if (!element) return true;\n\n if ('checkVisibility' in element) {\n return element.checkVisibility({ opacityProperty: true });\n }\n\n // hack to get around TS thinking element is never;\n const el = element as Element;\n const style = window.getComputedStyle(el);\n\n if (\n style.display === 'none' ||\n style.visibility === 'hidden' ||\n style.opacity === '0'\n ) {\n return false;\n }\n\n return checkVisibility(el.parentElement);\n}\n\nexport function PrefetchCrossZoneLinks(): JSX.Element | null {\n const { isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n const [links, setLinks] = useState<HTMLAnchorElement[]>([]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Intersection observer to add the data-prefetch attribute to cross-zone\n * links that have yet to be prefetched and are visible.\n */\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (\n entry.isIntersecting &&\n !entry.target.hasAttribute(PREFETCH_ATTR) &&\n // lazy perform the visibility check for nodes that are intersecting the viewport\n // and have not been prefetched.\n checkVisibility(entry.target)\n ) {\n entry.target.setAttribute(PREFETCH_ATTR, 'true');\n }\n });\n },\n {\n root: null,\n rootMargin: '0px',\n threshold: 0.1,\n },\n );\n\n links.forEach((link) => observer.observe(link));\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading, links]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Mutation observer to notify when new nodes have entered/exited the document\n * or an href has changed.\n */\n const observer = new MutationObserver((mutations) => {\n const hasChanged = mutations.some((mutation) => {\n return (\n (mutation.type === 'childList' && mutation.addedNodes.length > 0) ||\n (mutation.type === 'attributes' && mutation.attributeName === 'href')\n );\n });\n\n if (hasChanged) {\n // Whenever there's a change, add all cross-zone links that haven't been\n // prefetched.\n setLinks(\n Array.from(\n document.querySelectorAll<HTMLAnchorElement>(\n `a${DATA_ATTR_SELECTORS.anyZone}:not(${DATA_ATTR_SELECTORS.prefetch}):not(${DATA_ATTR_SELECTORS.sameZone}):not(${DATA_ATTR_SELECTORS.external})`,\n ),\n ),\n );\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading]);\n\n // Wait till the zone-config loads to take into consideration any\n // flagged routes.\n if (isLoading) {\n return null;\n }\n\n // Prefetch links with moderate eagerness by default, immediately when marked \"data-prefetch\".\n // Prerender links with conservative eagerness by default, immediately when marked \"data-prefetch\".\n const speculationRules = {\n prefetch: [\n {\n eagerness: 'moderate',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n {\n eagerness: 'immediate',\n where: PREFETCH_WHEN_VISIBLE_PREDICATES,\n },\n ],\n prerender: [\n {\n eagerness: 'conservative',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n ],\n };\n\n return (\n <Script\n dangerouslySetInnerHTML={{\n __html: JSON.stringify(speculationRules),\n }}\n id=\"prefetch-zones-links\"\n type=\"speculationrules\"\n />\n );\n}\n","import { forwardRef } from 'react';\n// There is a bug when compiling in Pages Router that accessing the default export\n// from next/image.js causes a \"Element type is invalid\" error in React. :shrug:\nimport { Image as NextImage } from 'next/dist/client/image-component.js';\nimport { getImageProps, type ImageLoader } from 'next/image.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\nimport { generateAssetPrefixFromName } from '../../../config/microfrontends-config/isomorphic/utils/generate-asset-prefix';\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nconst loaderWithAssetPrefix =\n (assetPrefix: string, src: string): ImageLoader =>\n () =>\n `/${assetPrefix}${src}`;\n\n/**\n * A Image component that prefixes microfrontend child zones with the asset prefix\n * to ensure the image request is routed to the correct zone.\n */\nexport const Image: typeof NextImage = forwardRef(\n ({ ...props }, ref): JSX.Element => {\n const { clientConfig } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n\n const assetPrefix =\n CURRENT_ZONE && !clientConfig.applications[CURRENT_ZONE]?.default\n ? generateAssetPrefixFromName({ name: CURRENT_ZONE })\n : null;\n\n const {\n props: { src },\n } = getImageProps(props);\n\n return (\n <NextImage\n loader={\n assetPrefix ? loaderWithAssetPrefix(assetPrefix, src) : undefined\n }\n {...props}\n ref={ref}\n />\n );\n },\n);\nImage.displayName = 'MicrofrontendsImage';\n","const PREFIX = 'vc-ap';\n\nexport function generateAssetPrefixFromName({\n name,\n}: {\n name: string;\n}): string {\n if (!name) {\n throw new Error('Name is required to generate an asset prefix');\n }\n\n return `${PREFIX}-${name}`;\n}\n"],"mappings":"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","names":["forwardRef","useContext","useMemo","NextLink","useState","useEffect","useMemo","pathToRegexp","regexpCache","getRegexp","path","existing","regexp","MicrofrontendConfigClient","config","opts","app","match","other","pathname","name","application","group","childPath","defaultApplication","clientCache","cachedHasDynamicPaths","getOptsKey","opts","getClient","config","optsKey","configCache","existing","client","MicrofrontendConfigClient","cachedServerClientConfigPromise","cachedServerClient","fetchClientConfigFromServer","response","responseJson","useClientConfig","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","useState","canLoad","useMemo","originalClientConfig","hasDynamicPaths","app","group","isLoading","setIsLoading","useEffect","newConfig","prevConfig","createContext","useCallback","useRef","useMemo","useState","startTransition","Fragment","jsx","jsxs","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","prefetchHref","href","prevHrefs","value","useEffect","useState","Script","jsx","PREFETCH_ATTR","DATA_ATTR_SELECTORS","PREFETCH_ON_HOVER_PREDICATES","PREFETCH_WHEN_VISIBLE_PREDICATES","checkVisibility","element","el","style","PrefetchCrossZoneLinks","isLoading","useClientConfig","links","setLinks","useState","useEffect","observer","entries","entry","link","mutations","mutation","Script","jsx","CURRENT_ZONE","useZoneForHref","href","clientConfig","isLoading","useClientConfig","isRelativePath","zoneOfHref","useMemo","isRelative","Link","forwardRef","children","props","ref","prefetchHref","useContext","PrefetchCrossZoneLinksContext","isDifferentZone","onHoverPrefetch","_","rest","NextLink","forwardRef","NextImage","getImageProps","PREFIX","generateAssetPrefixFromName","name","jsx","CURRENT_ZONE","loaderWithAssetPrefix","assetPrefix","src","Image","forwardRef","props","ref","clientConfig","useClientConfig","generateAssetPrefixFromName","getImageProps","NextImage"]}
1
+ {"version":3,"sources":["../../src/next/client/link/microfrontends-link.tsx","../../src/config/react/use-client-config.ts","../../src/config/microfrontends-config/client/index.ts","../../src/next/client/prefetch/prefetch-cross-zone-links-context.tsx","../../src/next/client/prefetch/prefetch-cross-zone-links.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes } from 'react';\nimport { forwardRef, useContext, useMemo } from 'react';\nimport NextLink, {\n type LinkProps as ExternalNextLinkProps,\n} from 'next/link.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\nimport { PrefetchCrossZoneLinksContext } from '../prefetch';\n\ninterface BaseProps {\n children: React.ReactNode;\n href: string;\n}\n\n// fix for tsc inlining LinkProps from next\n// https://github.com/microsoft/TypeScript/issues/37151#issuecomment-756232934\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\ninterface NextLinkProps extends ExternalNextLinkProps {}\nexport type LinkProps = BaseProps &\n Omit<NextLinkProps, keyof BaseProps> &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseProps>;\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nexport function useZoneForHref(href: LinkProps['href'] | undefined): {\n zoneOfHref: string | null;\n isDifferentZone: boolean;\n isLoading: boolean;\n} {\n const { clientConfig, isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n {\n removeFlaggedPathsFromDefault: true,\n },\n );\n const { isRelativePath, zoneOfHref } = useMemo(() => {\n const isRelative = typeof href === 'string' && href.startsWith('/');\n return {\n isRelativePath: isRelative,\n zoneOfHref: isRelative\n ? clientConfig.getApplicationNameForPath(href)\n : null,\n };\n }, [clientConfig, href]);\n\n if (typeof href === 'string' && !href.length) {\n return {\n zoneOfHref: null,\n isDifferentZone: false,\n isLoading: false,\n };\n }\n const isDifferentZone =\n !isRelativePath || (zoneOfHref ? CURRENT_ZONE !== zoneOfHref : false);\n return { zoneOfHref, isDifferentZone, isLoading };\n}\n\n/**\n * A Link component that works with microfrontend set-ups and will prefetch the\n * cross zone links automatically.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ children, ...props }, ref): JSX.Element => {\n const { prefetchHref } = useContext(PrefetchCrossZoneLinksContext);\n const { zoneOfHref, isDifferentZone, isLoading } = useZoneForHref(\n props.href,\n );\n\n function onHoverPrefetch(): void {\n if (!props.href) {\n return;\n }\n prefetchHref(props.href);\n }\n\n if (isDifferentZone && zoneOfHref !== null) {\n const { prefetch: _, ...rest } = props;\n return (\n <a\n {...rest}\n data-zone={zoneOfHref}\n onFocus={props.prefetch !== false ? onHoverPrefetch : undefined}\n onMouseOver={props.prefetch !== false ? onHoverPrefetch : undefined}\n >\n {children}\n </a>\n );\n }\n\n return (\n <NextLink\n {...props}\n data-zone={!zoneOfHref ? 'null' : 'same'}\n prefetch={props.prefetch ?? (isLoading ? false : undefined)}\n ref={ref}\n >\n {children}\n </NextLink>\n );\n },\n);\nLink.displayName = 'MicrofrontendsLink';\n","'use client';\n\nimport { useState, useEffect, useMemo } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\nimport type { MicrofrontendConfigClientOptions } from '../microfrontends-config/client';\n\nconst clientCache = new Map<string, Map<string, MicrofrontendConfigClient>>();\nconst cachedHasDynamicPaths = new Map<string, boolean>();\n\nconst getOptsKey = (opts?: MicrofrontendConfigClientOptions): string => {\n return JSON.stringify({\n removeFlaggedPaths: opts?.removeFlaggedPaths || false,\n });\n};\n\nconst getClient = (\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n) => {\n const optsKey = getOptsKey(opts);\n let configCache = clientCache.get(config || '');\n if (!configCache) {\n configCache = new Map();\n clientCache.set(config || '', configCache);\n } else {\n const existing = configCache.get(optsKey);\n if (existing) {\n return existing;\n }\n }\n\n const client = MicrofrontendConfigClient.fromEnv(config, opts);\n configCache.set(optsKey, client);\n return client;\n};\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n null;\n\nlet cachedServerClient: MicrofrontendConfigClient | null = null;\n\nasync function fetchClientConfigFromServer(): Promise<MicrofrontendConfigClient | null> {\n try {\n const response = await fetch(\n '/.well-known/vercel/microfrontends/client-config',\n );\n if (response.status !== 200) {\n return null;\n }\n const responseJson = (await response.json()) as WellKnownClientData;\n const client = new MicrofrontendConfigClient(responseJson.config);\n cachedServerClient = client;\n return client;\n } catch (err) {\n return null;\n }\n}\n\n/**\n * Hook to use the client microfrontends configuration. This hook will resolve\n * dynamic paths by fetching the configuration from the server if necessary,\n * allowing the server to specify the values for dynamic paths.\n */\nexport function useClientConfig(\n config: string | undefined,\n {\n removeFlaggedPathsFromDefault,\n }: {\n removeFlaggedPathsFromDefault?: boolean;\n } = {},\n): {\n clientConfig: MicrofrontendConfigClient;\n isLoading: boolean;\n} {\n const [clientConfig, setClientConfig] = useState<MicrofrontendConfigClient>(\n () =>\n cachedServerClient ??\n getClient(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const canLoad = useMemo(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n return false;\n }\n // If we've already fetched the server config and it's resolved, we don't need\n // to enter the loading state at all\n if (cachedServerClient) return false;\n // If we've already checked this config for dynamic paths, we can use the\n // cached result from before instead of reevaluating.\n const existing = cachedHasDynamicPaths.get(config || '');\n if (existing !== undefined) return existing;\n // Since we may remove flagged paths from the client config above, we need\n // to use the original client config to determine if the config has any\n // dynamic paths.\n const originalClientConfig = getClient(config);\n // As an optimization, only fetch the config from the server if the\n // microfrontends configuration has any dynamic paths. If it doesn't,\n // then the server won't return any different values.\n const hasDynamicPaths = Object.values(\n originalClientConfig.applications,\n ).some((app) => app.routing?.some((group) => group.flag));\n cachedHasDynamicPaths.set(config || '', hasDynamicPaths);\n if (!hasDynamicPaths) {\n return false;\n }\n return true;\n }, [config]);\n const [isLoading, setIsLoading] = useState(canLoad);\n useEffect(() => {\n if (!canLoad) return;\n if (!cachedServerClientConfigPromise) {\n cachedServerClientConfigPromise = fetchClientConfigFromServer();\n }\n void cachedServerClientConfigPromise\n .then((newConfig) => {\n if (newConfig) {\n setClientConfig((prevConfig) => {\n return prevConfig.isEqual(newConfig) ? prevConfig : newConfig;\n });\n }\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [config, clientConfig.applications, canLoad]);\n\n return { clientConfig, isLoading };\n}\n\nexport function resetCachedServerClientConfigPromise(): void {\n cachedServerClientConfigPromise = null;\n}\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\nexport interface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nconst regexpCache = new Map<string, RegExp>();\nconst getRegexp = (path: string): RegExp => {\n const existing = regexpCache.get(path);\n if (existing) {\n return existing;\n }\n\n const regexp = pathToRegexp(path);\n regexpCache.set(path, regexp);\n return regexp;\n};\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error(\n 'Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?',\n );\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n this === other ||\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = getRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import React, {\n createContext,\n useCallback,\n useRef,\n useMemo,\n useState,\n startTransition,\n} from 'react';\n\nexport interface PrefetchCrossZoneLinksContext {\n prefetchHref: (href: string) => void;\n}\n\nexport const PrefetchCrossZoneLinksContext =\n createContext<PrefetchCrossZoneLinksContext>({\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n prefetchHref: () => {},\n });\n\nexport function PrefetchCrossZoneLinksProvider({\n children,\n}: {\n children: React.ReactNode;\n}): JSX.Element | null {\n const [seenHrefs, setSeenHrefs] = useState(new Set<string>());\n const isSafariOrFirefox = useRef(\n typeof navigator !== 'undefined' &&\n (navigator.userAgent.includes('Firefox') ||\n (navigator.userAgent.includes('Safari') &&\n !navigator.userAgent.includes('Chrome'))),\n );\n\n // This useCallback must not have any dependencies because if it changes\n // its value, every component that uses this context will rerender.\n const prefetchHref = useCallback((href: string): void => {\n // It's not critical that we render the new preload `<link>` elements\n // immediately. We want to batch together `prefetchHref` calls that\n // occur in one synchronous pass and only render once after they've all\n // called this callback.\n startTransition(() => {\n setSeenHrefs((prevHrefs) => {\n if (prevHrefs.has(href)) return prevHrefs;\n return new Set(prevHrefs).add(href);\n });\n });\n }, []);\n\n const value = useMemo(() => ({ prefetchHref }), [prefetchHref]);\n\n if (!isSafariOrFirefox.current) {\n return <>{children}</>;\n }\n\n return (\n <PrefetchCrossZoneLinksContext.Provider value={value}>\n {children}\n {[...seenHrefs].map((href) => (\n <link as=\"fetch\" href={href} key={href} rel=\"preload\" />\n ))}\n </PrefetchCrossZoneLinksContext.Provider>\n );\n}\n","import { useEffect, useState } from 'react';\nimport Script from 'next/script.js';\nimport { useClientConfig } from '../../../config/react/use-client-config';\n\nconst PREFETCH_ATTR = 'data-prefetch';\nconst DATA_ATTR_SELECTORS = {\n anyZone: '[data-zone]',\n external: '[data-zone=\"null\"]',\n sameZone: '[data-zone=\"same\"]',\n prefetch: `[${PREFETCH_ATTR}]`,\n} as const;\n\nconst PREFETCH_ON_HOVER_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n ],\n};\n\nconst PREFETCH_WHEN_VISIBLE_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n { selector_matches: DATA_ATTR_SELECTORS.prefetch },\n ],\n};\n\nfunction checkVisibility(element: Element | null): boolean {\n if (!element) return true;\n\n if ('checkVisibility' in element) {\n return element.checkVisibility({ opacityProperty: true });\n }\n\n // hack to get around TS thinking element is never;\n const el = element as Element;\n const style = window.getComputedStyle(el);\n\n if (\n style.display === 'none' ||\n style.visibility === 'hidden' ||\n style.opacity === '0'\n ) {\n return false;\n }\n\n return checkVisibility(el.parentElement);\n}\n\nexport function PrefetchCrossZoneLinks(): JSX.Element | null {\n const { isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n const [links, setLinks] = useState<HTMLAnchorElement[]>([]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Intersection observer to add the data-prefetch attribute to cross-zone\n * links that have yet to be prefetched and are visible.\n */\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (\n entry.isIntersecting &&\n !entry.target.hasAttribute(PREFETCH_ATTR) &&\n // lazy perform the visibility check for nodes that are intersecting the viewport\n // and have not been prefetched.\n checkVisibility(entry.target)\n ) {\n entry.target.setAttribute(PREFETCH_ATTR, 'true');\n }\n });\n },\n {\n root: null,\n rootMargin: '0px',\n threshold: 0.1,\n },\n );\n\n links.forEach((link) => observer.observe(link));\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading, links]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Mutation observer to notify when new nodes have entered/exited the document\n * or an href has changed.\n */\n const observer = new MutationObserver((mutations) => {\n const hasChanged = mutations.some((mutation) => {\n return (\n (mutation.type === 'childList' && mutation.addedNodes.length > 0) ||\n (mutation.type === 'attributes' && mutation.attributeName === 'href')\n );\n });\n\n if (hasChanged) {\n // Whenever there's a change, add all cross-zone links that haven't been\n // prefetched.\n setLinks(\n Array.from(\n document.querySelectorAll<HTMLAnchorElement>(\n `a${DATA_ATTR_SELECTORS.anyZone}:not(${DATA_ATTR_SELECTORS.prefetch}):not(${DATA_ATTR_SELECTORS.sameZone}):not(${DATA_ATTR_SELECTORS.external})`,\n ),\n ),\n );\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading]);\n\n // Wait till the zone-config loads to take into consideration any\n // flagged routes.\n if (isLoading) {\n return null;\n }\n\n // Prefetch links with moderate eagerness by default, immediately when marked \"data-prefetch\".\n // Prerender links with conservative eagerness by default, immediately when marked \"data-prefetch\".\n const speculationRules = {\n prefetch: [\n {\n eagerness: 'moderate',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n {\n eagerness: 'immediate',\n where: PREFETCH_WHEN_VISIBLE_PREDICATES,\n },\n ],\n prerender: [\n {\n eagerness: 'conservative',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n ],\n };\n\n return (\n <Script\n dangerouslySetInnerHTML={{\n __html: JSON.stringify(speculationRules),\n }}\n id=\"prefetch-zones-links\"\n type=\"speculationrules\"\n />\n );\n}\n"],"mappings":"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","names":["forwardRef","useContext","useMemo","NextLink","useState","useEffect","useMemo","pathToRegexp","regexpCache","getRegexp","path","existing","regexp","MicrofrontendConfigClient","config","opts","app","match","other","pathname","name","application","group","childPath","defaultApplication","clientCache","cachedHasDynamicPaths","getOptsKey","opts","getClient","config","optsKey","configCache","existing","client","MicrofrontendConfigClient","cachedServerClientConfigPromise","cachedServerClient","fetchClientConfigFromServer","response","responseJson","useClientConfig","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","useState","canLoad","useMemo","originalClientConfig","hasDynamicPaths","app","group","isLoading","setIsLoading","useEffect","newConfig","prevConfig","createContext","useCallback","useRef","useMemo","useState","startTransition","Fragment","jsx","jsxs","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","prefetchHref","href","prevHrefs","value","useEffect","useState","Script","jsx","PREFETCH_ATTR","DATA_ATTR_SELECTORS","PREFETCH_ON_HOVER_PREDICATES","PREFETCH_WHEN_VISIBLE_PREDICATES","checkVisibility","element","el","style","PrefetchCrossZoneLinks","isLoading","useClientConfig","links","setLinks","useState","useEffect","observer","entries","entry","link","mutations","mutation","Script","jsx","CURRENT_ZONE","useZoneForHref","href","clientConfig","isLoading","useClientConfig","isRelativePath","zoneOfHref","useMemo","isRelative","Link","forwardRef","children","props","ref","prefetchHref","useContext","PrefetchCrossZoneLinksContext","isDifferentZone","onHoverPrefetch","_","rest","NextLink"]}
@@ -276,7 +276,7 @@ ${matchingPaths.join("\n \u2022 ")}`,
276
276
  }
277
277
  if (matchingPaths.length === 0) {
278
278
  throw new MicrofrontendError(
279
- `Could not find a \`microfrontends.json\` file in the repository that contains "applications.${applicationName}". Microfrontends defined in separate repositories are not supported yet.`,
279
+ `Could not find a \`microfrontends.json\` file in the repository that contains "applications.${applicationName}". If your Vercel Microfrontends configuration is not in this repository, you can use the Vercel CLI to pull the Vercel Microfrontends configuration using the "vercel microfrontends pull" command, or you can specify the path manually using the VC_MICROFRONTENDS_CONFIG environment variable. If you suspect this is thrown in error, please reach out to the Vercel team.`,
280
280
  { type: "config", subtype: "inference_failed" }
281
281
  );
282
282
  }