@fulgurjs/federation 2.0.3 → 3.0.0
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 +42 -0
- package/README.md +80 -25
- package/client.d.ts +49 -2
- package/dist/{chunk-RQPLFDDT.js → chunk-YBS2PO34.js} +1 -1
- package/dist/cli.js +148 -4
- package/dist/index.cjs +509 -61
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +511 -61
- package/dist/runtime.js +3 -3
- package/dist/vue.cjs +98 -30
- package/dist/vue.js +99 -31
- package/package.json +19 -28
package/dist/runtime.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`+
|
|
3
|
-
`),{remote:e.name})}
|
|
1
|
+
var oe=/^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-((?:[0-9A-Za-z-]+)(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.-]+)?$/;function I(o){let i=oe.exec(String(o).trim());return i?{major:Number(i[1]),minor:Number(i[2]??0),patch:Number(i[3]??0),pre:i[4]?i[4].split("."):[]}:null}function ie(o,i){if(o.length===0&&i.length===0)return 0;if(o.length===0)return 1;if(i.length===0)return-1;let s=Math.max(o.length,i.length);for(let n=0;n<s;n++){let f=o[n],y=i[n];if(f===void 0)return-1;if(y===void 0)return 1;let R=/^\d+$/.test(f),w=/^\d+$/.test(y);if(R&&w){let T=Number(f)-Number(y);if(T!==0)return T}else{if(R!==w)return R?-1:1;if(f!==y)return f<y?-1:1}}return 0}function j(o,i){let s=I(o),n=I(i);return!s||!n?o<i?-1:o>i?1:0:s.major!==n.major?s.major-n.major:s.minor!==n.minor?s.minor-n.minor:s.patch!==n.patch?s.patch-n.patch:ie(s.pre,n.pre)}var se=/^[a-z]+[+:-]/i;function P(o,i){if(i===!1||i==null||i==="")return!0;let s=String(i).trim();return!s||s==="*"||s==="latest"||se.test(s)?!0:s.split("||").some(n=>ae(o,n.trim()))}function ae(o,i){if(!i||i==="*")return!I(o)?.pre.length;let s=i.split(/\s+-\s+/);if(s.length===2){let y=s[0].trim(),R=s[1].trim();return!(!P(o,`>=${y}`)||!P(o,`<=${R}`))}let n=I(o);if(!n)return!1;let f=ce(i);if(f===null)return!0;for(let y of f)if(!pe(n,o,y))return!1;return!(n.pre.length>0&&!f.some(y=>y.ver.pre.length>0)&&!f.some(R=>R.ver.major===n.major&&R.ver.minor===n.minor&&R.ver.patch===n.patch))}function ce(o){let i=[],s=o.trim().split(/\s+/).filter(Boolean);if(s.length===0)return null;for(let n of s){let f=/^(>=|<=|>|<|=|\^|~)?(.*)$/.exec(n);if(!f)return null;let y=f[1],R=f[2],w=le(y,R);if(w===null)return null;i.push(...w)}return i}function le(o,i){let s=me(i);if(!s)return null;let{ver:n,partial:f}=s;switch(o){case"^":{let y=ue(n);return y?[{op:">=",ver:n},{op:"<",ver:y}]:null}case"~":{let y=f>=2?{major:n.major,minor:n.minor+1,patch:0,pre:[]}:{major:n.major+1,minor:0,patch:0,pre:[]};return[{op:">=",ver:n},{op:"<",ver:y}]}case">=":return[{op:">=",ver:n}];case">":return f===1?[{op:">=",ver:{major:n.major+1,minor:0,patch:0,pre:[]}}]:f===2?[{op:">=",ver:{major:n.major,minor:n.minor+1,patch:0,pre:[]}}]:[{op:">",ver:n}];case"<":return f===1?[{op:"<",ver:{major:n.major,minor:0,patch:0,pre:[]}}]:f===2?[{op:"<",ver:{major:n.major,minor:n.minor,patch:0,pre:[]}}]:[{op:"<",ver:n}];case"<=":return[{op:"<=",ver:n}];case"=":case void 0:return f===1?[{op:">=",ver:n},{op:"<",ver:{major:n.major+1,minor:0,patch:0,pre:[]}}]:f===2?[{op:">=",ver:n},{op:"<",ver:{major:n.major,minor:n.minor+1,patch:0,pre:[]}}]:[{op:"=",ver:n}];default:return null}}function ue(o){return o.major>0?{major:o.major+1,minor:0,patch:0,pre:[]}:o.minor>0?{major:0,minor:o.minor+1,patch:0,pre:[]}:{major:0,minor:0,patch:o.patch+1,pre:[]}}function me(o){let i=o.replace(/^v/,"").trim();if(!i||i==="*"||i==="x"||i==="X")return{ver:{major:0,minor:0,patch:0,pre:[]},partial:0};let s=i.split("."),n=[],f=0;for(let w of s.slice(0,3))if(/^\d+$/.test(w))n.push(Number(w)),f++;else{if(w==="x"||w==="X"||w==="*")break;break}let y=i.split("-"),R=y.length>1?y.slice(1).join("-").split("+")[0].split("."):[];return f===0&&R.length===0?{ver:{major:0,minor:0,patch:0,pre:[]},partial:0}:{ver:{major:n[0]??0,minor:n[1]??0,patch:n[2]??0,pre:R},partial:f}}function fe(o,i){switch(i){case">=":return o>=0;case">":return o>0;case"<":return o<0;case"<=":return o<=0;case"=":return o===0}}function pe(o,i,s){let n=`${o.major}.${o.minor}.${o.patch}`+(o.pre.length?`-${o.pre.join(".")}`:"");if(s.upper)return!(!(j(n,`${s.ver.major}.${s.ver.minor}.${s.ver.patch}`+(s.ver.pre.length?`-${s.ver.pre.join(".")}`:""))>=0)||!(j(n,`${s.upper.major}.${s.upper.minor}.${s.upper.patch}`)<0));let f=j(n,`${s.ver.major}.${s.ver.minor}.${s.ver.patch}`+(s.ver.pre.length?`-${s.ver.pre.join(".")}`:"")),y=fe(f,s.op);return s.ver.pre.length>0&&o.pre.length===0&&(s.op===">"||s.op==="<")?!1:y}var b=class extends Error{code;details;constructor(i,s,n){super(`[fulgurjs:${i}] ${s}`),this.name="FgError",this.code=i,this.details=n}},S={REMOTE_LOAD_FAILED:"MFU-001",REMOTE_NAME_MISMATCH:"MFU-002",SHARE_STRICT_VERSION:"MFU-003",SHARE_NOT_AVAILABLE:"MFU-004",CONTAINER_REINIT_CONFLICT:"MFU-005",MODULE_NOT_EXPOSED:"MFU-006",PRELOAD_FAILED:"MFU-007",REMOTE_UNKNOWN:"MFU-008",EMPTY_EXPORTS:"MFU-009",SINGLETON_SKEW:"MFU-010"};var q="3.0.0";var x=15e3,z=2,de=5,ge=3e4,he=4e3,ye=.2;function Ee(){let o=Object.create(null),i=new Map,s=[],n=new Map,f=new Map,y=new WeakMap,R=new WeakMap,w={},T=()=>{for(let e of s)try{e.init?.(w)}catch(t){console.warn("[fulgurjs] runtimePlugin init failed:",e.name,t)}},N=e=>o[e]??=Object.create(null);function $(e){try{w.onRemoteError?.(e)}catch{}typeof window<"u"&&window.dispatchEvent(new CustomEvent("fulgurjs:error",{detail:e}))}function B(e="default"){return N(e),o}function J(e,t,r,l,h={}){let a=N(e||"default"),p=Object.hasOwn(a,t)?a[t]:void 0,d=p&&typeof p=="object"?p:void 0;d||(d=Object.create(null),a[t]=d),!(Object.hasOwn(d,r)&&d[r])&&(d[r]={version:r,get:l,from:h.from??"unknown",eager:!!h.eager,loaded:!!h.loaded})}function G(e){let t=(r,l,h)=>{if(r===void 0)return;if(!(typeof r=="number"&&(h?Number.isInteger(r)&&r>=0&&r<=10:Number.isFinite(r)&&r>0)))throw new Error(`[fulgurjs] registerRemote("${e.name}"): ${l} must be a ${h?"integer 0..10":"finite positive number"}, got ${String(r)}`)};t(e.timeout,"timeout"),t(e.retries,"retries",!0),e.breaker&&(t(e.breaker.threshold,"breaker.threshold"),t(e.breaker.resetMs,"breaker.resetMs"))}function F(e){for(let t of e){G(t);let r=i.get(t.name);i.set(t.name,{timeout:x,retries:z,...r,...t,breakerThreshold:t.breaker?.threshold??r?.breakerThreshold??de,breakerResetMs:t.breaker?.resetMs??r?.breakerResetMs??ge,state:r?.state??"idle",breakerState:r?.breakerState??{fails:0,openUntil:0},entryInflight:r?.entryInflight??new Map,debug:r?.debug??{entry:t.entry,status:"idle"}})}}function X(e){F([e])}function Y(e){s.push(...e),T()}async function Z(e,t={}){let r=t.shareScope||"default",l=t.shareKey||e,a=N(r)[l]||{},p=Object.keys(a),d=t.requiredVersion,g=p.filter(c=>d===void 0||d===!1||P(c,d)),m;if(t.singleton&&p.length>0){let c=p.filter(u=>a[u].loaded);if(m=[...c.length?c:p].sort(j).pop(),p.length>1||!g.includes(m)){let u=a[m],k=`singleton skew "${l}": req "${d??"any"}" use ${m} from ${u.from}`;if(t.strictVersion){let v=new b(S.SHARE_STRICT_VERSION,k,{shareKey:l,requiredVersion:d});throw $({remote:u.from,error:v}),v}console.warn(`[fulgurjs:MFU-010] ${k}`)}}else if(m=[...g].sort(j).pop(),!m){if(t.strictVersion){let u=new b(S.SHARE_STRICT_VERSION,`no satisfying version for "${l}" (required "${d}") in share scope "${r}"`);throw $({remote:l,error:u}),u}if(t.fallback)return t.fallback();let c=new b(S.SHARE_NOT_AVAILABLE,`shared "${l}" (${d??"any"}) unavailable in scope "${r}" (no local fallback)`,{shareKey:l,requiredVersion:d});throw $({remote:l,error:c}),c}let E=a[m];if(w.resolveShare){let c=await w.resolveShare({shareKey:l,shareScope:r,requiredVersion:d,picked:E,available:Object.values(a)});c&&(E=c)}return E.loaded=!0,E.get()}function Q(e){try{let t=new URL(e,typeof location<"u"?location.href:"http://f.invalid");return t.protocol+"//"+t.host+t.pathname}catch{return String(e).replace(/[?#].*$/,"")}}function C(e,t,r){return new Promise((l,h)=>{let a=setTimeout(()=>h(new Error(`timeout after ${t}ms: ${r}`)),t);e.then(p=>{clearTimeout(a),l(p)},p=>{clearTimeout(a),h(p)})})}let ee=e=>new Promise(t=>setTimeout(t,e));function A(e,t){if(!e||typeof e.get!="function")throw new Error(`remoteEntry of "${t.name}" does not export a container interface (get/init)`);if(e.name&&t.name&&e.name!==t.name){let r=`remoteEntry self-reported name "${e.name}" mismatches configured name "${t.name}"`;if(t.promise)console.warn(`[fulgurjs] ${r} (promise-based remote, continuing)`);else throw Object.assign(new Error(r),{code:S.REMOTE_NAME_MISMATCH})}}async function D(e,t){let r=t.entryInflight.get(e),l=r??import(e);return r||(t.entryInflight.set(e,l),l.catch(()=>t.entryInflight.delete(e))),C(l,t.timeout??x,`load remoteEntry ${e}`)}async function V(e,t){let r=e.shareScope||"default";if(e.container){let a=R.get(e.container);if(a&&a!==r)throw new b(S.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${a}", cannot re-init with "${r}"`);return e.container}if(e.containerPromise)return e.containerPromise;let l=e.breakerState;if(l.openUntil>Date.now()){let a=new b(S.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(l.openUntil).toISOString()}`,{remote:e.name});throw $({remote:e.name,error:a}),a}e.state="loading",e.debug.status="loading";let h=(async()=>{let a=[];if(e.promise)a.push(async()=>{let c=await C(e.promise(),e.timeout??x,`resolve promise remote "${e.name}"`),u=typeof c=="string"?await D(c,e):c;return A(u,e),u});else for(let c of[e.entry,...e.fallback??[]])a.push(async()=>{let u=await D(c,e);return A(u,e),u});let p,d,g=!1,m=t?.retries??e.retries??z;for(let c of a){for(let u=0;u<=m;u++){let k=performance.now();try{p=await c(),e.lastLoadMs=Math.round(performance.now()-k),e.debug.lastLoadMs=e.lastLoadMs,g=!0;break}catch(v){if(d=v,v?.code)throw v;u<m&&await ee(Math.min(he,200*2**u)*(1-ye*(1-2*Math.random())))}}if(g)break}if(!g||!p){let c=Q(e.entry),u=[];throw/^https?:\/\//.test(e.entry)&&typeof location<"u"?(u.push(`1. is the remote dev server running? open ${c} in a browser \u2014 it must return JS, not HTML`),u.push("2. is the URL correct in federation({ remotes })? dev/prod entries can differ"),u.push("3. CORS: the remote dev server must allow cross-origin requests (check its server.cors)")):(u.push(`1. is the remote deployed? open ${c} in a browser \u2014 it must return JS`),u.push("2. NGINX/CDN routing: the entry path must serve the remoteEntry JS (check try_files)")),new b(S.REMOTE_LOAD_FAILED,`failed to load remote "${e.name}" from ${c}: ${String(d?.message??d)}
|
|
2
|
+
`+u.join(`
|
|
3
|
+
`),{remote:e.name})}A(p,e);let E=R.get(p);if(E&&E!==r)throw new b(S.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${E}", cannot re-init with "${r}"`);return typeof p.init=="function"&&await p.init(o),R.set(p,r),e.container=p,e.state="loaded",e.debug.status="loaded",l.fails=0,p})();e.containerPromise=h;try{return await h}catch(a){if(e.containerPromise=void 0,e.state="failed",e.debug.status="failed",e.debug.error=String(a?.message??a),l.fails+=1,l.fails>=e.breakerThreshold&&(l.openUntil=Date.now()+e.breakerResetMs,l.fails=0),a instanceof b)throw $({remote:e.name,error:a}),a;if(a?.code)throw $({remote:e.name,error:a}),a;let p=new b(S.REMOTE_LOAD_FAILED,String(a?.message??a),{remote:e.name});throw $({remote:e.name,error:p}),p}}function U(e){let t=e.indexOf("/");return t===-1?{remote:e,module:""}:{remote:e.slice(0,t),module:H(e.slice(t+1))}}function H(e){return e?e.startsWith(".")?e:`./${e}`:""}async function re(e,t){let{remote:r,module:l}=U(e);try{w.beforeLoadRemote?.({remote:r,module:l})}catch(g){console.warn("[fulgurjs] beforeLoadRemote hook error (ignored):",g)}let h=i.get(r);if(!h)throw new b(S.REMOTE_UNKNOWN,`unknown remote "${r}". Register it via federation({ remotes }) or registerRemote().`,{remote:r});let a;try{let g=l&&h.manifestUrl?K(e):Promise.resolve();[a]=await Promise.all([V(h,{retries:t?.retries}),g])}catch(g){if(t?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\u663E\u5F0F\u964D\u7EA7\uFF0C\u9519\u8BEF\u5DF2\u900F\u51FA)`,g),$({remote:r,error:g}),await t.fallbackModule();throw g}if(!l)return a;let p=`${r}@${h.shareScope||"default"}#${l}`;n.has(p)||n.set(p,a.get(l).catch(g=>{throw n.delete(p),g instanceof b||g?.code?g:new b(S.REMOTE_LOAD_FAILED,`failed to load module "${l}" from remote "${r}": ${String(g?.message??g)}`,{remote:r,module:l})}));let d;try{d=await n.get(p)}catch(g){if(t?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\u663E\u5F0F\u964D\u7EA7\uFF0C\u9519\u8BEF\u5DF2\u900F\u51FA)`,g),$({remote:r,error:g}),await t.fallbackModule();throw g}try{w.afterLoadRemote?.({remote:r,module:l,module_ns:d})}catch(g){console.warn("[fulgurjs] afterLoadRemote hook error (ignored):",g)}if(d&&typeof d=="object"&&Object.keys(d).length===0){let g=new b(S.EMPTY_EXPORTS,`no exports: ${l} @ ${r}`,{remote:r,module:l});$({remote:r,error:g}),console.error(`[fulgurjs:MFU-009] ${g.message}`)}return d}function te(e){let t=i.get(e);if(!t)throw new b(S.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return V(t)}async function K(e,t={}){let{remote:r,module:l}=U(e),h=i.get(r);if(!h)throw new b(S.REMOTE_UNKNOWN,`unknown remote "${r}"`,{remote:r});let a=t.mode??"preload",p=(m,E)=>{if(m.sheet)return Promise.resolve();let c=y.get(m);if(c)return c;let u=new Promise(k=>{let v=()=>{m.removeEventListener("load",v),m.removeEventListener("error",O),k()},O=()=>{$({remote:r,error:new b(S.PRELOAD_FAILED,`failed to load remote stylesheet ${E}`,{remote:r})}),v()};m.addEventListener("load",v,{once:!0}),m.addEventListener("error",O,{once:!0}),m.sheet&&v()});return y.set(m,u),u},d=(m,E)=>{if(typeof document>"u")return Promise.resolve();let c=document.querySelector(`link[href="${m}"]`);if(c)return E==="style"&&a==="preload"?y.get(c)??Promise.resolve():Promise.resolve();let u=document.createElement("link");u.rel=E==="style"?"stylesheet":"modulepreload",u.href=m,a==="prefetch"&&(u.fetchPriority="low");let k=E==="style"?p(u,m):Promise.resolve();return document.head.appendChild(u),E==="style"&&a==="preload"?k:Promise.resolve()},g=m=>{let E=typeof document<"u"?document.baseURI:void 0,c=new URL(h.entry,E||"http://fulgurjs.invalid/");return!c.pathname.endsWith("/")&&!c.pathname.split("/").pop().includes(".")&&(c.pathname+="/"),new URL(m,c).href};try{if(h.manifestUrl){let m=f.get(h.manifestUrl);m||(m=fetch(h.manifestUrl,{cache:"no-cache",signal:AbortSignal.timeout(8e3)}).then(c=>c.ok?c.json():void 0),f.set(h.manifestUrl,m),m.then(c=>{c||f.delete(h.manifestUrl)},()=>f.delete(h.manifestUrl)));let E=await m;if(E){let c=E.schemaVersion;if(typeof c=="number"&&(!Number.isInteger(c)||c>1)){$({remote:r,error:new b(S.PRELOAD_FAILED,`unsupported manifest schemaVersion ${String(c)} (expected 1)`,{remote:r})}),await d(h.entry,"modulepreload");return}await d(h.entry,"modulepreload");let u=E.exposes,k=Array.isArray(u)?u.filter(_=>_&&typeof _=="object").map(_=>[String(_.name??""),_]):u&&typeof u=="object"?Object.entries(u):[],v=l?k.filter(([_,L])=>H(String(L?.name??_))===l):k,O=[];for(let[,_]of v)if(typeof _?.file=="string"&&await d(g(_.file),"modulepreload"),Array.isArray(_?.css))for(let L of _.css){if(typeof L!="string")continue;let ne=d(g(L),"style");a==="preload"&&O.push(ne)}await Promise.all(O);return}}await d(h.entry,"modulepreload")}catch(m){$({remote:r,error:new b(S.PRELOAD_FAILED,String(m?.message??m),{remote:r})})}}return typeof window>"u"||(window.__FULGURJS_SCOPE__=o,window.__FULGURJS_INFO__={get remotes(){let e={};for(let[t,r]of i)e[t]={...r.debug,entry:r.entry};return e},errors:[]}),{shareScopeMap:o,initSharing:B,registerShare:J,registerRemotes:F,registerRemote:X,registerPlugins:Y,loadShare:Z,loadRemote:re,getContainer:te,preloadRemote:K,parseSpec:U}}var W=globalThis,M=W.__FULGURJS_RUNTIME__??Ee();W.__FULGURJS_RUNTIME__=M;try{Object.freeze(M)}catch{}var _e=q;function ke(){return M}var je=M.initSharing,Oe=M.registerShare,Te=M.registerRemotes,Le=M.registerRemote,Ie=M.registerPlugins,Pe=M.loadShare,Ne=M.loadRemote,Ae=M.getContainer,Ue=M.preloadRemote,xe=M.parseSpec,Fe=M.shareScopeMap;function Ce(o){if(o&&typeof o=="object"&&"default"in o){let i=o.default;return i!==void 0?i:o}return o}var De=M;export{De as default,Ae as getContainer,ke as getRuntime,je as initSharing,Ne as loadRemote,Pe as loadShare,xe as parseSpec,Ue as preloadRemote,Ie as registerPlugins,Le as registerRemote,Te as registerRemotes,Oe as registerShare,M as runtime,Fe as shareScopeMap,Ce as unwrapDefault,_e as version};
|
package/dist/vue.cjs
CHANGED
|
@@ -262,8 +262,10 @@ var DEFAULT_TIMEOUT = 15e3;
|
|
|
262
262
|
var DEFAULT_RETRIES = 2;
|
|
263
263
|
var BREAKER_THRESHOLD = 5;
|
|
264
264
|
var BREAKER_RESET_MS = 3e4;
|
|
265
|
+
var BACKOFF_MAX_MS = 4e3;
|
|
266
|
+
var BACKOFF_JITTER = 0.2;
|
|
265
267
|
function createRuntime() {
|
|
266
|
-
const shareScopeMap2 =
|
|
268
|
+
const shareScopeMap2 = /* @__PURE__ */ Object.create(null);
|
|
267
269
|
const remotes = /* @__PURE__ */ new Map();
|
|
268
270
|
const plugins = [];
|
|
269
271
|
const loadedModules = /* @__PURE__ */ new Map();
|
|
@@ -280,7 +282,7 @@ function createRuntime() {
|
|
|
280
282
|
}
|
|
281
283
|
}
|
|
282
284
|
};
|
|
283
|
-
const getScope = (name) => shareScopeMap2[name] ??=
|
|
285
|
+
const getScope = (name) => shareScopeMap2[name] ??= /* @__PURE__ */ Object.create(null);
|
|
284
286
|
function emitError(info) {
|
|
285
287
|
try {
|
|
286
288
|
hooks.onRemoteError?.(info);
|
|
@@ -296,22 +298,49 @@ function createRuntime() {
|
|
|
296
298
|
}
|
|
297
299
|
function registerShare2(scopeName, name, version, get, opts = {}) {
|
|
298
300
|
const scope = getScope(scopeName || "default");
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
+
const own = Object.hasOwn(scope, name) ? scope[name] : void 0;
|
|
302
|
+
let byName = own && typeof own === "object" ? own : void 0;
|
|
303
|
+
if (!byName) {
|
|
304
|
+
byName = /* @__PURE__ */ Object.create(null);
|
|
305
|
+
scope[name] = byName;
|
|
306
|
+
}
|
|
307
|
+
if (Object.hasOwn(byName, version) && byName[version]) {
|
|
301
308
|
return;
|
|
302
309
|
}
|
|
303
310
|
byName[version] = { version, get, from: opts.from ?? "unknown", eager: !!opts.eager, loaded: !!opts.loaded };
|
|
304
311
|
}
|
|
312
|
+
function assertRemoteParams(r) {
|
|
313
|
+
const check = (v, name, int10) => {
|
|
314
|
+
if (v === void 0) return;
|
|
315
|
+
const ok = typeof v === "number" && (int10 ? Number.isInteger(v) && v >= 0 && v <= 10 : Number.isFinite(v) && v > 0);
|
|
316
|
+
if (!ok) {
|
|
317
|
+
throw new Error(
|
|
318
|
+
`[fulgurjs] registerRemote("${r.name}"): ${name} must be a ${int10 ? "integer 0..10" : "finite positive number"}, got ${String(v)}`
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
check(r.timeout, "timeout");
|
|
323
|
+
check(r.retries, "retries", true);
|
|
324
|
+
if (r.breaker) {
|
|
325
|
+
check(r.breaker.threshold, "breaker.threshold");
|
|
326
|
+
check(r.breaker.resetMs, "breaker.resetMs");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
305
329
|
function registerRemotes2(list) {
|
|
306
330
|
for (const r of list) {
|
|
331
|
+
assertRemoteParams(r);
|
|
307
332
|
const prev = remotes.get(r.name);
|
|
308
333
|
remotes.set(r.name, {
|
|
309
334
|
timeout: DEFAULT_TIMEOUT,
|
|
310
335
|
retries: DEFAULT_RETRIES,
|
|
311
336
|
...prev,
|
|
312
337
|
...r,
|
|
338
|
+
// 熔断参数随最新配置刷新;计数状态(fails/openUntil)跨注册保留——半开窗口不被重置
|
|
339
|
+
breakerThreshold: r.breaker?.threshold ?? prev?.breakerThreshold ?? BREAKER_THRESHOLD,
|
|
340
|
+
breakerResetMs: r.breaker?.resetMs ?? prev?.breakerResetMs ?? BREAKER_RESET_MS,
|
|
313
341
|
state: prev?.state ?? "idle",
|
|
314
342
|
breakerState: prev?.breakerState ?? { fails: 0, openUntil: 0 },
|
|
343
|
+
entryInflight: prev?.entryInflight ?? /* @__PURE__ */ new Map(),
|
|
315
344
|
debug: prev?.debug ?? { entry: r.entry, status: "idle" }
|
|
316
345
|
});
|
|
317
346
|
}
|
|
@@ -385,6 +414,14 @@ function createRuntime() {
|
|
|
385
414
|
entry.loaded = true;
|
|
386
415
|
return entry.get();
|
|
387
416
|
}
|
|
417
|
+
function sanitizeUrl(u) {
|
|
418
|
+
try {
|
|
419
|
+
const x = new URL(u, typeof location < "u" ? location.href : "http://f.invalid");
|
|
420
|
+
return x.protocol + "//" + x.host + x.pathname;
|
|
421
|
+
} catch {
|
|
422
|
+
return String(u).replace(/[?#].*$/, "");
|
|
423
|
+
}
|
|
424
|
+
}
|
|
388
425
|
function withTimeout(p, ms, label) {
|
|
389
426
|
return new Promise((resolve, reject) => {
|
|
390
427
|
const t = setTimeout(() => reject(new Error(`timeout after ${ms}ms: ${label}`)), ms);
|
|
@@ -417,14 +454,16 @@ function createRuntime() {
|
|
|
417
454
|
}
|
|
418
455
|
}
|
|
419
456
|
async function importEntry(url, remote) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
),
|
|
425
|
-
remote.timeout ?? DEFAULT_TIMEOUT,
|
|
426
|
-
`load remoteEntry ${url}`
|
|
457
|
+
const cached = remote.entryInflight.get(url);
|
|
458
|
+
const inflight = cached ?? import(
|
|
459
|
+
/* @vite-ignore */
|
|
460
|
+
url
|
|
427
461
|
);
|
|
462
|
+
if (!cached) {
|
|
463
|
+
remote.entryInflight.set(url, inflight);
|
|
464
|
+
inflight.catch(() => remote.entryInflight.delete(url));
|
|
465
|
+
}
|
|
466
|
+
return withTimeout(inflight, remote.timeout ?? DEFAULT_TIMEOUT, `load remoteEntry ${url}`);
|
|
428
467
|
}
|
|
429
468
|
async function acquireContainer(remote, overrides) {
|
|
430
469
|
const scopeKey = remote.shareScope || "default";
|
|
@@ -455,7 +494,11 @@ function createRuntime() {
|
|
|
455
494
|
const loaders = [];
|
|
456
495
|
if (remote.promise) {
|
|
457
496
|
loaders.push(async () => {
|
|
458
|
-
const resolved = await
|
|
497
|
+
const resolved = await withTimeout(
|
|
498
|
+
remote.promise(),
|
|
499
|
+
remote.timeout ?? DEFAULT_TIMEOUT,
|
|
500
|
+
`resolve promise remote "${remote.name}"`
|
|
501
|
+
);
|
|
459
502
|
const container2 = typeof resolved === "string" ? await importEntry(resolved, remote) : resolved;
|
|
460
503
|
validateContainerInterface(container2, remote);
|
|
461
504
|
return container2;
|
|
@@ -486,25 +529,26 @@ function createRuntime() {
|
|
|
486
529
|
lastErr = err;
|
|
487
530
|
if (err?.code) throw err;
|
|
488
531
|
if (attempt < maxRetries) {
|
|
489
|
-
await sleep(200 * 2 ** attempt);
|
|
532
|
+
await sleep(Math.min(BACKOFF_MAX_MS, 200 * 2 ** attempt) * (1 - BACKOFF_JITTER * (1 - 2 * Math.random())));
|
|
490
533
|
}
|
|
491
534
|
}
|
|
492
535
|
}
|
|
493
536
|
if (succeeded) break;
|
|
494
537
|
}
|
|
495
538
|
if (!succeeded || !container) {
|
|
539
|
+
const shown = sanitizeUrl(remote.entry);
|
|
496
540
|
const hints = [];
|
|
497
541
|
if (/^https?:\/\//.test(remote.entry) && typeof location !== "undefined") {
|
|
498
|
-
hints.push(`1. is the remote dev server running?
|
|
499
|
-
hints.push(`2. is the URL correct in federation({ remotes })? dev
|
|
500
|
-
hints.push(`3. CORS: the remote dev server must allow cross-origin requests (
|
|
542
|
+
hints.push(`1. is the remote dev server running? open ${shown} in a browser \u2014 it must return JS, not HTML`);
|
|
543
|
+
hints.push(`2. is the URL correct in federation({ remotes })? dev/prod entries can differ`);
|
|
544
|
+
hints.push(`3. CORS: the remote dev server must allow cross-origin requests (check its server.cors)`);
|
|
501
545
|
} else {
|
|
502
|
-
hints.push(`1. is the remote deployed
|
|
503
|
-
hints.push(`2. NGINX/CDN routing: the entry path must serve the remoteEntry JS
|
|
546
|
+
hints.push(`1. is the remote deployed? open ${shown} in a browser \u2014 it must return JS`);
|
|
547
|
+
hints.push(`2. NGINX/CDN routing: the entry path must serve the remoteEntry JS (check try_files)`);
|
|
504
548
|
}
|
|
505
549
|
throw new FgError(
|
|
506
550
|
ErrorCodes.REMOTE_LOAD_FAILED,
|
|
507
|
-
`failed to load remote "${remote.name}" from ${
|
|
551
|
+
`failed to load remote "${remote.name}" from ${shown}: ${String(lastErr?.message ?? lastErr)}
|
|
508
552
|
` + hints.join("\n"),
|
|
509
553
|
{ remote: remote.name }
|
|
510
554
|
);
|
|
@@ -536,8 +580,8 @@ function createRuntime() {
|
|
|
536
580
|
remote.debug.status = "failed";
|
|
537
581
|
remote.debug.error = String(err?.message ?? err);
|
|
538
582
|
b.fails += 1;
|
|
539
|
-
if (b.fails >=
|
|
540
|
-
b.openUntil = Date.now() +
|
|
583
|
+
if (b.fails >= remote.breakerThreshold) {
|
|
584
|
+
b.openUntil = Date.now() + remote.breakerResetMs;
|
|
541
585
|
b.fails = 0;
|
|
542
586
|
}
|
|
543
587
|
if (err instanceof FgError) {
|
|
@@ -555,7 +599,7 @@ function createRuntime() {
|
|
|
555
599
|
throw wrapped;
|
|
556
600
|
}
|
|
557
601
|
}
|
|
558
|
-
function
|
|
602
|
+
function parseSpec2(spec) {
|
|
559
603
|
const idx = spec.indexOf("/");
|
|
560
604
|
if (idx === -1) return { remote: spec, module: "" };
|
|
561
605
|
return { remote: spec.slice(0, idx), module: normalizeModuleName(spec.slice(idx + 1)) };
|
|
@@ -565,8 +609,12 @@ function createRuntime() {
|
|
|
565
609
|
return m.startsWith(".") ? m : `./${m}`;
|
|
566
610
|
}
|
|
567
611
|
async function loadRemote2(spec, opts) {
|
|
568
|
-
const { remote: name, module: module2 } =
|
|
569
|
-
|
|
612
|
+
const { remote: name, module: module2 } = parseSpec2(spec);
|
|
613
|
+
try {
|
|
614
|
+
hooks.beforeLoadRemote?.({ remote: name, module: module2 });
|
|
615
|
+
} catch (hookErr) {
|
|
616
|
+
console.warn("[fulgurjs] beforeLoadRemote hook error (ignored):", hookErr);
|
|
617
|
+
}
|
|
570
618
|
const remote = remotes.get(name);
|
|
571
619
|
if (!remote) {
|
|
572
620
|
throw new FgError(
|
|
@@ -614,7 +662,11 @@ function createRuntime() {
|
|
|
614
662
|
}
|
|
615
663
|
throw err;
|
|
616
664
|
}
|
|
617
|
-
|
|
665
|
+
try {
|
|
666
|
+
hooks.afterLoadRemote?.({ remote: name, module: module2, module_ns: ns });
|
|
667
|
+
} catch (hookErr) {
|
|
668
|
+
console.warn("[fulgurjs] afterLoadRemote hook error (ignored):", hookErr);
|
|
669
|
+
}
|
|
618
670
|
if (ns && typeof ns === "object" && Object.keys(ns).length === 0) {
|
|
619
671
|
const err = new FgError(
|
|
620
672
|
ErrorCodes.EMPTY_EXPORTS,
|
|
@@ -634,7 +686,7 @@ function createRuntime() {
|
|
|
634
686
|
return acquireContainer(remote);
|
|
635
687
|
}
|
|
636
688
|
async function preloadRemote2(spec, opts = {}) {
|
|
637
|
-
const { remote: name, module: module2 } =
|
|
689
|
+
const { remote: name, module: module2 } = parseSpec2(spec);
|
|
638
690
|
const remote = remotes.get(name);
|
|
639
691
|
if (!remote) {
|
|
640
692
|
throw new FgError(ErrorCodes.REMOTE_UNKNOWN, `unknown remote "${name}"`, { remote: name });
|
|
@@ -686,15 +738,19 @@ function createRuntime() {
|
|
|
686
738
|
const resolveAssetUrl = (asset) => {
|
|
687
739
|
const pageUrl = typeof document !== "undefined" ? document.baseURI : void 0;
|
|
688
740
|
const base = new URL(remote.entry, pageUrl || "http://fulgurjs.invalid/");
|
|
741
|
+
if (!base.pathname.endsWith("/") && !base.pathname.split("/").pop().includes(".")) {
|
|
742
|
+
base.pathname += "/";
|
|
743
|
+
}
|
|
689
744
|
return new URL(asset, base).href;
|
|
690
745
|
};
|
|
691
746
|
try {
|
|
692
747
|
if (remote.manifestUrl) {
|
|
693
748
|
let manifestPromise = remoteManifests.get(remote.manifestUrl);
|
|
694
749
|
if (!manifestPromise) {
|
|
695
|
-
manifestPromise = fetch(remote.manifestUrl, {
|
|
696
|
-
|
|
697
|
-
|
|
750
|
+
manifestPromise = fetch(remote.manifestUrl, {
|
|
751
|
+
cache: "no-cache",
|
|
752
|
+
signal: AbortSignal.timeout(8e3)
|
|
753
|
+
}).then((res) => res.ok ? res.json() : void 0);
|
|
698
754
|
remoteManifests.set(remote.manifestUrl, manifestPromise);
|
|
699
755
|
manifestPromise.then(
|
|
700
756
|
(manifest2) => {
|
|
@@ -705,6 +761,17 @@ function createRuntime() {
|
|
|
705
761
|
}
|
|
706
762
|
const manifest = await manifestPromise;
|
|
707
763
|
if (manifest) {
|
|
764
|
+
const sv = manifest.schemaVersion;
|
|
765
|
+
if (typeof sv === "number" && (!Number.isInteger(sv) || sv > 1)) {
|
|
766
|
+
emitError({
|
|
767
|
+
remote: name,
|
|
768
|
+
error: new FgError(ErrorCodes.PRELOAD_FAILED, `unsupported manifest schemaVersion ${String(sv)} (expected 1)`, {
|
|
769
|
+
remote: name
|
|
770
|
+
})
|
|
771
|
+
});
|
|
772
|
+
await inject(remote.entry, "modulepreload");
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
708
775
|
await inject(remote.entry, "modulepreload");
|
|
709
776
|
const exposes = manifest.exposes;
|
|
710
777
|
const entries = Array.isArray(exposes) ? exposes.filter((item) => item && typeof item === "object").map((item) => [String(item.name ?? ""), item]) : exposes && typeof exposes === "object" ? Object.entries(exposes) : [];
|
|
@@ -762,7 +829,7 @@ function createRuntime() {
|
|
|
762
829
|
loadRemote: loadRemote2,
|
|
763
830
|
getContainer: getContainer2,
|
|
764
831
|
preloadRemote: preloadRemote2,
|
|
765
|
-
parseSpec
|
|
832
|
+
parseSpec: parseSpec2
|
|
766
833
|
};
|
|
767
834
|
}
|
|
768
835
|
var g = globalThis;
|
|
@@ -781,6 +848,7 @@ var loadShare = runtime.loadShare;
|
|
|
781
848
|
var loadRemote = runtime.loadRemote;
|
|
782
849
|
var getContainer = runtime.getContainer;
|
|
783
850
|
var preloadRemote = runtime.preloadRemote;
|
|
851
|
+
var parseSpec = runtime.parseSpec;
|
|
784
852
|
var shareScopeMap = runtime.shareScopeMap;
|
|
785
853
|
|
|
786
854
|
// src/vue.ts
|