# React Native 多 Bundle 系统

多 Bundle 系统提供了模块化的代码分割方案，支持将 React Native 应用拆分为多个独立的 bundle，实现按需加载和独立更新。

## 快速接入

### 1. 初始化多 Bundle 系统

在应用入口（通常是 `App.tsx`）中调用 `initMultiBundle`：

```typescript
import { initMultiBundle } from './src/multi-bundle/init';
import { LocalBundleManager } from './src/multi-bundle/LocalBundleManager';
import { Platform } from 'react-native';

function App() {
  const [ready, setReady] = useState(false);

  useEffect(() => {
    async function bootstrap() {
      const result = await initMultiBundle({
        // 模块路径规则（glob 模式）
        modulePaths: ['src/modules/**'],
        
        // 共享依赖路径（这些代码会被打包到主 bundle）
        sharedDependencies: ['src/multi-bundle/**', 'src/navigation/**'],
        
        // Manifest 提供者（可选，默认使用 LocalBundleManager）
        manifestProvider: async () => {
          return await LocalBundleManager.getCurrentBundleManifest();
        },
        
        // 预加载模块列表（可选）
        preloadModules: ['settings'],
        
        // 开发服务器配置（可选）
        devServer: {
          host: Platform.OS === 'android' ? '10.0.2.2' : 'localhost',
          port: 8081,
        },
        
        // 错误处理回调（可选）
        onError: (error) => {
          console.error('MultiBundle error:', error);
        },
      });

      if (result.success) {
        setReady(true);
      }
    }

    bootstrap();
  }, []);

  if (!ready) {
    return <LoadingScreen />;
  }

  // ... 其余代码
}
```

### 2. 使用模块路由

#### 方式一：使用 `createModuleRouteLoader` + `getComponent`（推荐，React Navigation v7+）

这是推荐的方式，支持真正的懒加载，组件只在导航到该路由时才被创建：

```typescript
import { createModuleRouteLoader } from './src/multi-bundle/createModuleRouteLoader';

// 创建路由加载器函数
export const createHomeScreen = createModuleRouteLoader('home', 'Home');
export const createDetailScreen = createModuleRouteLoader('details', 'Details');
```

在 React Navigation 中使用：

```tsx
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createHomeScreen, createDetailScreen } from './src/navigation/moduleRoutes';

const Stack = createNativeStackNavigator();

function App() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Home" getComponent={createHomeScreen} />
      <Stack.Screen name="Details" getComponent={createDetailScreen} />
    </Stack.Navigator>
  );
}
```

**优势**：
- 真正的懒加载：组件只在导航到该路由时才创建
- 减少初始内存占用
- 符合 React Navigation 最佳实践

#### 方式二：使用路由注册系统

```typescript
import { registerModuleRoute, getModuleRoute } from './src/multi-bundle/routeRegistry';

// 注册路由
registerModuleRoute('home', 'Home');
registerModuleRoute('details', 'Details');

// 获取路由组件
const HomeScreen = getModuleRoute('home', 'Home');
```

### 3. 配置 Metro

确保 `metro.config.js` 已正确配置。系统会自动从环境变量读取配置，或使用默认值。

如果需要自定义配置，可以通过环境变量传递：

```bash
RN_MULTI_BUNDLE_MODULE_PATHS='["src/modules/**"]' \
RN_MULTI_BUNDLE_SHARED_DEPS='["src/multi-bundle/**","src/navigation/**"]' \
npx react-native start
```

## 配置选项

### MultiBundleConfig

| 选项 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `modulePaths` | `string[]` | 否 | `['src/modules/**']` | 模块路径规则（glob 模式） |
| `sharedDependencies` | `string[]` | 否 | `['src/multi-bundle/**', 'src/navigation/**']` | 共享依赖路径 |
| `manifestProvider` | `ManifestProvider` | 否 | 使用 `LocalBundleManager` | Manifest 获取方式 |
| `moduleLoader` | `ModuleLoader` | 否 | 自动选择 | 自定义 ModuleLoader |
| `preloadModules` | `string[]` | 否 | `[]` | 预加载模块列表 |
| `devServer` | `DevServerConfig` | 否 | 根据平台自动选择 | 开发服务器配置 |
| `onError` | `(error: Error) => void` | 否 | - | 错误处理回调 |

### ManifestProvider

支持两种方式提供 manifest：

1. **函数方式**（推荐）：
```typescript
manifestProvider: async () => {
  // 自定义获取逻辑
  return await fetchManifestFromCustomSource();
}
```

2. **URL 方式**：
```typescript
manifestProvider: 'http://localhost:8081/bundle-manifest.json'
```

### DevServerConfig

```typescript
{
  host: string;        // 服务器地址
  port: number;        // 端口号
  protocol?: 'http' | 'https';  // 协议（默认 'http'）
}
```

## 模块开发规范

### 模块入口文件

每个模块需要在入口文件中注册：

