Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
"fix: Vite 7/Rolldown compatibility - convert shared/remote modules t…
…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 #320"
  • Loading branch information
DallasCarraher committed Dec 10, 2025
commit 9b1335a8451d53325d062723363d84447cb0c476
13 changes: 10 additions & 3 deletions src/virtualModules/virtualRemotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const cacheRemoteMap: {
export const LOAD_REMOTE_TAG = '__loadRemote__';
export function getRemoteVirtualModule(remote: string, command: string) {
if (!cacheRemoteMap[remote]) {
cacheRemoteMap[remote] = new VirtualModule(remote, LOAD_REMOTE_TAG, '.js');
// Use .mjs extension to ensure ESM treatment by bundlers
cacheRemoteMap[remote] = new VirtualModule(remote, LOAD_REMOTE_TAG, '.mjs');
cacheRemoteMap[remote].writeSync(generateRemotes(remote, command));
}
const virtual = cacheRemoteMap[remote];
Expand All @@ -24,10 +25,16 @@ export function getUsedRemotesMap() {
return usedRemotesMap;
}
export function generateRemotes(id: string, command: string) {
// Generate ESM-compatible code to fix Vite 7/Rolldown compatibility
// The previous CJS code (require + module.exports + top-level await) caused syntax errors
// because Rolldown wraps CJS in a function where top-level await is invalid
return `
const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
// Use dynamic import instead of require for ESM compatibility
const runtimeModule = await import("${virtualRuntimeInitStatus.getImportId()}")
const {initPromise} = runtimeModule
const res = initPromise.then(runtime => runtime.loadRemote(${JSON.stringify(id)}))
const exportModule = ${command !== 'build' ? '/*mf top-level-await placeholder replacement mf*/' : 'await '}initPromise.then(_ => res)
module.exports = exportModule
// Use ESM export instead of module.exports to avoid CJS wrapper issues
export default exportModule
`;
}
10 changes: 8 additions & 2 deletions src/virtualModules/virtualRuntimeInitStatus.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import VirtualModule from '../utils/VirtualModule';
export const virtualRuntimeInitStatus = new VirtualModule('runtimeInit');
// Use .mjs extension to ensure ESM treatment by bundlers
export const virtualRuntimeInitStatus = new VirtualModule('runtimeInit', '__mf_v__', '.mjs');
export function writeRuntimeInitStatus() {
// Use globalThis singleton to ensure only one initPromise exists
const globalKey = `__mf_init__${virtualRuntimeInitStatus.getImportId()}__`;
// Generate ESM-compatible code to fix Vite 7/Rolldown compatibility
// Use named ESM exports instead of module.exports for proper dynamic import support
virtualRuntimeInitStatus.writeSync(`
const globalKey = ${JSON.stringify(globalKey)}
if (!globalThis[globalKey]) {
Expand All @@ -17,6 +20,9 @@ export function writeRuntimeInitStatus() {
initReject
}
}
module.exports = globalThis[globalKey]
// Use ESM named exports instead of module.exports for compatibility with dynamic import()
export const initPromise = globalThis[globalKey].initPromise
export const initResolve = globalThis[globalKey].initResolve
export const initReject = globalThis[globalKey].initReject
`);
}
13 changes: 10 additions & 3 deletions src/virtualModules/virtualShared_preBuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,22 @@ export const LOAD_SHARE_TAG = '__loadShare__';
const loadShareCacheMap: Record<string, VirtualModule> = {};
export function getLoadShareModulePath(pkg: string): string {
if (!loadShareCacheMap[pkg])
loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, '.js');
// Use .mjs extension to ensure ESM treatment by bundlers
loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, '.mjs');
const filepath = loadShareCacheMap[pkg].getPath();
return filepath;
}
export function writeLoadShareModule(pkg: string, shareItem: ShareItem, command: string) {
// Generate ESM-compatible code to fix Vite 7/Rolldown compatibility
// The previous CJS code (require + module.exports + top-level await) caused syntax errors
// because Rolldown wraps CJS in a function where top-level await is invalid
loadShareCacheMap[pkg].writeSync(`
;() => import(${JSON.stringify(getPreBuildLibImportId(pkg))}).catch(() => {});
// dev uses dynamic import to separate chunks
${command !== 'build' ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ''}
const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
// Use dynamic import instead of require for ESM compatibility
const runtimeModule = await import("${virtualRuntimeInitStatus.getImportId()}")
const {initPromise} = runtimeModule
const res = initPromise.then(runtime => runtime.loadShare(${JSON.stringify(pkg)}, {
customShareInfo: {shareConfig:{
singleton: ${shareItem.shareConfig.singleton},
Expand All @@ -50,6 +56,7 @@ export function writeLoadShareModule(pkg: string, shareItem: ShareItem, command:
}}
}))
const exportModule = ${command !== 'build' ? '/*mf top-level-await placeholder replacement mf*/' : 'await '}res.then(factory => factory())
module.exports = exportModule
// Use ESM export instead of module.exports to avoid CJS wrapper issues
export default exportModule
`);
}
Loading