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

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.
package/CHANGELOG.md CHANGED
@@ -8,7 +8,7 @@
8
8
  - `projectId` is annoying to set up so we hope this simplifies things!
9
9
  - Ensure the application name matches the corresponding vercel project name, then remove the `projectId`.
10
10
  - The Vercel project name should ideally also match the application's `package.json` name. If this is not the case, you will need to set the `packageName` field to the `name` from the `package.json` file. This is needed for the local development proxy to work.
11
- - Add a performance improvement for `PrefetchCrossZoneLinksProvider`
11
+ - Add performance improvements for `PrefetchCrossZoneLinksProvider`
12
12
  - Minimise rerenders whenever new links are prefetched with `prefetchHref`.
13
13
 
14
14
  ## 1.3.0
package/dist/bin/cli.cjs CHANGED
@@ -30,7 +30,7 @@ var import_env = require("@next/env");
30
30
  // package.json
31
31
  var package_default = {
32
32
  name: "@vercel/microfrontends",
33
- version: "1.4.0-canary.2",
33
+ version: "1.4.0-canary.3",
34
34
  private: false,
35
35
  description: "Defines configuration and utilities for microfrontends development",
36
36
  keywords: [
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- "use strict";var z=Object.create;var C=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var $=(t,e)=>{for(var r in e)C(t,r,{get:e[r],enumerable:!0})},y=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of U(e))!J.call(t,n)&&n!==r&&C(t,n,{get:()=>e[n],enumerable:!(o=B(e,n))||o.enumerable});return t};var x=(t,e,r)=>(r=t!=null?z(X(t)):{},y(e||!t||!t.__esModule?C(r,"default",{value:t,enumerable:!0}):r,t)),V=t=>y(C({},"__esModule",{value:!0}),t);var ee={};$(ee,{Image:()=>Z,Link:()=>A,PrefetchCrossZoneLinks:()=>K,PrefetchCrossZoneLinksContext:()=>E,PrefetchCrossZoneLinksProvider:()=>q,useZoneForHref:()=>k});module.exports=V(ee);var P=require("react"),b=x(require("next/link.js"),1);var d=require("react");var R=require("path-to-regexp"),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 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((0,R.pathToRegexp)(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 L=null;async function W(){try{let t=await fetch("/.well-known/vercel/microfrontends/client-config");if(t.status!==200)return null;let e=await t.json();return new l(e.config)}catch{return null}}function m(t,{removeFlaggedPathsFromDefault:e}={}){let[r,o]=(0,d.useState)(l.fromEnv(t,{removeFlaggedPaths:e})),[n,i]=(0,d.useState)(!0);return(0,d.useEffect)(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"){i(!1);return}let s=l.fromEnv(t);if(!Object.values(s.applications).some(u=>u.routing?.some(h=>h.flag))){i(!1);return}L||(L=W()),L.then(u=>{u&&o(h=>h.isEqual(u)?h:u)}).finally(()=>{i(!1)})},[t,r.applications]),{clientConfig:r,isLoading:n}}var f=require("react"),p=require("react/jsx-runtime"),E=(0,f.createContext)({prefetchHref:()=>{}});function q({children:t}){let[e,r]=(0,f.useState)(new Set),o=(0,f.useRef)(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),n=(0,f.useCallback)(s=>{(0,f.startTransition)(()=>{r(a=>a.has(s)?a:new Set(e).add(s))})},[]),i=(0,f.useMemo)(()=>({prefetchHref:n}),[n]);return o.current?(0,p.jsxs)(E.Provider,{value:i,children:[t,[...e].map(s=>(0,p.jsx)("link",{as:"fetch",href:s,rel:"preload"},s))]}):(0,p.jsx)(p.Fragment,{children:t})}var g=require("react"),T=x(require("next/script.js"),1);var F=require("react/jsx-runtime"),N="data-prefetch",c={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${N}]`},O={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}}]},G={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}},{selector_matches:c.prefetch}]};function I(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:I(e.parentElement)}function K(){let{isLoading:t}=m(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=(0,g.useState)([]);return(0,g.useEffect)(()=>{if(t)return;let n=new IntersectionObserver(i=>{i.forEach(s=>{s.isIntersecting&&!s.target.hasAttribute(N)&&I(s.target)&&s.target.setAttribute(N,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(i=>n.observe(i)),()=>{n.disconnect()}},[t,e]),(0,g.useEffect)(()=>{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${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:(0,F.jsx)(T.default,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:O},{eagerness:"immediate",where:G}],prerender:[{eagerness:"conservative",where:O}]})},id:"prefetch-zones-links",type:"speculationrules"})}var _=require("react/jsx-runtime"),j=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function k(t){let{clientConfig:e,isLoading:r}=m(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?j!==n:!1),isLoading:r}}var A=(0,P.forwardRef)(({children:t,...e},r)=>{let{prefetchHref:o}=(0,P.useContext)(E),{zoneOfHref:n,isDifferentZone:i,isLoading:s}=k(e.href);function a(){e.href&&o(e.href)}if(i&&n!==null){let{prefetch:u,...h}=e;return(0,_.jsx)("a",{...h,"data-zone":n,onFocus:e.prefetch!==!1?a:void 0,onMouseOver:e.prefetch!==!1?a:void 0,children:t})}return(0,_.jsx)(b.default,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(s?!1:void 0),ref:r,children:t})});A.displayName="MicrofrontendsLink";var w=require("react"),S=require("next/dist/client/image-component.js"),H=require("next/image.js");var Q="vc-ap";function M({name:t}){if(!t)throw new Error("Name is required to generate an asset prefix");return`${Q}-${t}`}var D=require("react/jsx-runtime"),v=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION,Y=(t,e)=>()=>`/${t}${e}`,Z=(0,w.forwardRef)(({...t},e)=>{let{clientConfig:r}=m(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),o=v&&!r.applications[v]?.default?M({name:v}):null,{props:{src:n}}=(0,H.getImageProps)(t);return(0,D.jsx)(S.Image,{loader:o?Y(o,n):void 0,...t,ref:e})});Z.displayName="MicrofrontendsImage";0&&(module.exports={Image,Link,PrefetchCrossZoneLinks,PrefetchCrossZoneLinksContext,PrefetchCrossZoneLinksProvider,useZoneForHref});
2
+ "use strict";var B=Object.create;var C=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,$=Object.prototype.hasOwnProperty;var V=(t,e)=>{for(var r in e)C(t,r,{get:e[r],enumerable:!0})},y=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of X(e))!$.call(t,n)&&n!==r&&C(t,n,{get:()=>e[n],enumerable:!(o=U(e,n))||o.enumerable});return t};var x=(t,e,r)=>(r=t!=null?B(J(t)):{},y(e||!t||!t.__esModule?C(r,"default",{value:t,enumerable:!0}):r,t)),W=t=>y(C({},"__esModule",{value:!0}),t);var te={};V(te,{Image:()=>Z,Link:()=>M,PrefetchCrossZoneLinks:()=>j,PrefetchCrossZoneLinksContext:()=>E,PrefetchCrossZoneLinksProvider:()=>G,useZoneForHref:()=>k});module.exports=W(te);var d=require("react"),b=x(require("next/link.js"),1);var u=require("react");var R=require("path-to-regexp"),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 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((0,R.pathToRegexp)(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 L=null;async function q(){try{let t=await fetch("/.well-known/vercel/microfrontends/client-config");if(t.status!==200)return null;let e=await t.json();return new l(e.config)}catch{return null}}function m(t,{removeFlaggedPathsFromDefault:e}={}){let[r,o]=(0,u.useState)(()=>l.fromEnv(t,{removeFlaggedPaths:e})),n=(0,u.useMemo)(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1")return!1;let s=l.fromEnv(t);return!!Object.values(s.applications).some(P=>P.routing?.some(z=>z.flag))},[t]),[a,i]=(0,u.useState)(n);return(0,u.useEffect)(()=>{n&&(L||(L=q()),L.then(s=>{s&&o(h=>h.isEqual(s)?h:s)}).finally(()=>{i(!1)}))},[t,r.applications,n]),{clientConfig:r,isLoading:a}}var f=require("react"),p=require("react/jsx-runtime"),E=(0,f.createContext)({prefetchHref:()=>{}});function G({children:t}){let[e,r]=(0,f.useState)(new Set),o=(0,f.useRef)(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),n=(0,f.useCallback)(i=>{(0,f.startTransition)(()=>{r(s=>s.has(i)?s:new Set(e).add(i))})},[]),a=(0,f.useMemo)(()=>({prefetchHref:n}),[n]);return o.current?(0,p.jsxs)(E.Provider,{value:a,children:[t,[...e].map(i=>(0,p.jsx)("link",{as:"fetch",href:i,rel:"preload"},i))]}):(0,p.jsx)(p.Fragment,{children:t})}var g=require("react"),T=x(require("next/script.js"),1);var F=require("react/jsx-runtime"),v="data-prefetch",c={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${v}]`},O={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}}]},K={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}},{selector_matches:c.prefetch}]};function I(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:I(e.parentElement)}function j(){let{isLoading:t}=m(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=(0,g.useState)([]);return(0,g.useEffect)(()=>{if(t)return;let n=new IntersectionObserver(a=>{a.forEach(i=>{i.isIntersecting&&!i.target.hasAttribute(v)&&I(i.target)&&i.target.setAttribute(v,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(a=>n.observe(a)),()=>{n.disconnect()}},[t,e]),(0,g.useEffect)(()=>{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:(0,F.jsx)(T.default,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:O},{eagerness:"immediate",where:K}],prerender:[{eagerness:"conservative",where:O}]})},id:"prefetch-zones-links",type:"speculationrules"})}var N=require("react/jsx-runtime"),Q=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function k(t){let{clientConfig:e,isLoading:r}=m(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),{isRelativePath:o,zoneOfHref:n}=(0,d.useMemo)(()=>{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?Q!==n:!1),isLoading:r}}var M=(0,d.forwardRef)(({children:t,...e},r)=>{let{prefetchHref:o}=(0,d.useContext)(E),{zoneOfHref:n,isDifferentZone:a,isLoading:i}=k(e.href);function s(){e.href&&o(e.href)}if(a&&n!==null){let{prefetch:h,...P}=e;return(0,N.jsx)("a",{...P,"data-zone":n,onFocus:e.prefetch!==!1?s:void 0,onMouseOver:e.prefetch!==!1?s:void 0,children:t})}return(0,N.jsx)(b.default,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(i?!1:void 0),ref:r,children:t})});M.displayName="MicrofrontendsLink";var w=require("react"),S=require("next/dist/client/image-component.js"),H=require("next/image.js");var Y="vc-ap";function A({name:t}){if(!t)throw new Error("Name is required to generate an asset prefix");return`${Y}-${t}`}var D=require("react/jsx-runtime"),_=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION,ee=(t,e)=>()=>`/${t}${e}`,Z=(0,w.forwardRef)(({...t},e)=>{let{clientConfig:r}=m(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),o=_&&!r.applications[_]?.default?A({name:_}):null,{props:{src:n}}=(0,H.getImageProps)(t);return(0,D.jsx)(S.Image,{loader:o?ee(o,n):void 0,...t,ref:e})});Z.displayName="MicrofrontendsImage";0&&(module.exports={Image,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 } 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
+ {"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';\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 () =>\n MicrofrontendConfigClient.fromEnv(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 // 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 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\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","canLoad","originalClientConfig","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,3 +1,3 @@
1
1
  "use client";
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};
2
+ import{forwardRef as B,useContext as U,useMemo as X}from"react";import J from"next/link.js";import{useState as C,useEffect as R,useMemo as O}from"react";import{pathToRegexp as x}from"path-to-regexp";var c=class{constructor(e,r){this.pathCache={};if(this.serialized=e,r?.removeFlaggedPaths)for(let i of Object.values(e.applications))i.routing&&(i.routing=i.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,a]of Object.entries(this.applications))if(a.routing){for(let o of a.routing)for(let s of o.paths)if(x(s).test(r))return this.pathCache[e]=n,n}let i=Object.entries(this.applications).find(([,n])=>n.default);return i?(this.pathCache[e]=i[0],i[0]):null}serialize(){return this.serialized}};var m=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();return new c(e.config)}catch{return null}}function l(t,{removeFlaggedPathsFromDefault:e}={}){let[r,i]=C(()=>c.fromEnv(t,{removeFlaggedPaths:e})),n=O(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1")return!1;let s=c.fromEnv(t);return!!Object.values(s.applications).some(p=>p.routing?.some(y=>y.flag))},[t]),[a,o]=C(n);return R(()=>{n&&(m||(m=T()),m.then(s=>{s&&i(u=>u.isEqual(s)?u:s)}).finally(()=>{o(!1)}))},[t,r.applications,n]),{clientConfig:r,isLoading:a}}import{createContext as I,useCallback as F,useRef as b,useMemo as k,useState as M,startTransition as A}from"react";import{Fragment as w,jsx as E,jsxs as S}from"react/jsx-runtime";var d=I({prefetchHref:()=>{}});function fe({children:t}){let[e,r]=M(new Set),i=b(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),n=F(o=>{A(()=>{r(s=>s.has(o)?s:new Set(e).add(o))})},[]),a=k(()=>({prefetchHref:n}),[n]);return i.current?S(d.Provider,{value:a,children:[t,[...e].map(o=>E("link",{as:"fetch",href:o,rel:"preload"},o))]}):E(w,{children:t})}import{useEffect as P,useState as H}from"react";import Z from"next/script.js";import{jsx as z}from"react/jsx-runtime";var h="data-prefetch",f={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${h}]`},L={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}}]},D={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}},{selector_matches:f.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 de(){let{isLoading:t}=l(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=H([]);return P(()=>{if(t)return;let n=new IntersectionObserver(a=>{a.forEach(o=>{o.isIntersecting&&!o.target.hasAttribute(h)&&v(o.target)&&o.target.setAttribute(h,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(a=>n.observe(a)),()=>{n.disconnect()}},[t,e]),P(()=>{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${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(Z,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:L},{eagerness:"immediate",where:D}],prerender:[{eagerness:"conservative",where:L}]})},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as N}from"react/jsx-runtime";var $=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function V(t){let{clientConfig:e,isLoading:r}=l(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),{isRelativePath:i,zoneOfHref:n}=X(()=>{let o=typeof t=="string"&&t.startsWith("/");return{isRelativePath:o,zoneOfHref:o?e.getApplicationNameForPath(t):null}},[e,t]);return typeof t=="string"&&!t.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:n,isDifferentZone:!i||(n?$!==n:!1),isLoading:r}}var W=B(({children:t,...e},r)=>{let{prefetchHref:i}=U(d),{zoneOfHref:n,isDifferentZone:a,isLoading:o}=V(e.href);function s(){e.href&&i(e.href)}if(a&&n!==null){let{prefetch:u,...p}=e;return N("a",{...p,"data-zone":n,onFocus:e.prefetch!==!1?s:void 0,onMouseOver:e.prefetch!==!1?s:void 0,children:t})}return N(J,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(o?!1:void 0),ref:r,children:t})});W.displayName="MicrofrontendsLink";import{forwardRef as G}from"react";import{Image as K}from"next/dist/client/image-component.js";import{getImageProps as j}from"next/image.js";var q="vc-ap";function _({name:t}){if(!t)throw new Error("Name is required to generate an asset prefix");return`${q}-${t}`}import{jsx as ee}from"react/jsx-runtime";var g=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION,Q=(t,e)=>()=>`/${t}${e}`,Y=G(({...t},e)=>{let{clientConfig:r}=l(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),i=g&&!r.applications[g]?.default?_({name:g}):null,{props:{src:n}}=j(t);return ee(K,{loader:i?Q(i,n):void 0,...t,ref:e})});Y.displayName="MicrofrontendsImage";export{Y as Image,W as Link,de as PrefetchCrossZoneLinks,d as PrefetchCrossZoneLinksContext,fe as PrefetchCrossZoneLinksProvider,V 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 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"]}
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';\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 () =>\n MicrofrontendConfigClient.fromEnv(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 // 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 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\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","useMemo","NextLink","useState","useEffect","useMemo","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","canLoad","useMemo","originalClientConfig","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/microfrontends",
3
- "version": "1.4.0-canary.2",
3
+ "version": "1.4.0-canary.3",
4
4
  "private": false,
5
5
  "description": "Defines configuration and utilities for microfrontends development",
6
6
  "keywords": [