@vercel/microfrontends
Version:
Defines configuration and utilities for microfrontends development
3 lines • 6.01 kB
JavaScript
"use client";
import{forwardRef as U,useContext as W,useMemo as X}from"react";import $ from"next/link.js";import{useState as m,useEffect as M,useMemo as S}from"react";import{pathToRegexp as N}from"path-to-regexp";var C=new Map,b=t=>{let e=C.get(t);if(e)return e;let r=N(t);return C.set(t,r),r},f=class{constructor(e,r){this.pathCache={};this.hasFlaggedPaths=e.hasFlaggedPaths??!1;for(let i of Object.values(e.applications))if(i.routing){i.routing.some(n=>n.flag)&&(this.hasFlaggedPaths=!0);let o=[],s=[];for(let n of i.routing)if(n.flag){if(r?.removeFlaggedPaths)continue;n.group&&delete n.group,o.push(n)}else s.push(...n.paths);s.length>0&&o.push({paths:s}),i.routing=o}this.serialized=e,this.hasFlaggedPaths&&(this.serialized.hasFlaggedPaths=this.hasFlaggedPaths),this.applications=e.applications}static fromEnv(e){if(!e)throw new Error("Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`? Is the local proxy running and this application is being accessed via the proxy port? See https://vercel.com/docs/microfrontends/local-development#setting-up-microfrontends-proxy");return new f(JSON.parse(e))}isEqual(e){return this===e||JSON.stringify(this.applications)===JSON.stringify(e.applications)}getApplicationNameForPath(e){if(!e.startsWith("/"))throw new Error("Path must start with a /");if(this.pathCache[e])return this.pathCache[e];let r=new URL(e,"https://example.com").pathname;for(let[o,s]of Object.entries(this.applications))if(s.routing){for(let n of s.routing)for(let a of n.paths)if(b(a).test(r))return this.pathCache[e]=o,o}let i=Object.entries(this.applications).find(([,o])=>o.default);return i?(this.pathCache[e]=i[0],i[0]):null}serialize(){return this.serialized}};var P=new Map,E=new Map,L=t=>{let e=P.get(t||"");if(e)return e;let r=f.fromEnv(t);return P.set(t||"",r),r},h=null,p=null;async function F(){try{let t=await fetch("/.well-known/vercel/microfrontends/client-config");if(t.status!==200)return null;let e=await t.json(),r=new f(e.config);return p=r,r}catch{return null}}function u(t){let[e,r]=m(()=>p??L(t)),i=S(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"||p)return!1;let n=E.get(t||"");if(n!==void 0)return n;let l=L(t).hasFlaggedPaths;return E.set(t||"",l),!!l},[t]),[o,s]=m(i);return M(()=>{i&&(h||(h=F()),h.then(n=>{n&&r(a=>a.isEqual(n)?a:n)}).finally(()=>{s(!1)}))},[t,e.applications,i]),{clientConfig:e,isLoading:o}}import{createContext as O,useCallback as w,useRef as T,useMemo as A,useState as H,startTransition as Z}from"react";import{Fragment as I,jsx as x,jsxs as z}from"react/jsx-runtime";var d=O({prefetchHref:()=>{}});function oe({children:t}){let[e,r]=H(new Set),i=T(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome"))),o=w(n=>{Z(()=>{r(a=>a.has(n)?a:new Set(a).add(n))})},[]),s=A(()=>({prefetchHref:o}),[o]);return i.current?z(d.Provider,{value:s,children:[t,[...e].map(n=>x("link",{as:"fetch",href:n,rel:"preload"},n))]}):x(I,{children:t})}import{useEffect as y,useState as D}from"react";import B from"next/script.js";import{jsx as V}from"react/jsx-runtime";var g="data-prefetch",c={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${g}]`},v={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}}]},J={and:[{href_matches:"/*"},{selector_matches:c.anyZone},{not:{selector_matches:c.sameZone}},{not:{selector_matches:c.external}},{selector_matches:c.prefetch}]};function _(t){if(!t)return!0;if("checkVisibility"in t)return t.checkVisibility({opacityProperty:!0});let e=t,r=window.getComputedStyle(e);return r.display==="none"||r.visibility==="hidden"||r.opacity==="0"?!1:_(e.parentElement)}function fe({prerenderEagerness:t="conservative"}){let{isLoading:e}=u(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[r,i]=D([]);return y(()=>{if(e)return;let s=new IntersectionObserver(n=>{n.forEach(a=>{a.isIntersecting&&!a.target.hasAttribute(g)&&_(a.target)&&a.target.setAttribute(g,"true")})},{root:null,rootMargin:"0px",threshold:.1});return r.forEach(n=>s.observe(n)),()=>{s.disconnect()}},[e,r]),y(()=>{if(e)return;let s=new MutationObserver(n=>{n.some(l=>l.type==="childList"&&l.addedNodes.length>0||l.type==="attributes"&&l.attributeName==="href")&&i(Array.from(document.querySelectorAll(`a${c.anyZone}:not(${c.prefetch}):not(${c.sameZone}):not(${c.external})`)))});return s.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{s.disconnect()}},[e]),e?null:V(B,{dangerouslySetInnerHTML:{__html:JSON.stringify({prefetch:[{eagerness:"moderate",where:v},{eagerness:"immediate",where:J}],prerender:[{eagerness:t,where:v}]})},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as R}from"react/jsx-runtime";var q=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION_HASH;function G(t){let{clientConfig:e,isLoading:r}=u(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),{isRelativePath:i,zoneOfHref:o}=X(()=>{let n=typeof t=="string"&&t.startsWith("/");return{isRelativePath:n,zoneOfHref:n?e.getApplicationNameForPath(t):null}},[e,t]);return typeof t=="string"&&!t.length?{zoneOfHref:null,isDifferentZone:!1,isLoading:!1}:{zoneOfHref:o,isDifferentZone:!i||(o?q!==o:!1),isLoading:r}}var K=U(({children:t,...e},r)=>{let{prefetchHref:i}=W(d),{zoneOfHref:o,isDifferentZone:s,isLoading:n}=G(e.href);function a(){e.href&&i(e.href)}if(s&&o!==null){let{prefetch:l,...k}=e;return R("a",{...k,"data-zone":o,onFocus:e.prefetch!==!1?a:void 0,onMouseOver:e.prefetch!==!1?a:void 0,children:t})}return R($,{...e,"data-zone":o?"same":"null",prefetch:e.prefetch??(n?!1:void 0),ref:r,children:t})});K.displayName="MicrofrontendsLink";export{K as Link,fe as PrefetchCrossZoneLinks,d as PrefetchCrossZoneLinksContext,oe as PrefetchCrossZoneLinksProvider,G as useZoneForHref};
//# sourceMappingURL=client.js.map