Vite を用いた Module Federation によるマイクロフロントエンドをやってみた
はじめに
Module Federation
Module Federation は、webpack5 の機能です。これにより別のバンドルのコードを動的に実行できます。また以下 2 の概念があります。
- ホスト
- マイクロフロントエンドをロードするコンテナ
- リモート
- ホストでロードする JS バンドル
マイクロフロントエンド
マイクロフロントエンドは、マイクロサービスアーキテクチャの概念をフロントエンドの世界にまで拡張したものです。
We're seeing an approach emerge that our teams call micro frontends. In this approach, a web application is broken up by its pages and features, with each feature being owned end-to-end by a single team. Multiple techniques exist to bring the application features—some old and some new—together as a cohesive user experience, but the goal remains to allow each feature to be developed, tested and deployed independently from others. The BFF - backend for frontends approach works well here, with each team developing a BFF to support its set of application features.
作ったもの
モンスターの情報が表示される画面です。
水平分割で以下 3 つのマイクロフロントエンドが 1 つの画面上に存在します。
- 概要 MFE
- 緑の部分
- ステータス MFE
- 青の部分
- 詳細 MFE
- オレンジの部分
今回は単一のリポジトリに各マイクロフロントエンドがあります。
.
├── app-shell
├── details
├── overview
└── stats
詳細
上述したように、Module Federation は webpack5 の機能です。Vite で同様なことを実現するには、現時点ではライブラリを使用する必要があります。今回は、vite-plugin-federation を使います。
リモート側とホスト側それぞれで、vite.config.ts
に vite-plugin-federation
を使った Module Federation の設定を記述します。
リモート側
name
モジュール名
filename
リモートモジュールのエントリーファイル名。
任意項目でデフォルトは remoteEntry.js
となる。
exposes
リモートモジュールとして、一般に公開されているコンポーネントのリスト。
'外部公開コンポーネント名': '外部公開コンポーネントアドレス'
のように指定する。
この例では components/Overview.tsx
を Overview
として公開。
shared
ローカルモジュールとリモートモジュールで共有される依存関係
これにより、例えば MFE が 3 つあり、それぞれ Vue3.5 を使っている場合、Vue3.5 を 3 回読み込む必要がなくなる。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
plugins: [
react(),
federation({
name: 'remote_overview_app',
filename: 'remoteEntry.js',
exposes: {
'./Overview': './src/components/Overview'
},
shared: ['react','react-dom']
})
],
preview: {
port: 5000,
strictPort: true
}
})
ホスト側
remotes
ローカルのモジュールとして参照されるリモートモジュールエントリファイル
'リモートモジュール名'': 'リモートモジュールエントリーファイルアドレス'
のように指定する。
この例では overviewApp
として先ほどの Overview
リモートモジュールを指定
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
plugins: [
react(),
federation({
name: 'app_shell',
remotes: {
overviewApp: 'http://localhost:5000/assets/remoteEntry.js'
},
shared: ['react','react-dom']
})
]
})
以下のように、overviewApp/Overview
から Overview.tsx
をインポートして使う。
import { Overview } from 'overviewApp/Overview'
function App() {
return (
<main>
<Overview />
</main>
)
}
export default App
おわりに
今回は、Vite + vite-plugin-federation を用いて、簡易的な MFE を実装しました。
Module Federation によるマイクロフロントエンドにより、大規模なフロントエンドを分割して開発の効率を向上させたり、1 つの MFE を複数のプロダクトで使い回すことができるのではと思いました。
また先日以下のようなポストがありました。今後 Vite に Module Federation のサポートが組み込まれる可能性があるためウォッチしていきたいです。
参考
Discussion