@vercel/microfrontends 1.4.0-canary.1 → 1.4.0-canary.2

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +7 -8
  2. package/dist/bin/cli.cjs +7 -4
  3. package/dist/config.cjs +6 -3
  4. package/dist/config.cjs.map +1 -1
  5. package/dist/config.d.ts +1 -1
  6. package/dist/config.js +6 -3
  7. package/dist/config.js.map +1 -1
  8. package/dist/experimental/sveltekit.cjs +6 -3
  9. package/dist/experimental/sveltekit.cjs.map +1 -1
  10. package/dist/experimental/sveltekit.js +6 -3
  11. package/dist/experimental/sveltekit.js.map +1 -1
  12. package/dist/experimental/vite.cjs +6 -3
  13. package/dist/experimental/vite.cjs.map +1 -1
  14. package/dist/experimental/vite.js +6 -3
  15. package/dist/experimental/vite.js.map +1 -1
  16. package/dist/microfrontends/server.cjs +6 -3
  17. package/dist/microfrontends/server.cjs.map +1 -1
  18. package/dist/microfrontends/server.js +6 -3
  19. package/dist/microfrontends/server.js.map +1 -1
  20. package/dist/next/client.cjs +1 -1
  21. package/dist/next/client.cjs.map +1 -1
  22. package/dist/next/client.js +1 -1
  23. package/dist/next/client.js.map +1 -1
  24. package/dist/next/config.cjs +11 -4
  25. package/dist/next/config.cjs.map +1 -1
  26. package/dist/next/config.js +11 -4
  27. package/dist/next/config.js.map +1 -1
  28. package/dist/next/middleware.cjs +6 -3
  29. package/dist/next/middleware.cjs.map +1 -1
  30. package/dist/next/middleware.js +6 -3
  31. package/dist/next/middleware.js.map +1 -1
  32. package/dist/next/testing.cjs +6 -3
  33. package/dist/next/testing.cjs.map +1 -1
  34. package/dist/next/testing.js +6 -3
  35. package/dist/next/testing.js.map +1 -1
  36. package/dist/utils/mfe-port.cjs +6 -3
  37. package/dist/utils/mfe-port.cjs.map +1 -1
  38. package/dist/utils/mfe-port.js +6 -3
  39. package/dist/utils/mfe-port.js.map +1 -1
  40. package/package.json +1 -1