```typescript
// src/modules/Home/index.ts
import HomeScreen from './HomeScreen';

const exports = {
  routes: {
    Home: HomeScreen,
  },
  components: {
    HomeScreen,
  },
};

// 注册模块
const ModuleRegistry = globalThis.__ModuleRegistry;
if (ModuleRegistry) {
  ModuleRegistry.registerModule('home', exports);
}

export default exports;
```

### 模块导出结构

建议使用统一的导出结构：

```typescript
{
  routes: {
    [routeKey]: React.ComponentType;
  };
  components: {
    [componentName]: React.ComponentType;
  };
  services?: {
    [serviceName]: any;
  };
  constants?: {
    [constantName]: any;
  };
}
```

## API 参考

### initMultiBundle

初始化多 Bundle 系统。

```typescript
function initMultiBundle(config?: MultiBundleConfig): Promise<InitResult>
```

**返回值**：
```typescript
{
  success: boolean;
  error?: Error;
  manifest?: BundleManifest;
}
```

### createModuleRouteLoader

创建模块路由加载器函数（推荐，用于 React Navigation `getComponent` API）。

```typescript
function createModuleRouteLoader(
  moduleId: string,
  routeKey: string
): () => React.ComponentType<any>
```

**使用示例**：
```typescript
const createHomeScreen = createModuleRouteLoader('home', 'Home');

// 在 React Navigation 中使用
<Stack.Screen name="Home" getComponent={createHomeScreen} />
```

**注意**：`createModuleRouteLoader` 内部使用 `createModuleLoader`，因此也支持错误重试功能。如果模块加载失败，用户可以通过错误页面上的重试按钮重新加载模块。

### createModuleLoader

创建通用的模块加载器函数（用于自定义组件提取逻辑）。

```typescript
function createModuleLoader(
  moduleId: string,
  pickComponent: (exports: any) => React.ComponentType<any>,
  options?: CreateModuleLoaderOptions
): () => React.ComponentType<any>
```

**CreateModuleLoaderOptions**：
```typescript
interface CreateModuleLoaderOptions {
  onError?: (error: Error) => void;  // 错误处理回调
  ErrorFallback?: React.ComponentType<ErrorFallbackProps>;  // 自定义错误组件
}
```

**ErrorFallbackProps**：
```typescript
interface ErrorFallbackProps {
  moduleId: string;      // 模块 ID
  error: Error | null;   // 错误对象
  onRetry: () => void;   // 重试回调（点击重试按钮会触发重新加载）
}
```

**使用示例**：
```typescript
// 基础用法
const createCustomScreen = createModuleLoader(
  'my-module',
  (exports) => exports.components.MyComponent
);

// 使用自定义错误组件
import { ErrorFallbackProps } from '@bm-fe/react-native-multi-bundle';

function MyCustomErrorFallback({ moduleId, error, onRetry }: ErrorFallbackProps) {
  return (
    <View>
      <Text>模块 {moduleId} 加载失败</Text>
      <Button title="重试" onPress={onRetry} />
    </View>
  );
}

const createCustomScreen = createModuleLoader(
  'my-module',
  (exports) => exports.components.MyComponent,
  {
    ErrorFallback: MyCustomErrorFallback,
    onError: (error) => {
      console.error('模块加载失败:', error);
    },
  }
);
```

**特性**：
- ✅ 自动重试：点击重试按钮会触发模块重新加载
- ✅ 自定义错误 UI：支持传入自定义错误组件
- ✅ 错误回调：可通过 `onError` 监听加载失败事件


### registerModuleRoute

注册模块路由。

```typescript
function registerModuleRoute(
  moduleId: string,
  routeKey: string,
  component?: React.ComponentType<any>
): void
```

### getModuleRoute

获取已注册的路由组件。

```typescript
function getModuleRoute(
  moduleId: string,
  routeKey: string
): React.ComponentType<any> | undefined
```

### preloadModule

预加载模块。

```typescript
function preloadModule(moduleId: string): Promise<void>
```

## 最佳实践

1. **统一初始化**：在应用入口统一调用 `initMultiBundle`，避免分散的初始化逻辑。

2. **配置集中管理**：将多 Bundle 配置集中管理，便于维护和修改。

3. **错误处理**：始终提供 `onError` 回调，妥善处理初始化失败的情况。

4. **预加载策略**：只预加载关键模块，避免影响启动性能。

5. **模块设计**：保持模块独立性，避免循环依赖。

## 故障排查

### 模块加载失败

- 检查 manifest 是否正确配置
- 确认模块 ID 与 manifest 中的 ID 一致
- 查看控制台错误信息

### Metro 构建问题

- 确认 `metro.config.js` 配置正确
- 检查模块路径规则是否匹配实际路径
- 清除 Metro 缓存：`npx react-native start --reset-cache`

### 开发环境问题

- 确认开发服务器正在运行
- 检查 `devServer` 配置是否正确
- 验证 manifest URL 是否可访问

## 更多信息

- [模块 Bundle 开发规范](../docs/模块%20Bundle%20开发规范.md)
- [使用指南](../docs/使用指南.md)
- [多 Bundle 架构设计](../docs/React%20Native%20多%20bundle%20技术方案.md)



