@fulgurjs/federation 2.0.1 → 2.0.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 +60 -0
- package/README.md +11 -6
- package/dist/{chunk-I5FNKR7E.js → chunk-RQPLFDDT.js} +1 -1
- package/dist/index.cjs +245 -53
- package/dist/index.js +245 -53
- package/dist/runtime.js +3 -3
- package/dist/vue.cjs +76 -14
- package/dist/vue.js +77 -15
- package/docs/P5-vite7-8/345/205/274/345/256/271/347/237/251/351/230/265.md +4 -2
- package/package.json +1 -1
package/dist/runtime.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`+
|
|
3
|
-
`),{remote:e.name})}k(
|
|
1
|
+
var re=/^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-((?:[0-9A-Za-z-]+)(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.-]+)?$/;function P(t){let n=re.exec(String(t).trim());return n?{major:Number(n[1]),minor:Number(n[2]??0),patch:Number(n[3]??0),pre:n[4]?n[4].split("."):[]}:null}function te(t,n){if(t.length===0&&n.length===0)return 0;if(t.length===0)return 1;if(n.length===0)return-1;let o=Math.max(t.length,n.length);for(let r=0;r<o;r++){let m=t[r],d=n[r];if(m===void 0)return-1;if(d===void 0)return 1;let S=/^\d+$/.test(m),w=/^\d+$/.test(d);if(S&&w){let L=Number(m)-Number(d);if(L!==0)return L}else{if(S!==w)return S?-1:1;if(m!==d)return m<d?-1:1}}return 0}function T(t,n){let o=P(t),r=P(n);return!o||!r?t<n?-1:t>n?1:0:o.major!==r.major?o.major-r.major:o.minor!==r.minor?o.minor-r.minor:o.patch!==r.patch?o.patch-r.patch:te(o.pre,r.pre)}var ne=/^[a-z]+[+:-]/i;function N(t,n){if(n===!1||n==null||n==="")return!0;let o=String(n).trim();return!o||o==="*"||o==="latest"||ne.test(o)?!0:o.split("||").some(r=>oe(t,r.trim()))}function oe(t,n){if(!n||n==="*")return!P(t)?.pre.length;let o=n.split(/\s+-\s+/);if(o.length===2){let d=o[0].trim(),S=o[1].trim();return!(!N(t,`>=${d}`)||!N(t,`<=${S}`))}let r=P(t);if(!r)return!1;let m=ie(n);if(m===null)return!0;for(let d of m)if(!ue(r,t,d))return!1;return!(r.pre.length>0&&!m.some(d=>d.ver.pre.length>0)&&!m.some(S=>S.ver.major===r.major&&S.ver.minor===r.minor&&S.ver.patch===r.patch))}function ie(t){let n=[],o=t.trim().split(/\s+/).filter(Boolean);if(o.length===0)return null;for(let r of o){let m=/^(>=|<=|>|<|=|\^|~)?(.*)$/.exec(r);if(!m)return null;let d=m[1],S=m[2],w=se(d,S);if(w===null)return null;n.push(...w)}return n}function se(t,n){let o=ce(n);if(!o)return null;let{ver:r,partial:m}=o;switch(t){case"^":{let d=ae(r);return d?[{op:">=",ver:r},{op:"<",ver:d}]:null}case"~":{let d=m>=2?{major:r.major,minor:r.minor+1,patch:0,pre:[]}:{major:r.major+1,minor:0,patch:0,pre:[]};return[{op:">=",ver:r},{op:"<",ver:d}]}case">=":return[{op:">=",ver:r}];case">":return m===1?[{op:">=",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:m===2?[{op:">=",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:">",ver:r}];case"<":return m===1?[{op:"<",ver:{major:r.major,minor:0,patch:0,pre:[]}}]:m===2?[{op:"<",ver:{major:r.major,minor:r.minor,patch:0,pre:[]}}]:[{op:"<",ver:r}];case"<=":return[{op:"<=",ver:r}];case"=":case void 0:return m===1?[{op:">=",ver:r},{op:"<",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:m===2?[{op:">=",ver:r},{op:"<",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:"=",ver:r}];default:return null}}function ae(t){return t.major>0?{major:t.major+1,minor:0,patch:0,pre:[]}:t.minor>0?{major:0,minor:t.minor+1,patch:0,pre:[]}:{major:0,minor:0,patch:t.patch+1,pre:[]}}function ce(t){let n=t.replace(/^v/,"").trim();if(!n||n==="*"||n==="x"||n==="X")return{ver:{major:0,minor:0,patch:0,pre:[]},partial:0};let o=n.split("."),r=[],m=0;for(let w of o.slice(0,3))if(/^\d+$/.test(w))r.push(Number(w)),m++;else{if(w==="x"||w==="X"||w==="*")break;break}let d=n.split("-"),S=d.length>1?d.slice(1).join("-").split("+")[0].split("."):[];return m===0&&S.length===0?{ver:{major:0,minor:0,patch:0,pre:[]},partial:0}:{ver:{major:r[0]??0,minor:r[1]??0,patch:r[2]??0,pre:S},partial:m}}function le(t,n){switch(n){case">=":return t>=0;case">":return t>0;case"<":return t<0;case"<=":return t<=0;case"=":return t===0}}function ue(t,n,o){let r=`${t.major}.${t.minor}.${t.patch}`+(t.pre.length?`-${t.pre.join(".")}`:"");if(o.upper)return!(!(T(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:""))>=0)||!(T(r,`${o.upper.major}.${o.upper.minor}.${o.upper.patch}`)<0));let m=T(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:"")),d=le(m,o.op);return o.ver.pre.length>0&&t.pre.length===0&&(o.op===">"||o.op==="<")?!1:d}var R=class extends Error{code;details;constructor(n,o,r){super(`[fulgurjs:${n}] ${o}`),this.name="FgError",this.code=n,this.details=r}},b={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 V="2.0.3";var H=15e3,K=2,me=5,fe=3e4;function pe(){let t={},n=new Map,o=[],r=new Map,m=new Map,d=new WeakMap,S=new WeakMap,w={},L=()=>{for(let e of o)try{e.init?.(w)}catch(i){console.warn("[fulgurjs] runtimePlugin init failed:",e.name,i)}},I=e=>t[e]??={};function $(e){try{w.onRemoteError?.(e)}catch{}typeof window<"u"&&window.dispatchEvent(new CustomEvent("fulgurjs:error",{detail:e}))}function z(e="default"){return I(e),t}function W(e,i,s,l,h={}){let c=I(e||"default"),f=c[i]??={};f[s]||(f[s]={version:s,get:l,from:h.from??"unknown",eager:!!h.eager,loaded:!!h.loaded})}function A(e){for(let i of e){let s=n.get(i.name);n.set(i.name,{timeout:H,retries:K,...s,...i,state:s?.state??"idle",breakerState:s?.breakerState??{fails:0,openUntil:0},debug:s?.debug??{entry:i.entry,status:"idle"}})}}function G(e){A([e])}function J(e){o.push(...e),L()}async function B(e,i={}){let s=i.shareScope||"default",l=i.shareKey||e,c=I(s)[l]||{},f=Object.keys(c),y=i.requiredVersion,g=f.filter(a=>y===void 0||y===!1||N(a,y)),u;if(i.singleton&&f.length>0){let a=f.filter(p=>c[p].loaded);if(u=[...a.length?a:f].sort(T).pop(),f.length>1||!g.includes(u)){let p=c[u],j=`singleton skew "${l}": req "${y??"any"}" use ${u} from ${p.from}`;if(i.strictVersion){let _=new R(b.SHARE_STRICT_VERSION,j,{shareKey:l,requiredVersion:y});throw $({remote:p.from,error:_}),_}console.warn(`[fulgurjs:MFU-010] ${j}`)}}else if(u=[...g].sort(T).pop(),!u){if(i.strictVersion){let p=new R(b.SHARE_STRICT_VERSION,`no satisfying version for "${l}" (required "${y}") in share scope "${s}"`);throw $({remote:l,error:p}),p}if(i.fallback)return i.fallback();let a=new R(b.SHARE_NOT_AVAILABLE,`shared "${l}" (${y??"any"}) unavailable in scope "${s}" (no local fallback)`,{shareKey:l,requiredVersion:y});throw $({remote:l,error:a}),a}let E=c[u];if(w.resolveShare){let a=await w.resolveShare({shareKey:l,shareScope:s,requiredVersion:y,picked:E,available:Object.values(c)});a&&(E=a)}return E.loaded=!0,E.get()}function X(e,i,s){return new Promise((l,h)=>{let c=setTimeout(()=>h(new Error(`timeout after ${i}ms: ${s}`)),i);e.then(f=>{clearTimeout(c),l(f)},f=>{clearTimeout(c),h(f)})})}let Y=e=>new Promise(i=>setTimeout(i,e));function k(e,i){if(!e||typeof e.get!="function")throw new Error(`remoteEntry of "${i.name}" does not export a container interface (get/init)`);if(e.name&&i.name&&e.name!==i.name){let s=`remoteEntry self-reported name "${e.name}" mismatches configured name "${i.name}"`;if(i.promise)console.warn(`[fulgurjs] ${s} (promise-based remote, continuing)`);else throw Object.assign(new Error(s),{code:b.REMOTE_NAME_MISMATCH})}}async function x(e,i){return X(import(e),i.timeout??H,`load remoteEntry ${e}`)}async function C(e,i){let s=e.shareScope||"default";if(e.container){let c=S.get(e.container);if(c&&c!==s)throw new R(b.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${c}", cannot re-init with "${s}"`);return e.container}if(e.containerPromise)return e.containerPromise;let l=e.breakerState;if(l.openUntil>Date.now()){let c=new R(b.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(l.openUntil).toISOString()}`,{remote:e.name});throw $({remote:e.name,error:c}),c}e.state="loading",e.debug.status="loading";let h=(async()=>{let c=[];if(e.promise)c.push(async()=>{let a=await e.promise(),p=typeof a=="string"?await x(a,e):a;return k(p,e),p});else for(let a of[e.entry,...e.fallback??[]])c.push(async()=>{let p=await x(a,e);return k(p,e),p});let f,y,g=!1,u=i?.retries??e.retries??K;for(let a of c){for(let p=0;p<=u;p++){let j=performance.now();try{f=await a(),e.lastLoadMs=Math.round(performance.now()-j),e.debug.lastLoadMs=e.lastLoadMs,g=!0;break}catch(_){if(y=_,_?.code)throw _;p<u&&await Y(200*2**p)}}if(g)break}if(!g||!f){let a=[];throw/^https?:\/\//.test(e.entry)&&typeof location<"u"?(a.push(`1. is the remote dev server running? try opening ${e.entry} in the browser \u2014 it must return JS, not HTML/an error`),a.push("2. is the URL correct in federation({ remotes })? dev and prod entries can differ"),a.push("3. CORS: the remote dev server must allow cross-origin requests (fulgurjs-federation enables server.cors automatically; a custom server config may have disabled it)")):(a.push(`1. is the remote deployed and reachable? try opening ${e.entry} in the browser \u2014 it must return JS`),a.push("2. NGINX/CDN routing: the entry path must serve the remoteEntry JS file (check try_files / fallback rules)")),new R(b.REMOTE_LOAD_FAILED,`failed to load remote "${e.name}" from ${e.entry}: ${String(y?.message??y)}
|
|
2
|
+
`+a.join(`
|
|
3
|
+
`),{remote:e.name})}k(f,e);let E=S.get(f);if(E&&E!==s)throw new R(b.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${E}", cannot re-init with "${s}"`);return typeof f.init=="function"&&await f.init(t),S.set(f,s),e.container=f,e.state="loaded",e.debug.status="loaded",l.fails=0,f})();e.containerPromise=h;try{return await h}catch(c){if(e.containerPromise=void 0,e.state="failed",e.debug.status="failed",e.debug.error=String(c?.message??c),l.fails+=1,l.fails>=me&&(l.openUntil=Date.now()+fe,l.fails=0),c instanceof R)throw $({remote:e.name,error:c}),c;if(c?.code)throw $({remote:e.name,error:c}),c;let f=new R(b.REMOTE_LOAD_FAILED,String(c?.message??c),{remote:e.name});throw $({remote:e.name,error:f}),f}}function U(e){let i=e.indexOf("/");return i===-1?{remote:e,module:""}:{remote:e.slice(0,i),module:F(e.slice(i+1))}}function F(e){return e?e.startsWith(".")?e:`./${e}`:""}async function Z(e,i){let{remote:s,module:l}=U(e);w.beforeLoadRemote?.({remote:s,module:l});let h=n.get(s);if(!h)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${s}". Register it via federation({ remotes }) or registerRemote().`,{remote:s});let c;try{let g=l&&h.manifestUrl?D(e):Promise.resolve();[c]=await Promise.all([C(h,{retries:i?.retries}),g])}catch(g){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\u663E\u5F0F\u964D\u7EA7\uFF0C\u9519\u8BEF\u5DF2\u900F\u51FA)`,g),$({remote:s,error:g}),await i.fallbackModule();throw g}if(!l)return c;let f=`${s}@${h.shareScope||"default"}#${l}`;r.has(f)||r.set(f,c.get(l).catch(g=>{throw r.delete(f),g instanceof R||g?.code?g:new R(b.REMOTE_LOAD_FAILED,`failed to load module "${l}" from remote "${s}": ${String(g?.message??g)}`,{remote:s,module:l})}));let y;try{y=await r.get(f)}catch(g){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\u663E\u5F0F\u964D\u7EA7\uFF0C\u9519\u8BEF\u5DF2\u900F\u51FA)`,g),$({remote:s,error:g}),await i.fallbackModule();throw g}if(w.afterLoadRemote?.({remote:s,module:l,module_ns:y}),y&&typeof y=="object"&&Object.keys(y).length===0){let g=new R(b.EMPTY_EXPORTS,`no exports: ${l} @ ${s}`,{remote:s,module:l});$({remote:s,error:g}),console.error(`[fulgurjs:MFU-009] ${g.message}`)}return y}function Q(e){let i=n.get(e);if(!i)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return C(i)}async function D(e,i={}){let{remote:s,module:l}=U(e),h=n.get(s);if(!h)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${s}"`,{remote:s});let c=i.mode??"preload",f=(u,E)=>{if(u.sheet)return Promise.resolve();let a=d.get(u);if(a)return a;let p=new Promise(j=>{let _=()=>{u.removeEventListener("load",_),u.removeEventListener("error",v),j()},v=()=>{$({remote:s,error:new R(b.PRELOAD_FAILED,`failed to load remote stylesheet ${E}`,{remote:s})}),_()};u.addEventListener("load",_,{once:!0}),u.addEventListener("error",v,{once:!0}),u.sheet&&_()});return d.set(u,p),p},y=(u,E)=>{if(typeof document>"u")return Promise.resolve();let a=document.querySelector(`link[href="${u}"]`);if(a)return E==="style"&&c==="preload"?d.get(a)??Promise.resolve():Promise.resolve();let p=document.createElement("link");p.rel=E==="style"?"stylesheet":"modulepreload",p.href=u,c==="prefetch"&&(p.fetchPriority="low");let j=E==="style"?f(p,u):Promise.resolve();return document.head.appendChild(p),E==="style"&&c==="preload"?j:Promise.resolve()},g=u=>{let E=typeof document<"u"?document.baseURI:void 0,a=new URL(h.entry,E||"http://fulgurjs.invalid/");return new URL(u,a).href};try{if(h.manifestUrl){let u=m.get(h.manifestUrl);u||(u=fetch(h.manifestUrl,{cache:"no-cache"}).then(a=>a.ok?a.json():void 0),m.set(h.manifestUrl,u),u.then(a=>{a||m.delete(h.manifestUrl)},()=>m.delete(h.manifestUrl)));let E=await u;if(E){await y(h.entry,"modulepreload");let a=E.exposes,p=Array.isArray(a)?a.filter(v=>v&&typeof v=="object").map(v=>[String(v.name??""),v]):a&&typeof a=="object"?Object.entries(a):[],j=l?p.filter(([v,O])=>F(String(O?.name??v))===l):p,_=[];for(let[,v]of j)if(typeof v?.file=="string"&&await y(g(v.file),"modulepreload"),Array.isArray(v?.css))for(let O of v.css){if(typeof O!="string")continue;let ee=y(g(O),"style");c==="preload"&&_.push(ee)}await Promise.all(_);return}}await y(h.entry,"modulepreload")}catch(u){$({remote:s,error:new R(b.PRELOAD_FAILED,String(u?.message??u),{remote:s})})}}return typeof window>"u"||(window.__FULGURJS_SCOPE__=t,window.__FULGURJS_INFO__={get remotes(){let e={};for(let[i,s]of n)e[i]={...s.debug,entry:s.entry};return e},errors:[]}),{shareScopeMap:t,initSharing:z,registerShare:W,registerRemotes:A,registerRemote:G,registerPlugins:J,loadShare:B,loadRemote:Z,getContainer:Q,preloadRemote:D,parseSpec:U}}var q=globalThis,M=q.__FULGURJS_RUNTIME__??pe();q.__FULGURJS_RUNTIME__=M;try{Object.freeze(M)}catch{}var we=V;function be(){return M}var ve=M.initSharing,_e=M.registerShare,Me=M.registerRemotes,$e=M.registerRemote,je=M.registerPlugins,Te=M.loadShare,Le=M.loadRemote,Oe=M.getContainer,Pe=M.preloadRemote,Ne=M.shareScopeMap;function Ie(t){if(t&&typeof t=="object"&&"default"in t){let n=t.default;return n!==void 0?n:t}return t}var ke=M;export{ke as default,Oe as getContainer,be as getRuntime,ve as initSharing,Le as loadRemote,Te as loadShare,Pe as preloadRemote,je as registerPlugins,$e as registerRemote,Me as registerRemotes,_e as registerShare,M as runtime,Ne as shareScopeMap,Ie as unwrapDefault,we as version};
|
package/dist/vue.cjs
CHANGED
|
@@ -267,6 +267,8 @@ function createRuntime() {
|
|
|
267
267
|
const remotes = /* @__PURE__ */ new Map();
|
|
268
268
|
const plugins = [];
|
|
269
269
|
const loadedModules = /* @__PURE__ */ new Map();
|
|
270
|
+
const remoteManifests = /* @__PURE__ */ new Map();
|
|
271
|
+
const stylesheetLoads = /* @__PURE__ */ new WeakMap();
|
|
270
272
|
const containerInitScopes = /* @__PURE__ */ new WeakMap();
|
|
271
273
|
const hooks = {};
|
|
272
274
|
const applyPlugins = () => {
|
|
@@ -575,7 +577,8 @@ function createRuntime() {
|
|
|
575
577
|
}
|
|
576
578
|
let container;
|
|
577
579
|
try {
|
|
578
|
-
|
|
580
|
+
const stylesReady = module2 && remote.manifestUrl ? preloadRemote2(spec) : Promise.resolve();
|
|
581
|
+
[container] = await Promise.all([acquireContainer(remote, { retries: opts?.retries }), stylesReady]);
|
|
579
582
|
} catch (err) {
|
|
580
583
|
if (opts?.fallbackModule) {
|
|
581
584
|
console.error(`[fulgurjs] loadRemote("${spec}") failed; returning fallbackModule (\u663E\u5F0F\u964D\u7EA7\uFF0C\u9519\u8BEF\u5DF2\u900F\u51FA)`, err);
|
|
@@ -631,15 +634,44 @@ function createRuntime() {
|
|
|
631
634
|
return acquireContainer(remote);
|
|
632
635
|
}
|
|
633
636
|
async function preloadRemote2(spec, opts = {}) {
|
|
634
|
-
const { remote: name } = parseSpec(spec);
|
|
637
|
+
const { remote: name, module: module2 } = parseSpec(spec);
|
|
635
638
|
const remote = remotes.get(name);
|
|
636
639
|
if (!remote) {
|
|
637
640
|
throw new FgError(ErrorCodes.REMOTE_UNKNOWN, `unknown remote "${name}"`, { remote: name });
|
|
638
641
|
}
|
|
639
642
|
const mode = opts.mode ?? "preload";
|
|
643
|
+
const waitForStylesheet = (link, href) => {
|
|
644
|
+
if (link.sheet) return Promise.resolve();
|
|
645
|
+
const pending = stylesheetLoads.get(link);
|
|
646
|
+
if (pending) return pending;
|
|
647
|
+
const loaded = new Promise((resolve) => {
|
|
648
|
+
const finish = () => {
|
|
649
|
+
link.removeEventListener("load", finish);
|
|
650
|
+
link.removeEventListener("error", failed);
|
|
651
|
+
resolve();
|
|
652
|
+
};
|
|
653
|
+
const failed = () => {
|
|
654
|
+
emitError({
|
|
655
|
+
remote: name,
|
|
656
|
+
error: new FgError(ErrorCodes.PRELOAD_FAILED, `failed to load remote stylesheet ${href}`, {
|
|
657
|
+
remote: name
|
|
658
|
+
})
|
|
659
|
+
});
|
|
660
|
+
finish();
|
|
661
|
+
};
|
|
662
|
+
link.addEventListener("load", finish, { once: true });
|
|
663
|
+
link.addEventListener("error", failed, { once: true });
|
|
664
|
+
if (link.sheet) finish();
|
|
665
|
+
});
|
|
666
|
+
stylesheetLoads.set(link, loaded);
|
|
667
|
+
return loaded;
|
|
668
|
+
};
|
|
640
669
|
const inject = (href, as) => {
|
|
641
|
-
if (typeof document === "undefined") return;
|
|
642
|
-
|
|
670
|
+
if (typeof document === "undefined") return Promise.resolve();
|
|
671
|
+
const existing = document.querySelector(`link[href="${href}"]`);
|
|
672
|
+
if (existing) {
|
|
673
|
+
return as === "style" && mode === "preload" ? stylesheetLoads.get(existing) ?? Promise.resolve() : Promise.resolve();
|
|
674
|
+
}
|
|
643
675
|
const link = document.createElement("link");
|
|
644
676
|
link.rel = as === "style" ? "stylesheet" : "modulepreload";
|
|
645
677
|
link.href = href;
|
|
@@ -647,24 +679,54 @@ function createRuntime() {
|
|
|
647
679
|
;
|
|
648
680
|
link.fetchPriority = "low";
|
|
649
681
|
}
|
|
682
|
+
const loaded = as === "style" ? waitForStylesheet(link, href) : Promise.resolve();
|
|
650
683
|
document.head.appendChild(link);
|
|
684
|
+
return as === "style" && mode === "preload" ? loaded : Promise.resolve();
|
|
685
|
+
};
|
|
686
|
+
const resolveAssetUrl = (asset) => {
|
|
687
|
+
const pageUrl = typeof document !== "undefined" ? document.baseURI : void 0;
|
|
688
|
+
const base = new URL(remote.entry, pageUrl || "http://fulgurjs.invalid/");
|
|
689
|
+
return new URL(asset, base).href;
|
|
651
690
|
};
|
|
652
691
|
try {
|
|
653
692
|
if (remote.manifestUrl) {
|
|
654
|
-
|
|
655
|
-
if (
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
693
|
+
let manifestPromise = remoteManifests.get(remote.manifestUrl);
|
|
694
|
+
if (!manifestPromise) {
|
|
695
|
+
manifestPromise = fetch(remote.manifestUrl, { cache: "no-cache" }).then(
|
|
696
|
+
(res) => res.ok ? res.json() : void 0
|
|
697
|
+
);
|
|
698
|
+
remoteManifests.set(remote.manifestUrl, manifestPromise);
|
|
699
|
+
manifestPromise.then(
|
|
700
|
+
(manifest2) => {
|
|
701
|
+
if (!manifest2) remoteManifests.delete(remote.manifestUrl);
|
|
702
|
+
},
|
|
703
|
+
() => remoteManifests.delete(remote.manifestUrl)
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
const manifest = await manifestPromise;
|
|
707
|
+
if (manifest) {
|
|
708
|
+
await inject(remote.entry, "modulepreload");
|
|
709
|
+
const exposes = manifest.exposes;
|
|
710
|
+
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) : [];
|
|
711
|
+
const selected = module2 ? entries.filter(([key, item]) => normalizeModuleName(String(item?.name ?? key)) === module2) : entries;
|
|
712
|
+
const cssLoads = [];
|
|
713
|
+
for (const [, item] of selected) {
|
|
714
|
+
if (typeof item?.file === "string") {
|
|
715
|
+
await inject(resolveAssetUrl(item.file), "modulepreload");
|
|
716
|
+
}
|
|
717
|
+
if (Array.isArray(item?.css)) {
|
|
718
|
+
for (const css of item.css) {
|
|
719
|
+
if (typeof css !== "string") continue;
|
|
720
|
+
const loading = inject(resolveAssetUrl(css), "style");
|
|
721
|
+
if (mode === "preload") cssLoads.push(loading);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
663
724
|
}
|
|
725
|
+
await Promise.all(cssLoads);
|
|
664
726
|
return;
|
|
665
727
|
}
|
|
666
728
|
}
|
|
667
|
-
inject(remote.entry, "modulepreload");
|
|
729
|
+
await inject(remote.entry, "modulepreload");
|
|
668
730
|
} catch (err) {
|
|
669
731
|
emitError({
|
|
670
732
|
remote: name,
|
package/dist/vue.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
ErrorCodes,
|
|
3
3
|
FgError
|
|
4
4
|
} from "./chunk-3VBYOVH4.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-RQPLFDDT.js";
|
|
6
6
|
|
|
7
7
|
// src/vue.ts
|
|
8
8
|
import { defineAsyncComponent, defineComponent, h } from "vue";
|
|
@@ -215,6 +215,8 @@ function createRuntime() {
|
|
|
215
215
|
const remotes = /* @__PURE__ */ new Map();
|
|
216
216
|
const plugins = [];
|
|
217
217
|
const loadedModules = /* @__PURE__ */ new Map();
|
|
218
|
+
const remoteManifests = /* @__PURE__ */ new Map();
|
|
219
|
+
const stylesheetLoads = /* @__PURE__ */ new WeakMap();
|
|
218
220
|
const containerInitScopes = /* @__PURE__ */ new WeakMap();
|
|
219
221
|
const hooks = {};
|
|
220
222
|
const applyPlugins = () => {
|
|
@@ -523,7 +525,8 @@ function createRuntime() {
|
|
|
523
525
|
}
|
|
524
526
|
let container;
|
|
525
527
|
try {
|
|
526
|
-
|
|
528
|
+
const stylesReady = module && remote.manifestUrl ? preloadRemote2(spec) : Promise.resolve();
|
|
529
|
+
[container] = await Promise.all([acquireContainer(remote, { retries: opts?.retries }), stylesReady]);
|
|
527
530
|
} catch (err) {
|
|
528
531
|
if (opts?.fallbackModule) {
|
|
529
532
|
console.error(`[fulgurjs] loadRemote("${spec}") failed; returning fallbackModule (\u663E\u5F0F\u964D\u7EA7\uFF0C\u9519\u8BEF\u5DF2\u900F\u51FA)`, err);
|
|
@@ -579,15 +582,44 @@ function createRuntime() {
|
|
|
579
582
|
return acquireContainer(remote);
|
|
580
583
|
}
|
|
581
584
|
async function preloadRemote2(spec, opts = {}) {
|
|
582
|
-
const { remote: name } = parseSpec(spec);
|
|
585
|
+
const { remote: name, module } = parseSpec(spec);
|
|
583
586
|
const remote = remotes.get(name);
|
|
584
587
|
if (!remote) {
|
|
585
588
|
throw new FgError(ErrorCodes.REMOTE_UNKNOWN, `unknown remote "${name}"`, { remote: name });
|
|
586
589
|
}
|
|
587
590
|
const mode = opts.mode ?? "preload";
|
|
591
|
+
const waitForStylesheet = (link, href) => {
|
|
592
|
+
if (link.sheet) return Promise.resolve();
|
|
593
|
+
const pending = stylesheetLoads.get(link);
|
|
594
|
+
if (pending) return pending;
|
|
595
|
+
const loaded = new Promise((resolve) => {
|
|
596
|
+
const finish = () => {
|
|
597
|
+
link.removeEventListener("load", finish);
|
|
598
|
+
link.removeEventListener("error", failed);
|
|
599
|
+
resolve();
|
|
600
|
+
};
|
|
601
|
+
const failed = () => {
|
|
602
|
+
emitError({
|
|
603
|
+
remote: name,
|
|
604
|
+
error: new FgError(ErrorCodes.PRELOAD_FAILED, `failed to load remote stylesheet ${href}`, {
|
|
605
|
+
remote: name
|
|
606
|
+
})
|
|
607
|
+
});
|
|
608
|
+
finish();
|
|
609
|
+
};
|
|
610
|
+
link.addEventListener("load", finish, { once: true });
|
|
611
|
+
link.addEventListener("error", failed, { once: true });
|
|
612
|
+
if (link.sheet) finish();
|
|
613
|
+
});
|
|
614
|
+
stylesheetLoads.set(link, loaded);
|
|
615
|
+
return loaded;
|
|
616
|
+
};
|
|
588
617
|
const inject = (href, as) => {
|
|
589
|
-
if (typeof document === "undefined") return;
|
|
590
|
-
|
|
618
|
+
if (typeof document === "undefined") return Promise.resolve();
|
|
619
|
+
const existing = document.querySelector(`link[href="${href}"]`);
|
|
620
|
+
if (existing) {
|
|
621
|
+
return as === "style" && mode === "preload" ? stylesheetLoads.get(existing) ?? Promise.resolve() : Promise.resolve();
|
|
622
|
+
}
|
|
591
623
|
const link = document.createElement("link");
|
|
592
624
|
link.rel = as === "style" ? "stylesheet" : "modulepreload";
|
|
593
625
|
link.href = href;
|
|
@@ -595,24 +627,54 @@ function createRuntime() {
|
|
|
595
627
|
;
|
|
596
628
|
link.fetchPriority = "low";
|
|
597
629
|
}
|
|
630
|
+
const loaded = as === "style" ? waitForStylesheet(link, href) : Promise.resolve();
|
|
598
631
|
document.head.appendChild(link);
|
|
632
|
+
return as === "style" && mode === "preload" ? loaded : Promise.resolve();
|
|
633
|
+
};
|
|
634
|
+
const resolveAssetUrl = (asset) => {
|
|
635
|
+
const pageUrl = typeof document !== "undefined" ? document.baseURI : void 0;
|
|
636
|
+
const base = new URL(remote.entry, pageUrl || "http://fulgurjs.invalid/");
|
|
637
|
+
return new URL(asset, base).href;
|
|
599
638
|
};
|
|
600
639
|
try {
|
|
601
640
|
if (remote.manifestUrl) {
|
|
602
|
-
|
|
603
|
-
if (
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
641
|
+
let manifestPromise = remoteManifests.get(remote.manifestUrl);
|
|
642
|
+
if (!manifestPromise) {
|
|
643
|
+
manifestPromise = fetch(remote.manifestUrl, { cache: "no-cache" }).then(
|
|
644
|
+
(res) => res.ok ? res.json() : void 0
|
|
645
|
+
);
|
|
646
|
+
remoteManifests.set(remote.manifestUrl, manifestPromise);
|
|
647
|
+
manifestPromise.then(
|
|
648
|
+
(manifest2) => {
|
|
649
|
+
if (!manifest2) remoteManifests.delete(remote.manifestUrl);
|
|
650
|
+
},
|
|
651
|
+
() => remoteManifests.delete(remote.manifestUrl)
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
const manifest = await manifestPromise;
|
|
655
|
+
if (manifest) {
|
|
656
|
+
await inject(remote.entry, "modulepreload");
|
|
657
|
+
const exposes = manifest.exposes;
|
|
658
|
+
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) : [];
|
|
659
|
+
const selected = module ? entries.filter(([key, item]) => normalizeModuleName(String(item?.name ?? key)) === module) : entries;
|
|
660
|
+
const cssLoads = [];
|
|
661
|
+
for (const [, item] of selected) {
|
|
662
|
+
if (typeof item?.file === "string") {
|
|
663
|
+
await inject(resolveAssetUrl(item.file), "modulepreload");
|
|
664
|
+
}
|
|
665
|
+
if (Array.isArray(item?.css)) {
|
|
666
|
+
for (const css of item.css) {
|
|
667
|
+
if (typeof css !== "string") continue;
|
|
668
|
+
const loading = inject(resolveAssetUrl(css), "style");
|
|
669
|
+
if (mode === "preload") cssLoads.push(loading);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
611
672
|
}
|
|
673
|
+
await Promise.all(cssLoads);
|
|
612
674
|
return;
|
|
613
675
|
}
|
|
614
676
|
}
|
|
615
|
-
inject(remote.entry, "modulepreload");
|
|
677
|
+
await inject(remote.entry, "modulepreload");
|
|
616
678
|
} catch (err) {
|
|
617
679
|
emitError({
|
|
618
680
|
remote: name,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
# P5:fixtures Vite 7/8 兼容矩阵(2026-09-14
|
|
1
|
+
# P5:fixtures Vite 7/8 兼容矩阵(2026-09-14 完成,2026-09-23 补充)
|
|
2
2
|
|
|
3
3
|
> 结论先行:**Vite 7.3.6 与 8.3.0 下 fixtures 三件套 dev+prod e2e 全部通过**,无需代码改动。
|
|
4
4
|
> 兼容矩阵至此覆盖 Vite 5.1.4 / 5.2.12 / 6.4.3 / 7.3.6 / 8.3.0。
|
|
5
|
+
> 2026-09-23 补充:Vite 8.3.0(Rolldown)下,expose 的静态依赖 chunk 持有 CSS 时,manifest 仍能收集到该 CSS;针对性回归测试通过。
|
|
5
6
|
|
|
6
7
|
## 测试方法
|
|
7
8
|
|
|
@@ -29,8 +30,9 @@
|
|
|
29
30
|
等钩子签名在 7/8 无破坏性变化;
|
|
30
31
|
- dev 协作引擎依赖的 `server.middlewares`、`pluginContainer.resolveId` 行为一致;
|
|
31
32
|
- build 引擎(rollup 原生输出 + `emitFile chunk`)在 7/8 下产物结构不变。
|
|
33
|
+
- `packages/plugin/tests/build-manifest-css.test.ts` 在 Vite 8.3.0/Rolldown 下验证了共享静态依赖 chunk 上的 CSS 会进入 expose manifest;这是针对 CSS 注入链的构建测试,不等同于完整的 Rolldown dev/prod e2e 矩阵。
|
|
32
34
|
|
|
33
35
|
## 遗留
|
|
34
36
|
|
|
35
|
-
- Vite 8 原生
|
|
37
|
+
- Vite 8 原生 Rolldown 的完整 fixtures dev/prod e2e 矩阵仍未执行;当前仅 CSS manifest 构建回归已验证。
|
|
36
38
|
- fixtures 只覆盖 vue 生态;react fixture 若将来补齐需同步扩 7/8 矩阵。
|