Skip to content

Conversation

@DallasCarraher
Copy link

@DallasCarraher DallasCarraher commented Dec 10, 2025

TLDR change summary

  • Added manualChunks logic to isolate Vite's preload helper into its own chunk
  • This prevents a circular deadlock where hostInit waits for loadShare TLA, which waits for init()

Problem

When using @module-federation/vite with shared dependencies (e.g., React singleton), users encounter a circular deadlock that causes the app to hang silently on load.

The deadlock sequence:

  1. hostInit imports the preload helper _ from a shared chunk (e.g., mf-loadShare)
  2. That chunk contains loadShare modules with top-level await (TLA) waiting for initPromise
  3. initPromise only resolves when remoteEntry.init() is called
  4. But hostInit can't call init() until it finishes loading → DEADLOCK

Root cause: Rollup/Vite bundles the preload helper into the same chunk as the loadShare TLA code because both are imported by multiple entry points.

Example of problematic chunk structure:

hostInit-xxx.js:

import { _ as preloadHelper } from "./mf-loadShare-xxx.js" // ❌ Imports from TLA chunk

mf-loadShare-xxx.js:

export const _ = vite_preload_helper // Preload helper
const exportModule = await initPromise.then(...) // TLA blocks until init()

Solution

Add manualChunks configuration in the plugin's config hook to isolate the preload helper:

if (command === 'build') {
  const existingManualChunks = output.manualChunks;
  output.manualChunks = function(id, meta) {
    // Isolate preload helper to prevent deadlock
    if (id.includes('vite/preload-helper') || 
        id.includes('vite/modulepreload-polyfill') ||
        id.includes('commonjsHelpers')) {
      return 'preload-helper';
    }
    // Preserve existing manualChunks behavior
    if (typeof existingManualChunks === 'function') {
      return existingManualChunks(id, meta);
    }
    return undefined;
  };
}

Fixed chunk structure:

hostInit-xxx.js:

import { _ as preloadHelper } from "./preload-helper-xxx.js"  // ✅ Separate chunk

preload-helper-xxx.js:

export const _ = __vite_preload_helper  // No TLA, loads immediately

mf-loadShare-xxx.js:

  const exportModule = await initPromise.then(...)  // TLA in isolatered in the user's vite config
  • Bootstrap pattern required: The dynamic import('./bootstrap') pattern is still necessary to create an async boundary for MF runtime initialization

Testing

  • Built plugin successfully
  • Tested with Vite 6 project using shared React/ReactDOM singleton
  • Verified app loads and renders correctly
  • Verified MFE (remote) loads successfully
  • Backwards compatibility with Vite 5.x (should be fine - manualChunks is standard Rollup)

Related Issues

Fixes #320

…o ESM"

- Changed virtual modules from CJS (require + module.exports) to ESM
(await import + export)
- Changed file extensions from .js to .mjs to ensure ESM treatment by
bundlers
- This fixes the 'await is only valid in async functions' syntax error
when Rolldown
  wraps CJS modules in a function wrapper

Fixes module-federation#320"
Copy link
Collaborator

@gioboa gioboa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your help, in the next days I'm going to check this PR. 🙏

@gioboa gioboa changed the title Fix: Vite 7 Rolldown compatibility - convert shared/remote modules to ESM fix: Vite 7 Rolldown compatibility - convert shared/remote modules to ESM Dec 10, 2025
## Problem
Vite 7 (Rolldown) wraps CJS modules in __commonJSMin() arrow function,
making top-level await invalid ('await is only valid in async functions').

## Solution
- Dev mode: Keep original CJS syntax (backward compatible with Vite 5)
- Build mode: Use ESM (import/export) with top-level await
- runtimeInitStatus: Dual exports to support both modes

## Testing
Added new CI job to test production builds (vite build + preview),
which catches the Vite 7/Rolldown CJS wrapper issue.

Fixes module-federation#320
@gioboa gioboa self-requested a review December 11, 2025 05:27
Copy link
Collaborator

@gioboa gioboa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pcfreak30 @sabov can you double check this PR? Thanks 🙏

… TLA

The build was hanging due to a circular dependency where:
1. hostInit imports preload helper from a shared chunk
2. That chunk contains loadShare TLA waiting for initPromise
3. initPromise only resolves after remoteEntry.init() is called
4. hostInit can't call init() until the shared chunk loads → DEADLOCK

Changes:
- Isolate vite/preload-helper, vite/modulepreload-polyfill, and
  commonjsHelpers into a separate 'preload-helper' chunk via manualChunks
- Fix shared module alias regex: patterns ending with '/' (e.g., 'react/')
  now correctly match only subpaths ('react/jsx-runtime') and not the
  base package ('react')
- Use globalThis singleton for initPromise to prevent duplicate instances

This ensures the preload helper is available before any TLA-blocked chunks
need to load, breaking the circular dependency.
@DallasCarraher DallasCarraher changed the title fix: Vite 7 Rolldown compatibility - convert shared/remote modules to ESM fix: Vite 7 Rolldown compatibility - isolate preload helper to prevent shared module deadlock Dec 11, 2025
@DallasCarraher DallasCarraher marked this pull request as draft December 11, 2025 06:31
@DallasCarraher DallasCarraher marked this pull request as ready for review December 11, 2025 06:33
@wojtask9
Copy link

wojtask9 commented Dec 11, 2025

Summary from my testing:

  1. vite 7.2.7 (here I haven't seen any deadlocks)
    • dev -> no changes (everything looks good)
    • build -> these 404 errors existing before this change. Still everything works as expected.
image
  1. rolldown-vite 7.2.10 (before this change I saw deadlocks)
  • dev -> before there was deadlock. Now i got issue.
    Not sure if it is a problem with rolldown or this plugin
image
  • build -> this looks like still problem with this plugin
image

reserved word is await from
image

attached chunk below

import{r as e}from"./preload-helper-DAbutUMQ.js";import{n as t,t as n}from"./host__mf_v__runtimeInit__mf_v__-BQ7g54Iu.js";var r=e(((e,t)=>{var{initPromise:r}=n();t.exports=await r.then(e=>e.loadShare(`vue`,{customShareInfo:{shareConfig:{singleton:!0,strictVersion:!1,requiredVersion:`^3.5.25`}}})).then(e=>e())}));r();var i=typeof document<`u`;function a(e){return typeof e==`object`||`displayName`in e||`props`in e||`__vccOpts`in e}function o(e){return e.__esModule||e[Symbol.toStringTag]===`Module`||e.default&&a(e.default)}var s=Object.assign;function c(e,t){let n={};for(let r in t){let i=t[r];n[r]=u(i)?i.map(e):e(i)}return n}var l=()=>{},u=Array.isArray;function d(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}var f=/#/g,p=/&/g,m=/\//g,h=/=/g,g=/\?/g,_=/\+/g,ee=/%5B/g,te=/%5D/g,ne=/%5E/g,re=/%60/g,v=/%7B/g,y=/%7C/g,b=/%7D/g,x=/%20/g;function S(e){return e==null?``:encodeURI(``+e).replace(y,`|`).replace(ee,`[`).replace(te,`]`)}function ie(e){return S(e).replace(v,`{`).replace(b,`}`).replace(ne,`^`)}function C(e){return S(e).replace(_,`%2B`).replace(x,`+`).replace(f,`%23`).replace(p,`%26`).replace(re,"`").replace(v,`{`).replace(b,`}`).replace(ne,`^`)}function w(e){return C(e).replace(h,`%3D`)}function ae(e){return S(e).replace(f,`%23`).replace(g,`%3F`)}function oe(e){return ae(e).replace(m,`%2F`)}function T(e){if(e==null)return null;try{return decodeURIComponent(``+e)}catch{}return``+e}var E=/\/$/,D=e=>e.replace(E,``);function O(e,t,n=`/`){let r,i={},a=``,o=``,s=t.indexOf(`#`),c=t.indexOf(`?`);return c=s>=0&&c>s?-1:c,c>=0&&(r=t.slice(0,c),a=t.slice(c,s>0?s:t.length),i=e(a.slice(1))),s>=0&&(r||=t.slice(0,s),o=t.slice(s,t.length)),r=N(r??t,n),{fullPath:r+a+o,path:r,query:i,hash:T(o)}}function se(e,t){let n=t.query?e(t.query):``;return t.path+(n&&`?`)+n+(t.hash||``)}function k(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||`/`}function ce(e,t,n){let r=t.matched.length-1,i=n.matched.length-1;return r>-1&&r===i&&A(t.matched[r],n.matched[i])&&j(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function A(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function j(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(let n in e)if(!le(e[n],t[n]))return!1;return!0}function le(e,t){return u(e)?M(e,t):u(t)?M(t,e):e===t}function M(e,t){return u(t)?e.length===t.length&&e.every((e,n)=>e===t[n]):e.length===1&&e[0]===t}function N(e,t){if(e.startsWith(`/`))return e;if(!e)return t;let n=t.split(`/`),r=e.split(`/`),i=r[r.length-1];(i===`..`||i===`.`)&&r.push(``);let a=n.length-1,o,s;for(o=0;o<r.length;o++)if(s=r[o],s!==`.`)if(s===`..`)a>1&&a--;else break;return n.slice(0,a).join(`/`)+`/`+r.slice(o).join(`/`)}var P={path:`/`,name:void 0,params:{},query:{},hash:``,fullPath:`/`,matched:[],meta:{},redirectedFrom:void 0},F=function(e){return e.pop=`pop`,e.push=`push`,e}({}),I=function(e){return e.back=`back`,e.forward=`forward`,e.unknown=``,e}({});function L(e){if(!e)if(i){let t=document.querySelector(`base`);e=t&&t.getAttribute(`href`)||`/`,e=e.replace(/^\w+:\/\/[^\/]+/,``)}else e=`/`;return e[0]!==`/`&&e[0]!==`#`&&(e=`/`+e),D(e)}var ue=/^[^#]+#/;function R(e,t){return e.replace(ue,`#`)+t}function de(e,t){let n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}var z=()=>({left:window.scrollX,top:window.scrollY});function fe(e){let t;if(`el`in e){let n=e.el,r=typeof n==`string`&&n.startsWith(`#`),i=typeof n==`string`?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!i)return;t=de(i,e)}else t=e;`scrollBehavior`in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left==null?window.scrollX:t.left,t.top==null?window.scrollY:t.top)}function pe(e,t){return(history.state?history.state.position-t:-1)+e}var B=new Map;function me(e,t){B.set(e,t)}function he(e){let t=B.get(e);return B.delete(e),t}function V(e){return typeof e==`string`||e&&typeof e==`object`}function ge(e){return typeof e==`string`||typeof e==`symbol`}var H=function(e){return e[e.MATCHER_NOT_FOUND=1]=`MATCHER_NOT_FOUND`,e[e.NAVIGATION_GUARD_REDIRECT=2]=`NAVIGATION_GUARD_REDIRECT`,e[e.NAVIGATION_ABORTED=4]=`NAVIGATION_ABORTED`,e[e.NAVIGATION_CANCELLED=8]=`NAVIGATION_CANCELLED`,e[e.NAVIGATION_DUPLICATED=16]=`NAVIGATION_DUPLICATED`,e}({}),U=Symbol(``);H.MATCHER_NOT_FOUND,H.NAVIGATION_GUARD_REDIRECT,H.NAVIGATION_ABORTED,H.NAVIGATION_CANCELLED,H.NAVIGATION_DUPLICATED;function W(e,t){return s(Error(),{type:e,[U]:!0},t)}function G(e,t){return e instanceof Error&&U in e&&(t==null||!!(e.type&t))}function _e(e){let t={};if(e===``||e===`?`)return t;let n=(e[0]===`?`?e.slice(1):e).split(`&`);for(let e=0;e<n.length;++e){let r=n[e].replace(_,` `),i=r.indexOf(`=`),a=T(i<0?r:r.slice(0,i)),o=i<0?null:T(r.slice(i+1));if(a in t){let e=t[a];u(e)||(e=t[a]=[e]),e.push(o)}else t[a]=o}return t}function ve(e){let t=``;for(let n in e){let r=e[n];if(n=w(n),r==null){r!==void 0&&(t+=(t.length?`&`:``)+n);continue}(u(r)?r.map(e=>e&&C(e)):[r&&C(r)]).forEach(e=>{e!==void 0&&(t+=(t.length?`&`:``)+n,e!=null&&(t+=`=`+e))})}return t}function ye(e){let t={};for(let n in e){let r=e[n];r!==void 0&&(t[n]=u(r)?r.map(e=>e==null?null:``+e):r==null?r:``+r)}return t}var K=Symbol(``),q=Symbol(``),be=Symbol(``),xe=Symbol(``),Se=Symbol(``);function J(){let e=[];function t(t){return e.push(t),()=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Y(e,t,n,r,i,a=e=>e()){let o=r&&(r.enterCallbacks[i]=r.enterCallbacks[i]||[]);return()=>new Promise((s,c)=>{let l=e=>{e===!1?c(W(H.NAVIGATION_ABORTED,{from:n,to:t})):e instanceof Error?c(e):V(e)?c(W(H.NAVIGATION_GUARD_REDIRECT,{from:t,to:e})):(o&&r.enterCallbacks[i]===o&&typeof e==`function`&&o.push(e),s())},u=a(()=>e.call(r&&r.instances[i],t,n,l)),d=Promise.resolve(u);e.length<3&&(d=d.then(l)),d.catch(e=>c(e))})}function Ce(e,t,n,r,i=e=>e()){let s=[];for(let c of e)for(let e in c.components){let l=c.components[e];if(!(t!==`beforeRouteEnter`&&!c.instances[e]))if(a(l)){let a=(l.__vccOpts||l)[t];a&&s.push(Y(a,n,r,c,e,i))}else{let a=l();s.push(()=>a.then(a=>{if(!a)throw Error(`Couldn't resolve component "${e}" at "${c.path}"`);let s=o(a)?a.default:a;c.mods[e]=a,c.components[e]=s;let l=(s.__vccOpts||s)[t];return l&&Y(l,n,r,c,e,i)()}))}}return s}function we(e,t){let n=[],r=[],i=[],a=Math.max(t.matched.length,e.matched.length);for(let o=0;o<a;o++){let a=t.matched[o];a&&(e.matched.find(e=>A(e,a))?r.push(a):n.push(a));let s=e.matched[o];s&&(t.matched.find(e=>A(e,s))||i.push(s))}return[n,r,i]}var X=r(),Te=()=>location.protocol+`//`+location.host;function Ee(e,t){let{pathname:n,search:r,hash:i}=t,a=e.indexOf(`#`);if(a>-1){let t=i.includes(e.slice(a))?e.slice(a).length:1,n=i.slice(t);return n[0]!==`/`&&(n=`/`+n),k(n,``)}return k(n,e)+r+i}function De(e,t,n,r){let i=[],a=[],o=null,c=({state:a})=>{let s=Ee(e,location),c=n.value,l=t.value,u=0;if(a){if(n.value=s,t.value=a,o&&o===c){o=null;return}u=l?a.position-l.position:0}else r(s);i.forEach(e=>{e(n.value,c,{delta:u,type:F.pop,direction:u?u>0?I.forward:I.back:I.unknown})})};function l(){o=n.value}function u(e){i.push(e);let t=()=>{let t=i.indexOf(e);t>-1&&i.splice(t,1)};return a.push(t),t}function d(){if(document.visibilityState===`hidden`){let{history:e}=window;if(!e.state)return;e.replaceState(s({},e.state,{scroll:z()}),``)}}function f(){for(let e of a)e();a=[],window.removeEventListener(`popstate`,c),window.removeEventListener(`pagehide`,d),document.removeEventListener(`visibilitychange`,d)}return window.addEventListener(`popstate`,c),window.addEventListener(`pagehide`,d),document.addEventListener(`visibilitychange`,d),{pauseListeners:l,listen:u,destroy:f}}function Oe(e,t,n,r=!1,i=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:i?z():null}}function ke(e){let{history:t,location:n}=window,r={value:Ee(e,n)},i={value:t.state};i.value||a(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function a(r,a,o){let s=e.indexOf(`#`),c=s>-1?(n.host&&document.querySelector(`base`)?e:e.slice(s))+r:Te()+e+r;try{t[o?`replaceState`:`pushState`](a,``,c),i.value=a}catch(e){console.error(e),n[o?`replace`:`assign`](c)}}function o(e,n){a(e,s({},t.state,Oe(i.value.back,e,i.value.forward,!0),n,{position:i.value.position}),!0),r.value=e}function c(e,n){let o=s({},i.value,t.state,{forward:e,scroll:z()});a(o.current,o,!0),a(e,s({},Oe(r.value,e,null),{position:o.position+1},n),!1),r.value=e}return{location:r,state:i,push:c,replace:o}}function Ae(e){e=L(e);let t=ke(e),n=De(e,t.state,t.location,t.replace);function r(e,t=!0){t||n.pauseListeners(),history.go(e)}let i=s({location:``,base:e,go:r,createHref:R.bind(null,e)},t,n);return Object.defineProperty(i,`location`,{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(i,`state`,{enumerable:!0,get:()=>t.state.value}),i}var Z=function(e){return e[e.Static=0]=`Static`,e[e.Param=1]=`Param`,e[e.Group=2]=`Group`,e}({}),Q=function(e){return e[e.Static=0]=`Static`,e[e.Param=1]=`Param`,e[e.ParamRegExp=2]=`ParamRegExp`,e[e.ParamRegExpEnd=3]=`ParamRegExpEnd`,e[e.EscapeNext=4]=`EscapeNext`,e}(Q||{}),je={type:Z.Static,value:``},Me=/[a-zA-Z0-9_]/;function Ne(e){if(!e)return[[]];if(e===`/`)return[[je]];if(!e.startsWith(`/`))throw Error(`Invalid path "${e}"`);function t(e){throw Error(`ERR (${n})/"${l}": ${e}`)}let n=Q.Static,r=n,i=[],a;function o(){a&&i.push(a),a=[]}let s=0,c,l=``,u=``;function d(){l&&=(n===Q.Static?a.push({type:Z.Static,value:l}):n===Q.Param||n===Q.ParamRegExp||n===Q.ParamRegExpEnd?(a.length>1&&(c===`*`||c===`+`)&&t(`A repeatable param (${l}) must be alone in its segment. eg: '/:ids+.`),a.push({type:Z.Param,value:l,regexp:u,repeatable:c===`*`||c===`+`,optional:c===`*`||c===`?`})):t(`Invalid state to consume buffer`),``)}function f(){l+=c}for(;s<e.length;){if(c=e[s++],c===`\\`&&n!==Q.ParamRegExp){r=n,n=Q.EscapeNext;continue}switch(n){case Q.Static:c===`/`?(l&&d(),o()):c===`:`?(d(),n=Q.Param):f();break;case Q.EscapeNext:f(),n=r;break;case Q.Param:c===`(`?n=Q.ParamRegExp:Me.test(c)?f():(d(),n=Q.Static,c!==`*`&&c!==`?`&&c!==`+`&&s--);break;case Q.ParamRegExp:c===`)`?u[u.length-1]==`\\`?u=u.slice(0,-1)+c:n=Q.ParamRegExpEnd:u+=c;break;case Q.ParamRegExpEnd:d(),n=Q.Static,c!==`*`&&c!==`?`&&c!==`+`&&s--,u=``;break;default:t(`Unknown state`);break}}return n===Q.ParamRegExp&&t(`Unfinished custom RegExp for param "${l}"`),d(),o(),i}var Pe=`[^/]+?`,Fe={sensitive:!1,strict:!1,start:!0,end:!0},$=function(e){return e[e._multiplier=10]=`_multiplier`,e[e.Root=90]=`Root`,e[e.Segment=40]=`Segment`,e[e.SubSegment=30]=`SubSegment`,e[e.Static=40]=`Static`,e[e.Dynamic=20]=`Dynamic`,e[e.BonusCustomRegExp=10]=`BonusCustomRegExp`,e[e.BonusWildcard=-50]=`BonusWildcard`,e[e.BonusRepeatable=-20]=`BonusRepeatable`,e[e.BonusOptional=-8]=`BonusOptional`,e[e.BonusStrict=.7000000000000001]=`BonusStrict`,e[e.BonusCaseSensitive=.25]=`BonusCaseSensitive`,e}($||{}),Ie=/[.+*?^${}()[\]/\\]/g;function Le(e,t){let n=s({},Fe,t),r=[],i=n.start?`^`:``,a=[];for(let t of e){let e=t.length?[]:[$.Root];n.strict&&!t.length&&(i+=`/`);for(let r=0;r<t.length;r++){let o=t[r],s=$.Segment+(n.sensitive?$.BonusCaseSensitive:0);if(o.type===Z.Static)r||(i+=`/`),i+=o.value.replace(Ie,`\\$&`),s+=$.Static;else if(o.type===Z.Param){let{value:e,repeatable:n,optional:c,regexp:l}=o;a.push({name:e,repeatable:n,optional:c});let u=l||Pe;if(u!==Pe){s+=$.BonusCustomRegExp;try{`${u}`}catch(t){throw Error(`Invalid custom RegExp for param "${e}" (${u}): `+t.message)}}let d=n?`((?:${u})(?:/(?:${u}))*)`:`(${u})`;r||(d=c&&t.length<2?`(?:/${d})`:`/`+d),c&&(d+=`?`),i+=d,s+=$.Dynamic,c&&(s+=$.BonusOptional),n&&(s+=$.BonusRepeatable),u===`.*`&&(s+=$.BonusWildcard)}e.push(s)}r.push(e)}if(n.strict&&n.end){let e=r.length-1;r[e][r[e].length-1]+=$.BonusStrict}n.strict||(i+=`/?`),n.end?i+=`$`:n.strict&&!i.endsWith(`/`)&&(i+=`(?:/|$)`);let o=new RegExp(i,n.sensitive?``:`i`);function c(e){let t=e.match(o),n={};if(!t)return null;for(let e=1;e<t.length;e++){let r=t[e]||``,i=a[e-1];n[i.name]=r&&i.repeatable?r.split(`/`):r}return n}function l(t){let n=``,r=!1;for(let i of e){(!r||!n.endsWith(`/`))&&(n+=`/`),r=!1;for(let e of i)if(e.type===Z.Static)n+=e.value;else if(e.type===Z.Param){let{value:a,repeatable:o,optional:s}=e,c=a in t?t[a]:``;if(u(c)&&!o)throw Error(`Provided param "${a}" is an array but it is not repeatable (* or + modifiers)`);let l=u(c)?c.join(`/`):c;if(!l)if(s)i.length<2&&(n.endsWith(`/`)?n=n.slice(0,-1):r=!0);else throw Error(`Missing required param "${a}"`);n+=l}}return n||`/`}return{re:o,score:r,keys:a,parse:c,stringify:l}}function Re(e,t){let n=0;for(;n<e.length&&n<t.length;){let r=t[n]-e[n];if(r)return r;n++}return e.length<t.length?e.length===1&&e[0]===$.Static+$.Segment?-1:1:e.length>t.length?t.length===1&&t[0]===$.Static+$.Segment?1:-1:0}function ze(e,t){let n=0,r=e.score,i=t.score;for(;n<r.length&&n<i.length;){let e=Re(r[n],i[n]);if(e)return e;n++}if(Math.abs(i.length-r.length)===1){if(Be(r))return 1;if(Be(i))return-1}return i.length-r.length}function Be(e){let t=e[e.length-1];return e.length>0&&t[t.length-1]<0}var Ve={strict:!1,end:!0,sensitive:!1};function He(e,t,n){let r=s(Le(Ne(e.path),n),{record:e,parent:t,children:[],alias:[]});return t&&!r.record.aliasOf==!t.record.aliasOf&&t.children.push(r),r}function Ue(e,t){let n=[],r=new Map;t=d(Ve,t);function i(e){return r.get(e)}function a(e,n,r){let i=!r,c=Ge(e);c.aliasOf=r&&r.record;let f=d(t,e),p=[c];if(`alias`in e){let t=typeof e.alias==`string`?[e.alias]:e.alias;for(let e of t)p.push(Ge(s({},c,{components:r?r.record.components:c.components,path:e,aliasOf:r?r.record:c})))}let m,h;for(let t of p){let{path:s}=t;if(n&&s[0]!==`/`){let e=n.record.path,r=e[e.length-1]===`/`?``:`/`;t.path=n.record.path+(s&&r+s)}if(m=He(t,n,f),r?r.alias.push(m):(h||=m,h!==m&&h.alias.push(m),i&&e.name&&!qe(m)&&o(e.name)),Ze(m)&&u(m),c.children){let e=c.children;for(let t=0;t<e.length;t++)a(e[t],m,r&&r.children[t])}r||=m}return h?()=>{o(h)}:l}function o(e){if(ge(e)){let t=r.get(e);t&&(r.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(o),t.alias.forEach(o))}else{let t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&r.delete(e.record.name),e.children.forEach(o),e.alias.forEach(o))}}function c(){return n}function u(e){let t=Ye(e,n);n.splice(t,0,e),e.record.name&&!qe(e)&&r.set(e.record.name,e)}function f(e,t){let i,a={},o,c;if(`name`in e&&e.name){if(i=r.get(e.name),!i)throw W(H.MATCHER_NOT_FOUND,{location:e});c=i.record.name,a=s(We(t.params,i.keys.filter(e=>!e.optional).concat(i.parent?i.parent.keys.filter(e=>e.optional):[]).map(e=>e.name)),e.params&&We(e.params,i.keys.map(e=>e.name))),o=i.stringify(a)}else if(e.path!=null)o=e.path,i=n.find(e=>e.re.test(o)),i&&(a=i.parse(o),c=i.record.name);else{if(i=t.name?r.get(t.name):n.find(e=>e.re.test(t.path)),!i)throw W(H.MATCHER_NOT_FOUND,{location:e,currentLocation:t});c=i.record.name,a=s({},t.params,e.params),o=i.stringify(a)}let l=[],u=i;for(;u;)l.unshift(u.record),u=u.parent;return{name:c,path:o,params:a,matched:l,meta:Je(l)}}e.forEach(e=>a(e));function p(){n.length=0,r.clear()}return{addRoute:a,resolve:f,removeRoute:o,clearRoutes:p,getRoutes:c,getRecordMatcher:i}}function We(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}function Ge(e){let t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:Ke(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:`components`in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,`mods`,{value:{}}),t}function Ke(e){let t={},n=e.props||!1;if(`component`in e)t.default=n;else for(let r in e.components)t[r]=typeof n==`object`?n[r]:n;return t}function qe(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function Je(e){return e.reduce((e,t)=>s(e,t.meta),{})}function Ye(e,t){let n=0,r=t.length;for(;n!==r;){let i=n+r>>1;ze(e,t[i])<0?r=i:n=i+1}let i=Xe(e);return i&&(r=t.lastIndexOf(i,r-1)),r}function Xe(e){let t=e;for(;t=t.parent;)if(Ze(t)&&ze(e,t)===0)return t}function Ze({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function Qe(e){let t=(0,X.inject)(be),n=(0,X.inject)(xe),r=(0,X.computed)(()=>{let n=(0,X.unref)(e.to);return t.resolve(n)}),i=(0,X.computed)(()=>{let{matched:e}=r.value,{length:t}=e,i=e[t-1],a=n.matched;if(!i||!a.length)return-1;let o=a.findIndex(A.bind(null,i));if(o>-1)return o;let s=rt(e[t-2]);return t>1&&rt(i)===s&&a[a.length-1].path!==s?a.findIndex(A.bind(null,e[t-2])):o}),a=(0,X.computed)(()=>i.value>-1&&nt(n.params,r.value.params)),o=(0,X.computed)(()=>i.value>-1&&i.value===n.matched.length-1&&j(n.params,r.value.params));function s(n={}){if(tt(n)){let n=t[(0,X.unref)(e.replace)?`replace`:`push`]((0,X.unref)(e.to)).catch(l);return e.viewTransition&&typeof document<`u`&&`startViewTransition`in document&&document.startViewTransition(()=>n),n}return Promise.resolve()}return{route:r,href:(0,X.computed)(()=>r.value.href),isActive:a,isExactActive:o,navigate:s}}function $e(e){return e.length===1?e[0]:e}var et=(0,X.defineComponent)({name:`RouterLink`,compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:`page`},viewTransition:Boolean},useLink:Qe,setup(e,{slots:t}){let n=(0,X.reactive)(Qe(e)),{options:r}=(0,X.inject)(be),i=(0,X.computed)(()=>({[it(e.activeClass,r.linkActiveClass,`router-link-active`)]:n.isActive,[it(e.exactActiveClass,r.linkExactActiveClass,`router-link-exact-active`)]:n.isExactActive}));return()=>{let r=t.default&&$e(t.default(n));return e.custom?r:(0,X.h)(`a`,{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:i.value},r)}}});function tt(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){let t=e.currentTarget.getAttribute(`target`);if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function nt(e,t){for(let n in t){let r=t[n],i=e[n];if(typeof r==`string`){if(r!==i)return!1}else if(!u(i)||i.length!==r.length||r.some((e,t)=>e!==i[t]))return!1}return!0}function rt(e){return e?e.aliasOf?e.aliasOf.path:e.path:``}var it=(e,t,n)=>e??t??n,at=(0,X.defineComponent)({name:`RouterView`,inheritAttrs:!1,props:{name:{type:String,default:`default`},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){let r=(0,X.inject)(Se),i=(0,X.computed)(()=>e.route||r.value),a=(0,X.inject)(q,0),o=(0,X.computed)(()=>{let e=(0,X.unref)(a),{matched:t}=i.value,n;for(;(n=t[e])&&!n.components;)e++;return e}),c=(0,X.computed)(()=>i.value.matched[o.value]);(0,X.provide)(q,(0,X.computed)(()=>o.value+1)),(0,X.provide)(K,c),(0,X.provide)(Se,i);let l=(0,X.ref)();return(0,X.watch)(()=>[l.value,c.value,e.name],([e,t,n],[r,i,a])=>{t&&(t.instances[n]=e,i&&i!==t&&e&&e===r&&(t.leaveGuards.size||(t.leaveGuards=i.leaveGuards),t.updateGuards.size||(t.updateGuards=i.updateGuards))),e&&t&&(!i||!A(t,i)||!r)&&(t.enterCallbacks[n]||[]).forEach(t=>t(e))},{flush:`post`}),()=>{let r=i.value,a=e.name,o=c.value,u=o&&o.components[a];if(!u)return ot(n.default,{Component:u,route:r});let d=o.props[a],f=d?d===!0?r.params:typeof d==`function`?d(r):d:null,p=(0,X.h)(u,s({},f,t,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(o.instances[a]=null)},ref:l}));return ot(n.default,{Component:p,route:r})||p}}});function ot(e,t){if(!e)return null;let n=e(t);return n.length===1?n[0]:n}var st=at;function ct(e){let t=Ue(e.routes,e),n=e.parseQuery||_e,r=e.stringifyQuery||ve,a=e.history,o=J(),d=J(),f=J(),p=(0,X.shallowRef)(P),m=P;i&&e.scrollBehavior&&`scrollRestoration`in history&&(history.scrollRestoration=`manual`);let h=c.bind(null,e=>``+e),g=c.bind(null,oe),_=c.bind(null,T);function ee(e,n){let r,i;return ge(e)?(r=t.getRecordMatcher(e),i=n):i=e,t.addRoute(i,r)}function te(e){let n=t.getRecordMatcher(e);n&&t.removeRoute(n)}function ne(){return t.getRoutes().map(e=>e.record)}function re(e){return!!t.getRecordMatcher(e)}function v(e,i){if(i=s({},i||p.value),typeof e==`string`){let r=O(n,e,i.path),o=t.resolve({path:r.path},i),c=a.createHref(r.fullPath);return s(r,o,{params:_(o.params),hash:T(r.hash),redirectedFrom:void 0,href:c})}let o;if(e.path!=null)o=s({},e,{path:O(n,e.path,i.path).path});else{let t=s({},e.params);for(let e in t)t[e]??delete t[e];o=s({},e,{params:g(t)}),i.params=g(i.params)}let c=t.resolve(o,i),l=e.hash||``;c.params=h(_(c.params));let u=se(r,s({},e,{hash:ie(l),path:c.path})),d=a.createHref(u);return s({fullPath:u,hash:l,query:r===ve?ye(e.query):e.query||{}},c,{redirectedFrom:void 0,href:d})}function y(e){return typeof e==`string`?O(n,e,p.value.path):s({},e)}function b(e,t){if(m!==e)return W(H.NAVIGATION_CANCELLED,{from:t,to:e})}function x(e){return w(e)}function S(e){return x(s(y(e),{replace:!0}))}function C(e,t){let n=e.matched[e.matched.length-1];if(n&&n.redirect){let{redirect:r}=n,i=typeof r==`function`?r(e,t):r;return typeof i==`string`&&(i=i.includes(`?`)||i.includes(`#`)?i=y(i):{path:i},i.params={}),s({query:e.query,hash:e.hash,params:i.path==null?e.params:{}},i)}}function w(e,t){let n=m=v(e),i=p.value,a=e.state,o=e.force,c=e.replace===!0,l=C(n,i);if(l)return w(s(y(l),{state:typeof l==`object`?s({},a,l.state):a,force:o,replace:c}),t||n);let u=n;u.redirectedFrom=t;let d;return!o&&ce(r,i,n)&&(d=W(H.NAVIGATION_DUPLICATED,{to:u,from:i}),de(i,i,!0,!1)),(d?Promise.resolve(d):D(u,i)).catch(e=>G(e)?G(e,H.NAVIGATION_GUARD_REDIRECT)?e:R(e):L(e,u,i)).then(e=>{if(e){if(G(e,H.NAVIGATION_GUARD_REDIRECT))return w(s({replace:c},y(e.to),{state:typeof e.to==`object`?s({},a,e.to.state):a,force:o}),t||u)}else e=A(u,i,!0,c,a);return k(u,i,e),e})}function ae(e,t){let n=b(e,t);return n?Promise.reject(n):Promise.resolve()}function E(e){let t=U.values().next().value;return t&&typeof t.runWithContext==`function`?t.runWithContext(e):e()}function D(e,t){let n,[r,i,a]=we(e,t);n=Ce(r.reverse(),`beforeRouteLeave`,e,t);for(let i of r)i.leaveGuards.forEach(r=>{n.push(Y(r,e,t))});let s=ae.bind(null,e,t);return n.push(s),q(n).then(()=>{n=[];for(let r of o.list())n.push(Y(r,e,t));return n.push(s),q(n)}).then(()=>{n=Ce(i,`beforeRouteUpdate`,e,t);for(let r of i)r.updateGuards.forEach(r=>{n.push(Y(r,e,t))});return n.push(s),q(n)}).then(()=>{n=[];for(let r of a)if(r.beforeEnter)if(u(r.beforeEnter))for(let i of r.beforeEnter)n.push(Y(i,e,t));else n.push(Y(r.beforeEnter,e,t));return n.push(s),q(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Ce(a,`beforeRouteEnter`,e,t,E),n.push(s),q(n))).then(()=>{n=[];for(let r of d.list())n.push(Y(r,e,t));return n.push(s),q(n)}).catch(e=>G(e,H.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function k(e,t,n){f.list().forEach(r=>E(()=>r(e,t,n)))}function A(e,t,n,r,o){let c=b(e,t);if(c)return c;let l=t===P,u=i?history.state:{};n&&(r||l?a.replace(e.fullPath,s({scroll:l&&u&&u.scroll},o)):a.push(e.fullPath,o)),p.value=e,de(e,t,n,l),R()}let j;function le(){j||=a.listen((e,t,n)=>{if(!K.listening)return;let r=v(e),o=C(r,K.currentRoute.value);if(o){w(s(o,{replace:!0,force:!0}),r).catch(l);return}m=r;let c=p.value;i&&me(pe(c.fullPath,n.delta),z()),D(r,c).catch(e=>G(e,H.NAVIGATION_ABORTED|H.NAVIGATION_CANCELLED)?e:G(e,H.NAVIGATION_GUARD_REDIRECT)?(w(s(y(e.to),{force:!0}),r).then(e=>{G(e,H.NAVIGATION_ABORTED|H.NAVIGATION_DUPLICATED)&&!n.delta&&n.type===F.pop&&a.go(-1,!1)}).catch(l),Promise.reject()):(n.delta&&a.go(-n.delta,!1),L(e,r,c))).then(e=>{e||=A(r,c,!1),e&&(n.delta&&!G(e,H.NAVIGATION_CANCELLED)?a.go(-n.delta,!1):n.type===F.pop&&G(e,H.NAVIGATION_ABORTED|H.NAVIGATION_DUPLICATED)&&a.go(-1,!1)),k(r,c,e)}).catch(l)})}let M=J(),N=J(),I;function L(e,t,n){R(e);let r=N.list();return r.length?r.forEach(r=>r(e,t,n)):console.error(e),Promise.reject(e)}function ue(){return I&&p.value!==P?Promise.resolve():new Promise((e,t)=>{M.add([e,t])})}function R(e){return I||(I=!e,le(),M.list().forEach(([t,n])=>e?n(e):t()),M.reset()),e}function de(t,n,r,a){let{scrollBehavior:o}=e;if(!i||!o)return Promise.resolve();let s=!r&&he(pe(t.fullPath,0))||(a||!r)&&history.state&&history.state.scroll||null;return(0,X.nextTick)().then(()=>o(t,n,s)).then(e=>e&&fe(e)).catch(e=>L(e,t,n))}let B=e=>a.go(e),V,U=new Set,K={currentRoute:p,listening:!0,addRoute:ee,removeRoute:te,clearRoutes:t.clearRoutes,hasRoute:re,getRoutes:ne,resolve:v,options:e,push:x,replace:S,go:B,back:()=>B(-1),forward:()=>B(1),beforeEach:o.add,beforeResolve:d.add,afterEach:f.add,onError:N.add,isReady:ue,install(e){e.component(`RouterLink`,et),e.component(`RouterView`,st),e.config.globalProperties.$router=K,Object.defineProperty(e.config.globalProperties,`$route`,{enumerable:!0,get:()=>(0,X.unref)(p)}),i&&!V&&p.value===P&&(V=!0,x(a.location).catch(e=>{}));let t={};for(let e in P)Object.defineProperty(t,e,{get:()=>p.value[e],enumerable:!0});e.provide(be,K),e.provide(xe,(0,X.shallowReactive)(t)),e.provide(Se,p);let n=e.unmount;U.add(e),e.unmount=function(){U.delete(e),U.size<1&&(m=P,j&&j(),j=null,p.value=P,V=!1,I=!1),n()}}};function q(e){return e.reduce((e,t)=>e.then(()=>E(t)),Promise.resolve())}return K}function lt(e){return(0,X.inject)(xe)}var ut=[{remote:{module:`app1`,entry:`http://localhost:5021/remoteEntry.js`},route:{name:`app1`,path:`/app-1`,meta:{title:`Micro App 1`}}},{remote:{module:`app2`,entry:`http://localhost:5022/remoteEntry.js`},route:{name:`app2`,path:`/app-2`,meta:{title:`Micro App 2`}}}];const dt=()=>ut.map(e=>e.remote);var ft=ut,pt=t();const mt={install:(e,t)=>{let n=t.map(e=>({name:e.module,entry:e.entry,type:`module`}));console.log(`initfederation`),(0,pt.registerRemotes)(n)}},ht=()=>({loadRemote:async e=>{let t=await(0,pt.loadRemote)(`${e}/entry`);return{name:e,mount:t.mount,unmount:t.unmount}}});export{ct as a,r as c,ft as i,ht as n,Ae as o,dt as r,lt as s,mt as t};

This can be reproduced with repo
https://github.com/lmlong-huynh/micro-frontend-sample
but bump versions in package.json

}
// Call existing manualChunks if it exists
if (typeof existingManualChunks === 'function') {
return existingManualChunks(id, meta);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if this part could cause breaking changes for anyone relying on manual checks since a set of vite plugins (line 118-120) won't be checked anymore.

@ZiuChen
Copy link

ZiuChen commented Dec 16, 2025

I've also encountered similar deadlock issues caused by circular dependencies, which I resolved by configuring manualChunks:

The Module Federation initialization logic was bundled into another business chunk, creating a circular dependency: hostInit -> bizChunk -> remoteEntry -> hostInit, which in turn caused the initPromise to never be resolved.

My solution was to package runtimeInit separately:

// vite.config.ts
manualChunks: (id) => {
  if (id.includes('Host__mf_v__runtimeInit__mf_v__')) {
    // Module Federation runtime init chunk
    return 'runtimeInit';
  }
}

But my thought is: if the circular dependency issue isn't caused by the module-federation library, it shouldn't be the library's responsibility to fix it either. Of course, not yet.

@sabov
Copy link
Contributor

sabov commented Dec 16, 2025

if the circular dependency issue isn't caused by the module-federation library, it shouldn't be the library's responsibility to fix it either.

I think in this case it's partially caused by the library's architecture. Maybe there is a way to change how remote modules are loaded to make sure the deadlock never happens regardless of how vite bundles things. E.g. instead of waiting for init(), we could queue loadShare requests immediately, execute the queue when init() is called and return a promise that resolves when the queue is processed. What do you think?

@sabov sabov mentioned this pull request Dec 17, 2025
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ Vite 7 Support

5 participants