Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,8 @@
"vite": "^5.4.3",
"vitest": "^2.1.1",
"wait-on": "^8.0.1"
},
"peerDependencies": {
"vite": "*"
}
}
7 changes: 5 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,12 @@ function federation(mfUserOptions: ModuleFederationOptions): Plugin[] {
},
});
const virtualDir = options.virtualModuleDir || '__mf__virtual';
const virtualDirPath = VirtualModule.getVirtualModuleDirPath();
(config.resolve as any).alias.push({
find: new RegExp(`^${virtualDir}/`),
replacement: `${virtualDirPath}/`,
});
config.optimizeDeps?.include?.push('@module-federation/runtime');
config.optimizeDeps?.include?.push(virtualDir);
config.optimizeDeps?.needsInterop?.push(virtualDir);
config.optimizeDeps?.needsInterop?.push(getLocalSharedImportMapPath());
},
},
Expand Down
41 changes: 16 additions & 25 deletions src/utils/VirtualModule.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
import { existsSync, mkdirSync, writeFile, writeFileSync } from 'fs';
import { dirname, join, parse, resolve, basename } from 'pathe';
import { basename, join, resolve } from 'pathe';
import { packageNameDecode, packageNameEncode } from '../utils/packageNameUtils';
import { getNormalizeModuleFederationOptions } from './normalizeModuleFederationOptions';

// Cache root path
let rootDir: string | undefined;

function findNodeModulesDir(root: string = process.cwd()) {
let currentDir = root;

while (currentDir !== parse(currentDir).root) {
const nodeModulesPath = join(currentDir, 'node_modules');
if (existsSync(nodeModulesPath)) {
return nodeModulesPath;
}
currentDir = dirname(currentDir);
}

return '';
}

// Cache nodeModulesDir result to avoid repeated calculations
let cachedNodeModulesDir: string | undefined;

function getNodeModulesDir() {
if (!cachedNodeModulesDir) {
cachedNodeModulesDir = findNodeModulesDir(rootDir);
if (cachedNodeModulesDir) {
return cachedNodeModulesDir;
}
const targetRoot = rootDir || process.cwd();
const nodeModulesPath = join(targetRoot, 'node_modules');
if (!existsSync(nodeModulesPath)) {
mkdirSync(nodeModulesPath, { recursive: true });
}
cachedNodeModulesDir = nodeModulesPath;
return cachedNodeModulesDir;
Comment on lines +16 to 22
Copy link
Author

Choose a reason for hiding this comment

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

We are using vite project's root instead of traversing for existing folder because pnp doesn't generate node_modules and this seems more natural

Copy link
Collaborator

@gioboa gioboa Dec 24, 2025

Choose a reason for hiding this comment

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

I see, I'm not sure if this is working on monorepo projects. cc @Xeikim you added this fix long time ago for monorepos.

Copy link
Author

@ha1fstack ha1fstack Dec 25, 2025

Choose a reason for hiding this comment

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

The original problem was that rootDir find traversal was using process.cwd not the actual vite project's root
We are still using vite's project rootDir (fixed by #256) but only omitting the traversal part - so it seems fine to me.

Copy link
Collaborator

Choose a reason for hiding this comment

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

findNodeModulesDir is traversing upwards from a starting directory to find the correct path though.

}

Expand Down Expand Up @@ -89,18 +81,17 @@ export default class VirtualModule {
const virtualPackagePath = resolve(nodeModulesDir, virtualModuleDir);

if (!existsSync(virtualPackagePath)) {
mkdirSync(virtualPackagePath);
mkdirSync(virtualPackagePath, { recursive: true });
writeFileSync(resolve(virtualPackagePath, 'empty.js'), '');
writeFileSync(
resolve(virtualPackagePath, 'package.json'),
JSON.stringify({
name: virtualModuleDir,
main: 'empty.js',
})
);
}
}

static getVirtualModuleDirPath() {
const nodeModulesDir = getNodeModulesDir();
const { virtualModuleDir } = getNormalizeModuleFederationOptions();
return resolve(nodeModulesDir, virtualModuleDir);
}

static findModule(tag: string, str: string = ''): VirtualModule | undefined {
if (!patternMap[tag])
patternMap[tag] = new RegExp(`(.*${packageNameEncode(tag)}(.+?)${packageNameEncode(tag)}.*)`);
Expand Down
8 changes: 6 additions & 2 deletions src/utils/normalizeModuleFederationOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function removePathFromNpmPackage(packageString: string): string {
*/
function searchPackageVersion(sharedName: string): string | undefined {
try {
const sharedPath = require.resolve(sharedName);
const sharedPath = require.resolve(sharedName, { paths: [process.cwd()] });
let potentialPackageJsonDir = path.dirname(sharedPath);
const rootDir = path.parse(potentialPackageJsonDir).root;
while (
Expand Down Expand Up @@ -168,7 +168,11 @@ function normalizeShareItem(
let version: string | undefined;
try {
try {
version = require(path.join(removePathFromNpmPackage(key), 'package.json')).version;
version = require(
require.resolve(path.join(removePathFromNpmPackage(key), 'package.json'), {
paths: [process.cwd()],
})
).version;
} catch (e1) {
try {
const localPath = path.join(
Expand Down