Viteとvite-plugin-federationでマイクロフロントエンドしてみる。


# はじめに

Twitterで[vite-plugin-federation](https://github.com/originjs/vite-plugin-federation) というパッケージを紹介しているツイートがあったので、どんな感じに使えるかを何回かに分けて見ていきます。今回は外部のコンポーネントを組み込む方法について見ていきます。

# プロジェクトの構成とプロジェクトの作成

ShellAppでリモートに定義されたHeaderコンポーネントと、Footerコンポーネントを読み込んで合成します。構成としてはこんな感じになります。

```
+------------------------------------+
| Shell(ShellApp:5000)               |
| +--------------------------------+ |
| | Header(KernelMfe:5001)         | |
| +--------------------------------+ |
| +--------------------------------+ |
| | Contents                       | |
| +--------------------------------+ |
| +--------------------------------+ |
| | Footer(KernelMfe:5001)         | |
| +--------------------------------+ |
+------------------------------------+
```

プロジェクトを作ります。

```sh
❯ cd src
❯ yarn create vite shell --template react-swc-ts
❯ yarn create vite kernel --template react-swc-ts
```

すべてのプロジェクトに、`vite-plugin-federation`パッケージを追加します。

```sh
❯ cd src/shell
❯ yarn add @originjs/vite-plugin-federation --dev
❯ cd ../kernel
❯ yarn add @originjs/vite-plugin-federation --dev
```

`ShellApp`を5000で、`KernelMFE`を5001で起動するように設定します。
例えば、`ShellApp`を5000で提供する場合は次のように設定します。

```json:/src/shell/package.json
{
  // ... 略 ...
  "scripts": {
    "dev": "vite --port 5000 --strictPort",
    "build": "tsc && vite build",
    "preview": "vite preview --port 5000 --strictPort"
  },
  // ... 略 ...
}
```

# Kernel MFEにコンポーネントを作成し公開する。

`KernelMFE`に`Headerコンポーネント`と`Footerコンポーネント`を追加します。
`Footerコンポーネント`の実装はほぼ同じなのでここでは省略します。

```ts:/src/kernel/src/compoments/Header.tsx
import styles from './Header.module.css'

export default function Header = () => {
    return (
      <div className={styles.header}>
        ヘッダー
      </div>
    );
}
```

`vite.config.ts`にモジュールフェデレーションの設定をして、外部に`Headerコンポーネント`と`Footerコンポーネント`を公開します。

```ts:/src/kernel/vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import federation from '@originjs/vite-plugin-federation'

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: "remote_app",
      filename: "remoteEntry.js",
      exposes: {
        './Header': './src/components/Header',
        './Footer': './src/components/Footer'
      },
      shared: ['react','react-dom']
    })
  ],
  build: {
    modulePreload: false,
    target: 'esnext',
    minify: false,
    cssCodeSplit: false
  }
})
```

上記の設定をした後にビルド`yarn build`すると`/src/kernel/dist/assets`以下にremoteEntry.jsが作成され、`yarn preview`すれば`http://localhost:5001/assets/remoteEntry.js`でリモートコンポーネントが公開されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/2048632f-ef6a-f5e1-a049-cc9a404196e3.png)


# ShellでKernelMFEのコンポーネントを合成して表示する。

`ShellApp`で、`KernelMFE`のコンポーネントを参照できるように`vite.config`で参照します。

```ts:/src/shell/vite.config
import { defineConfig } from 'vite'
import federation from '@originjs/vite-plugin-federation'
import react from '@vitejs/plugin-react-swc'

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'kernelMfe',
      remotes: {
        kernelMfe: 'http://localhost:5001/assets/remoteEntry.js',
      },
      shared: ['react','react-dom']
    })
  ],
  build: {
    modulePreload: false,
    target: 'esnext',
    minify: false,
    cssCodeSplit: false
  }
})
```

`App.tsx`に`Kernel MFE`の`Headerコンポーネント`と`Footerコンポーネント`を組み込む

```tsx:/src/shell/src/App.tsx
import './App.css'
import Header from 'kernelMfe/Header';
import Footer from 'kernelMfe/Footer';

export default function App() {
  return (
    <div className="App">
      <Header />
      <div>
        Shell App
      </div>
      <Footer />
    </div>
  )
}
```

# MFEとAppを開発サーバーで起動して動作を確認する。

`KernelMFE`は`yarn build`後に`yarn preview`で開発サーバーを起動します。

```sh:KernelMFEを開発サーバーで起動
❯ cd src/kernel
❯ yarn build && yarn preview
```

App側は`yarn dev`開発サーバーを起動すると、リモートに定義されたコンポーネントが呼び出されていることを確認できます。

```sh:ShellAppを開発サーバーで起動
❯ cd src/Shell
❯ yarn dev
```

そっけない画面ですが、リモートのコンポーネントが合成されて表示されたのを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/69209bf0-f381-b92a-1222-ff4fce0d01cd.png)

# おわりに

MFEってよくわからなかったんですけれど、雰囲気わかってきました（あやしい、、、）！
次はコンポーネント間の通信を見ていきます。