Skip to content
This repository was archived by the owner on Feb 15, 2026. It is now read-only.
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
10 changes: 5 additions & 5 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@
},
"peerDependencies": {
"@babel/types": "^7.25.0",
"metro": "^0.82.1",
"metro-config": "^0.82.1",
"metro-file-map": "^0.82.1",
"metro-resolver": "^0.82.1",
"metro-source-map": "^0.82.1",
"metro": "^0.82.1 || ^0.83.0",
"metro-config": "^0.82.1 || ^0.83.0",
"metro-file-map": "^0.82.1 || ^0.83.0",
"metro-resolver": "^0.82.1 || ^0.83.0",
"metro-source-map": "^0.82.1 || ^0.83.0",
Comment on lines +55 to +59
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should not be necessary since the existing ^0.82.1 matches 0.83.0 or higher already

"react": ">=19.0.0",
"react-native": ">=0.79.0"
},
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/commands/bundle-host/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import path from 'node:path';
import util from 'node:util';
import Server from 'metro/src/Server';
import type { RequestOptions } from 'metro/src/shared/types';
import type { ModuleFederationConfigNormalized } from '../../types';
import { CLIError } from '../../utils/errors';
import { type RequestOptions, Server } from '../../utils/metro-compat';
import type { Config } from '../types';
import { createResolver } from '../utils/create-resolver';
import { getCommunityCliPlugin } from '../utils/get-community-plugin';
Expand Down Expand Up @@ -54,7 +53,10 @@ async function bundleFederatedHost(
communityCliPlugin.unstable_buildBundleWithConfig;

return buildBundleWithConfig(args, config, {
build: async (server: Server, requestOpts: RequestOptions) => {
build: async (
server: InstanceType<typeof Server>,
requestOpts: RequestOptions
) => {
// setup enhance middleware to trigger virtual modules setup
config.server.enhanceMiddleware(server.processRequest, server);
const resolver = await createResolver(server, args.platform);
Expand Down
12 changes: 9 additions & 3 deletions packages/core/src/commands/bundle-remote/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import path from 'node:path';
import { pathToFileURL } from 'node:url';
import util from 'node:util';
import { mergeConfig } from 'metro';
import Server from 'metro/src/Server';
import type { OutputOptions, RequestOptions } from 'metro/src/shared/types';
import type { ModuleFederationConfigNormalized } from '../../types';
import { CLIError } from '../../utils/errors';
import {
type OutputOptions,
type RequestOptions,
Server,
} from '../../utils/metro-compat';
import type { Config } from '../types';
import { createModulePathRemapper } from '../utils/create-module-path-remapper';
import { createResolver } from '../utils/create-resolver';
Expand Down Expand Up @@ -39,7 +42,10 @@ interface BundleRequestOptions extends RequestOptions {
sourceUrl: string;
}

async function buildBundle(server: Server, requestOpts: BundleRequestOptions) {
async function buildBundle(
server: InstanceType<typeof Server>,
requestOpts: BundleRequestOptions
) {
const bundle = await server.build({
...Server.DEFAULT_BUNDLE_OPTIONS,
...requestOpts,
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/commands/utils/create-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type Server from 'metro/src/Server';
import type { Server } from '../../utils/metro-compat';

/**
* Creates a resolver utility that mirrors Metro's bundling resolution behavior.
Expand All @@ -14,7 +14,10 @@ import type Server from 'metro/src/Server';
* @param platform - The target platform for resolution (e.g., 'ios', 'android', null for default)
* @returns The resolver object with a resolve method that takes source and target paths
*/
export async function createResolver(server: Server, platform: string | null) {
export async function createResolver(
server: InstanceType<typeof Server>,
platform: string | null
) {
const bundler = server.getBundler().getBundler();
const depGraph = await bundler.getDependencyGraph();

Expand Down
9 changes: 6 additions & 3 deletions packages/core/src/commands/utils/get-community-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { ConfigT } from 'metro-config';
import type Server from 'metro/src/Server';
import type { OutputOptions, RequestOptions } from 'metro/src/shared/types';
import { CLIError } from '../../utils/errors';
import type {
OutputOptions,
RequestOptions,
Server,
} from '../../utils/metro-compat';

interface Command {
name: string;
Expand All @@ -21,7 +24,7 @@ interface CommunityCliPlugin {
config: ConfigT,
bundleImpl: {
build: (
server: Server,
server: InstanceType<typeof Server>,
requestOpts: RequestOptions
) => Promise<{ code: string; map: string }>;
save: (
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/commands/utils/save-bundle-and-map.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { promises as fs } from 'node:fs';
import util from 'node:util';
import type { MixedSourceMap } from 'metro-source-map';
import relativizeSourceMapInline from 'metro/src/lib/relativizeSourceMap';
import type { OutputOptions } from 'metro/src/shared/types';
import {
type OutputOptions,
relativizeSourceMapInline,
} from '../../utils/metro-compat';

function relativizeSerializedMap(
map: string,
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/plugin/serializer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import path from 'node:path';
import type { Module, ReadOnlyGraph, SerializerOptions } from 'metro';
import type { SerializerConfigT } from 'metro-config';
import baseJSBundle from 'metro/src/DeltaBundler/Serializers/baseJSBundle';
import CountingSet from 'metro/src/lib/CountingSet';
import bundleToString from 'metro/src/lib/bundleToString';
import type { ModuleFederationConfigNormalized, Shared } from '../types';
import { ConfigError } from '../utils/errors';
import {
CountingSet,
baseJSBundle,
bundleToString,
} from '../utils/metro-compat';

type CustomSerializer = SerializerConfigT['customSerializer'];

Expand Down
55 changes: 55 additions & 0 deletions packages/core/src/utils/metro-compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Metro Compatibility Layer
*
* Provides backwards-compatible imports for Metro 0.82 and 0.83+
*
* Metro 0.83 introduced a restrictive `exports` field that only allows
* `metro/private/*` paths instead of direct `metro/src/*` imports.
*
* This module dynamically resolves the correct import path based on the
* installed Metro version, ensuring compatibility with both versions.
*/

/**
* Attempts to import from Metro 0.83 format first, falls back to 0.82 format
*/
function tryImport(metro83Path: string, metro82Path: string) {
try {
return require(metro83Path);
} catch {
return require(metro82Path);
}
}

// Server class
export const Server = tryImport(
'metro/private/Server',
'metro/src/Server'
).default;

// DeltaBundler Serializers
export const baseJSBundle = tryImport(
'metro/private/DeltaBundler/Serializers/baseJSBundle',
'metro/src/DeltaBundler/Serializers/baseJSBundle'
).default;

// Utility classes
export const CountingSet = tryImport(
'metro/private/lib/CountingSet',
'metro/src/lib/CountingSet'
).default;

// Bundle utilities
export const bundleToString = tryImport(
'metro/private/lib/bundleToString',
'metro/src/lib/bundleToString'
).default;

export const relativizeSourceMapInline = tryImport(
'metro/private/lib/relativizeSourceMap',
'metro/src/lib/relativizeSourceMap'
).relativizeSourceMapInline;

// Re-export types - these come from metro/src/shared/types in both versions
// The types themselves are available through the main 'metro' package export
export type { RequestOptions, OutputOptions } from 'metro/src/shared/types';
16 changes: 11 additions & 5 deletions packages/core/src/utils/vm-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import type {
TransformerConfigT,
} from 'metro-config';
import type { FileSystem } from 'metro-file-map';
import type MetroServer from 'metro/src/Server';
import type { Server as MetroServer } from './metro-compat';

type EnhanceMiddleware = ServerConfigT['enhanceMiddleware'];
type GetTransformOptions = TransformerConfigT['getTransformOptions'];
type Bundler = ReturnType<ReturnType<MetroServer['getBundler']>['getBundler']>;
type Bundler = ReturnType<
ReturnType<InstanceType<typeof MetroServer>['getBundler']>['getBundler']
>;

export class VirtualModuleManager {
private setupFinished: Promise<boolean> | null = null;
Expand Down Expand Up @@ -69,8 +71,8 @@ export class VirtualModuleManager {
setup(bundler: Bundler) {
this.setupFinished = (async () => {
const graph = await bundler.getDependencyGraph();
// @ts-expect-error incomplete types
this.ensureFileSystemPatched(graph._fileSystem);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.ensureFileSystemPatched((graph as any)._fileSystem);
this.ensureBundlerPatched(bundler);
return true;
})();
Expand Down Expand Up @@ -104,7 +106,11 @@ export class VirtualModuleManager {
}
const transformFile = bundler.transformFile.bind(bundler);

bundler.transformFile = async (filePath, transformOptions, fileBuffer) => {
bundler.transformFile = async (
filePath: string,
transformOptions: any,
fileBuffer?: Buffer
) => {
let buffer = fileBuffer;
const virtualModule = this.virtualModules.get(filePath);

Expand Down
Loading