# 应用级别模块

Modern.js 提供了运行时 API，支持快速从应用中导出应用级别的 Module Federation 模块。

我们以 [使用模块联邦](/guides/topic-detail/module-federation/usage) 创建的应用为例，进一步说明如何导入应用级别模块。

## 安装依赖

在原本应用的基础上，我们需要安装 `@module-federation/bridge-react` 依赖，用于使用 Bridge 加载应用级别模块。

import { PackageManagerTabs } from '@theme';

<PackageManagerTabs command="add @module-federation/bridge-react" />

## 生产者导出模块

和直接导出组件级别的模块不同，我们需要为应用级别模块创建一个独立的入口来作为 `Module Federation` 的导出。

我们创建 `src/export-App.tsx` 文件：

:::note
这里可以是任意的文件名，Modern.js 没有做强制约定。
:::

```ts title="src/export-App.tsx"
import '@modern-js/runtime/registry/main'; // 这一行必须引入，它会默认导入微前端运行时依赖
import { render } from '@modern-js/runtime/browser';
import { createRoot } from '@modern-js/runtime/react';
import { createBridgeComponent } from '@module-federation/bridge-react';

const ModernRoot = createRoot();
export const provider = createBridgeComponent({
  rootComponent: ModernRoot,
  render: (Component, dom) => render(Component, dom),
});

export default provider;
```

该文件会将 `main` 入口的应用根组件传递给 Bridge API，并通过 Bridge 将调用渲染函数将其渲染到指定的节点上。

接下来，我们配置 `module-federation.config.ts`，将导出修改为 `src/export-App.tsx`：

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js';

export default createModuleFederationConfig({
  name: 'remote',
  filename: 'remoteEntry.js',
  exposes: {
    './app': './src/export-App.tsx',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
});
```

:::info
[`createBridgeComponent`](https://module-federation.io/zh/practice/bridge/react-bridge.html#createbridgecomponent) 用于导出应用级别模块，Modern.js 相关 API 可以查看 [createRoot](/apis/app/runtime/core/create-root)、[render](/apis/app/runtime/core/render)。
:::

## 消费者使用模块

然后我们修改消费者配置，移除之前创建的的路由文件 `src/routes/remote/page.tsx`。

我们希望所有访问到 `/remote` 的路由都能被进入上述应用级别模块中，因此我们重新添加 `src/routes/remote/$.tsx`。

:::note
如果你还不了解 `$.tsx` 的能力，可以阅读 [通配路由](/guides/basic-features/routes.html#通配路由)。
:::

```tsx title="src/routes/remote/$.tsx"
import { createRemoteComponent } from '@module-federation/bridge-react';
import { loadRemote } from '@module-federation/modern-js/runtime';

const ErrorBoundary = (info?: { error: { message: string } }) => {
  return (
    <div>
      <h2>This is ErrorBoundary Component, Something went wrong:</h2>
      <pre style={{ color: 'red' }}>{info?.error.message}</pre>
    </div>
  );
};
const Loading = <div>loading...</div>;
const RemoteApp = createRemoteComponent({
  loader: () => loadRemote('remote/app'),
  fallback: ErrorBoundary,
  loading: Loading,
});

export default RemoteApp;
```

:::info
[`createRemoteComponent`](https://module-federation.io/zh/practice/bridge/react-bridge.html#createremotecomponent) 用于加载应用级别模块。
:::

## 启动应用

现在，生产者应用和消费者应用都已经搭建完毕，我们可以在本地运行 `modern dev` 启动两个应用。

启动后，消费者应用访问 `/remote` 路由时，会进入生产者应用中。访问 `http://localhost:8080/remote`，可以看到页面中已经包含了生产者的远程模块的完整页面。

你可以在生产者应用中，创建新的路由文件，并在代码中添加路由导航，可以发现这些功能也能够正常运行。

上述用例可以参考：[Modern.js & Module Federation 应用级别模块](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/module-federation/app-export)。

## 相关文档

- [Module Federation Bridge](https://module-federation.io/zh/practice/bridge/index.html)