@@ -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 } 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 = typeof href === 'string' && href.startsWith('/');\n const zoneOfHref = isRelativePath\n ? clientConfig.getApplicationNameForPath(href)\n : null;\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 } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n 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 return new MicrofrontendConfigClient(responseJson.config);\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 MicrofrontendConfigClient.fromEnv(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const [isLoading, setIsLoading] = useState(true);\n useEffect(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n setIsLoading(false);\n return;\n }\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 = MicrofrontendConfigClient.fromEnv(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 if (!hasDynamicPaths) {\n setIsLoading(false);\n return;\n }\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]);\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\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\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 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 = pathToRegexp(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} 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 const prefetchHref = useCallback(\n (href: string): void => {\n if (!seenHrefs.has(href)) {\n setSeenHrefs(new Set(seenHrefs).add(href));\n }\n },\n [seenHrefs],\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","MicrofrontendConfigClient","config","opts","app","match","other","path","pathname","name","application","group","childPath","defaultApplication","cachedServerClientConfigPromise","fetchClientConfigFromServer","response","responseJson","MicrofrontendConfigClient","useClientConfig","config","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","isLoading","setIsLoading","originalClientConfig","app","group","newConfig","prevConfig","import_react","import_jsx_runtime","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","prefetchHref","href","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","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","../../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 } 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 = typeof href === 'string' && href.startsWith('/');\n const zoneOfHref = isRelativePath\n ? clientConfig.getApplicationNameForPath(href)\n : null;\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 } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n 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 return new MicrofrontendConfigClient(responseJson.config);\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 MicrofrontendConfigClient.fromEnv(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const [isLoading, setIsLoading] = useState(true);\n useEffect(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n setIsLoading(false);\n return;\n }\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 = MicrofrontendConfigClient.fromEnv(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 if (!hasDynamicPaths) {\n setIsLoading(false);\n return;\n }\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]);\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\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\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 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 = pathToRegexp(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(seenHrefs).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","MicrofrontendConfigClient","config","opts","app","match","other","path","pathname","name","application","group","childPath","defaultApplication","cachedServerClientConfigPromise","fetchClientConfigFromServer","response","responseJson","MicrofrontendConfigClient","useClientConfig","config","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","isLoading","setIsLoading","originalClientConfig","app","group","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","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,3 +1,3 @@
1
1
  "use client";
2
- import{forwardRef as Z,useContext as D}from"react";import z from"next/link.js";import{useState as C,useEffect as x}from"react";import{pathToRegexp as y}from"path-to-regexp";var c=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 c(JSON.parse(e),r)}isEqual(e){return 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,i]of Object.entries(this.applications))if(i.routing){for(let s of i.routing)for(let f of s.paths)if(y(f).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 h=null;async function R(){try{let t=await fetch("/.well-known/vercel/microfrontends/client-config");if(t.status!==200)return null;let e=await t.json();return new c(e.config)}catch{return null}}function p(t,{removeFlaggedPathsFromDefault:e}={}){let[r,o]=C(c.fromEnv(t,{removeFlaggedPaths:e})),[n,i]=C(!0);return x(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"){i(!1);return}let s=c.fromEnv(t);if(!Object.values(s.applications).some(l=>l.routing?.some(u=>u.flag))){i(!1);return}h||(h=R()),h.then(l=>{l&&o(u=>u.isEqual(l)?u:l)}).finally(()=>{i(!1)})},[t,r.applications]),{clientConfig:r,isLoading:n}}import{createContext as O,useCallback as I,useRef as T,useMemo as F,useState as b}from"react";import{Fragment as k,jsx as E,jsxs as A}from"react/jsx-runtime";var m=O({prefetchHref:()=>{}});function oe({children:t}){let[e,r]=b(new Set),o=T(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),n=I(s=>{e.has(s)||r(new Set(e).add(s))},[e]),i=F(()=>({prefetchHref:n}),[n]);return o.current?A(m.Provider,{value:i,children:[t,[...e].map(s=>E("link",{as:"fetch",href:s,rel:"preload"},s))]}):E(k,{children:t})}import{useEffect as P,useState as M}from"react";import w from"next/script.js";import{jsx as H}from"react/jsx-runtime";var d="data-prefetch",a={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${d}]`},L={and:[{href_matches:"/*"},{selector_matches:a.anyZone},{not:{selector_matches:a.sameZone}},{not:{selector_matches:a.external}}]},S={and:[{href_matches:"/*"},{selector_matches:a.anyZone},{not:{selector_matches:a.sameZone}},{not:{selector_matches:a.external}},{selector_matches:a.prefetch}]};function v(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:v(e.parentElement)}function le(){let{isLoading:t}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=M([]);return P(()=>{if(t)return;let n=new IntersectionObserver(i=>{i.forEach(s=>{s.isIntersecting&&!s.target.hasAttribute(d)&&v(s.target)&&s.target.setAttribute(d,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(i=>n.observe(i)),()=>{n.disconnect()}},[t,e]),P(()=>{if(t)return;let n=new MutationObserver(i=>{i.some(f=>f.type==="childList"&&f.addedNodes.length>0||f.type==="attributes"&&f.attributeName==="href")&&r(Array.from(document.querySelectorAll(`a${a.anyZone}:not(${a.prefetch}):not(${a.sameZone}):not(${a.external})`)))});return n.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{n.disconnect()}},[t]),t?null:H(w,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:L},{eagerness:"immediate",where:S}],prerender:[{eagerness:"conservative",where:L}]})},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as N}from"react/jsx-runtime";var B=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function U(t){let{clientConfig:e,isLoading:r}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),o=typeof t=="string"&&t.startsWith("/"),n=o?e.getApplicationNameForPath(t):null;return typeof t=="string"&&!t.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:n,isDifferentZone:!o||(n?B!==n:!1),isLoading:r}}var X=Z(({children:t,...e},r)=>{let{prefetchHref:o}=D(m),{zoneOfHref:n,isDifferentZone:i,isLoading:s}=U(e.href);function f(){e.href&&o(e.href)}if(i&&n!==null){let{prefetch:l,...u}=e;return N("a",{...u,"data-zone":n,onFocus:e.prefetch!==!1?f:void 0,onMouseOver:e.prefetch!==!1?f:void 0,children:t})}return N(z,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(s?!1:void 0),ref:r,children:t})});X.displayName="MicrofrontendsLink";import{forwardRef as $}from"react";import{Image as V}from"next/dist/client/image-component.js";import{getImageProps as W}from"next/image.js";var J="vc-ap";function _({name:t}){if(!t)throw new Error("Name is required to generate an asset prefix");return`${J}-${t}`}import{jsx as K}from"react/jsx-runtime";var g=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION,q=(t,e)=>()=>`/${t}${e}`,G=$(({...t},e)=>{let{clientConfig:r}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),o=g&&!r.applications[g]?.default?_({name:g}):null,{props:{src:n}}=W(t);return K(V,{loader:o?q(o,n):void 0,...t,ref:e})});G.displayName="MicrofrontendsImage";export{G as Image,X as Link,le as PrefetchCrossZoneLinks,m as PrefetchCrossZoneLinksContext,oe as PrefetchCrossZoneLinksProvider,U as useZoneForHref};
2
+ import{forwardRef as D,useContext as z}from"react";import B from"next/link.js";import{useState as C,useEffect as x}from"react";import{pathToRegexp as y}from"path-to-regexp";var c=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 c(JSON.parse(e),r)}isEqual(e){return 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,i]of Object.entries(this.applications))if(i.routing){for(let s of i.routing)for(let a of s.paths)if(y(a).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 h=null;async function R(){try{let t=await fetch("/.well-known/vercel/microfrontends/client-config");if(t.status!==200)return null;let e=await t.json();return new c(e.config)}catch{return null}}function p(t,{removeFlaggedPathsFromDefault:e}={}){let[r,o]=C(c.fromEnv(t,{removeFlaggedPaths:e})),[n,i]=C(!0);return x(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"){i(!1);return}let s=c.fromEnv(t);if(!Object.values(s.applications).some(l=>l.routing?.some(u=>u.flag))){i(!1);return}h||(h=R()),h.then(l=>{l&&o(u=>u.isEqual(l)?u:l)}).finally(()=>{i(!1)})},[t,r.applications]),{clientConfig:r,isLoading:n}}import{createContext as O,useCallback as T,useRef as I,useMemo as F,useState as b,startTransition as k}from"react";import{Fragment as A,jsx as E,jsxs as M}from"react/jsx-runtime";var m=O({prefetchHref:()=>{}});function ie({children:t}){let[e,r]=b(new Set),o=I(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),n=T(s=>{k(()=>{r(a=>a.has(s)?a:new Set(e).add(s))})},[]),i=F(()=>({prefetchHref:n}),[n]);return o.current?M(m.Provider,{value:i,children:[t,[...e].map(s=>E("link",{as:"fetch",href:s,rel:"preload"},s))]}):E(A,{children:t})}import{useEffect as P,useState as w}from"react";import S from"next/script.js";import{jsx as Z}from"react/jsx-runtime";var d="data-prefetch",f={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${d}]`},L={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}}]},H={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}},{selector_matches:f.prefetch}]};function N(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:N(e.parentElement)}function ue(){let{isLoading:t}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=w([]);return P(()=>{if(t)return;let n=new IntersectionObserver(i=>{i.forEach(s=>{s.isIntersecting&&!s.target.hasAttribute(d)&&N(s.target)&&s.target.setAttribute(d,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(i=>n.observe(i)),()=>{n.disconnect()}},[t,e]),P(()=>{if(t)return;let n=new MutationObserver(i=>{i.some(a=>a.type==="childList"&&a.addedNodes.length>0||a.type==="attributes"&&a.attributeName==="href")&&r(Array.from(document.querySelectorAll(`a${f.anyZone}:not(${f.prefetch}):not(${f.sameZone}):not(${f.external})`)))});return n.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{n.disconnect()}},[t]),t?null:Z(S,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:L},{eagerness:"immediate",where:H}],prerender:[{eagerness:"conservative",where:L}]})},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as _}from"react/jsx-runtime";var U=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function X(t){let{clientConfig:e,isLoading:r}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),o=typeof t=="string"&&t.startsWith("/"),n=o?e.getApplicationNameForPath(t):null;return typeof t=="string"&&!t.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:n,isDifferentZone:!o||(n?U!==n:!1),isLoading:r}}var J=D(({children:t,...e},r)=>{let{prefetchHref:o}=z(m),{zoneOfHref:n,isDifferentZone:i,isLoading:s}=X(e.href);function a(){e.href&&o(e.href)}if(i&&n!==null){let{prefetch:l,...u}=e;return _("a",{...u,"data-zone":n,onFocus:e.prefetch!==!1?a:void 0,onMouseOver:e.prefetch!==!1?a:void 0,children:t})}return _(B,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(s?!1:void 0),ref:r,children:t})});J.displayName="MicrofrontendsLink";import{forwardRef as V}from"react";import{Image as W}from"next/dist/client/image-component.js";import{getImageProps as q}from"next/image.js";var $="vc-ap";function v({name:t}){if(!t)throw new Error("Name is required to generate an asset prefix");return`${$}-${t}`}import{jsx as j}from"react/jsx-runtime";var g=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION,G=(t,e)=>()=>`/${t}${e}`,K=V(({...t},e)=>{let{clientConfig:r}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),o=g&&!r.applications[g]?.default?v({name:g}):null,{props:{src:n}}=q(t);return j(W,{loader:o?G(o,n):void 0,...t,ref:e})});K.displayName="MicrofrontendsImage";export{K as Image,J as Link,ue as PrefetchCrossZoneLinks,m as PrefetchCrossZoneLinksContext,ie as PrefetchCrossZoneLinksProvider,X 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 } 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 = typeof href === 'string' && href.startsWith('/');\n const zoneOfHref = isRelativePath\n ? clientConfig.getApplicationNameForPath(href)\n : null;\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 } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n 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 return new MicrofrontendConfigClient(responseJson.config);\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 MicrofrontendConfigClient.fromEnv(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const [isLoading, setIsLoading] = useState(true);\n useEffect(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n setIsLoading(false);\n return;\n }\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 = MicrofrontendConfigClient.fromEnv(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 if (!hasDynamicPaths) {\n setIsLoading(false);\n return;\n }\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]);\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\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\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 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 = pathToRegexp(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} 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 const prefetchHref = useCallback(\n (href: string): void => {\n if (!seenHrefs.has(href)) {\n setSeenHrefs(new Set(seenHrefs).add(href));\n }\n },\n [seenHrefs],\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","NextLink","useState","useEffect","pathToRegexp","MicrofrontendConfigClient","config","opts","app","match","other","path","pathname","name","application","group","childPath","defaultApplication","cachedServerClientConfigPromise","fetchClientConfigFromServer","response","responseJson","MicrofrontendConfigClient","useClientConfig","config","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","useState","isLoading","setIsLoading","useEffect","originalClientConfig","app","group","newConfig","prevConfig","createContext","useCallback","useRef","useMemo","useState","Fragment","jsx","jsxs","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","prefetchHref","href","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","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","../../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 } 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 = typeof href === 'string' && href.startsWith('/');\n const zoneOfHref = isRelativePath\n ? clientConfig.getApplicationNameForPath(href)\n : null;\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 } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n 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 return new MicrofrontendConfigClient(responseJson.config);\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 MicrofrontendConfigClient.fromEnv(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const [isLoading, setIsLoading] = useState(true);\n useEffect(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n setIsLoading(false);\n return;\n }\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 = MicrofrontendConfigClient.fromEnv(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 if (!hasDynamicPaths) {\n setIsLoading(false);\n return;\n }\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]);\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\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\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 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 = pathToRegexp(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(seenHrefs).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","NextLink","useState","useEffect","pathToRegexp","MicrofrontendConfigClient","config","opts","app","match","other","path","pathname","name","application","group","childPath","defaultApplication","cachedServerClientConfigPromise","fetchClientConfigFromServer","response","responseJson","MicrofrontendConfigClient","useClientConfig","config","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","useState","isLoading","setIsLoading","useEffect","originalClientConfig","app","group","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","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"]}
@@ -607,6 +607,9 @@ var validateDeprecatedFields = (config) => {
607
607
  );
608
608
  }
609
609
  if (application.projectId) {
610
+ errors.push(
611
+ `Application '${applicationId}' cannot contain deprecated field 'projectId'. If the application ID matches the Vercel project name, then please remove the 'projectId' field. Otherwise, either update the application ID / Vercel project name to match, or set the 'packageName' field to the name of the package.json name.`
612
+ );
610
613
  }
611
614
  }
612
615
  if (errors.length) {
@@ -955,12 +958,12 @@ var MicrofrontendConfigIsomorphic = class {
955
958
  return false;
956
959
  }
957
960
  }
958
- getApplicationByProjectId(projectId) {
959
- if (this.defaultApplication.projectId === projectId) {
961
+ getApplicationByProjectName(projectName) {
962
+ if (this.defaultApplication.name === projectName) {
960
963
  return this.defaultApplication;
961
964
  }
962
965
  return Object.values(this.childApplications).find(
963
- (app) => app.projectId === projectId
966
+ (app) => app.name === projectName
964
967
  );
965
968
  }
966
969
  /**
@@ -1876,7 +1879,11 @@ function withMicrofrontends(nextConfig, opts) {
1876
1879
  throw e;
1877
1880
  }
1878
1881
  }
1879
- displayLocalProxyInfo(microfrontends.config.getLocalProxyPort());
1882
+ const localProxyPort = microfrontends.config.getLocalProxyPort();
1883
+ if (typeof localProxyPort === "number") {
1884
+ process.env.MFE_LOCAL_PROXY_PORT = localProxyPort.toString();
1885
+ }
1886
+ displayLocalProxyInfo(localProxyPort);
1880
1887
  return next;
1881
1888
  }
1882
1889
  // Annotate the CommonJS export names for ESM import in node: