🔖

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.

https://www.thoughtworks.com/radar/techniques/micro-frontends

作ったもの

モンスターの情報が表示される画面です。

水平分割で以下 3 つのマイクロフロントエンドが 1 つの画面上に存在します。

  • 概要 MFE
    • 緑の部分
  • ステータス MFE
    • 青の部分
  • 詳細 MFE
    • オレンジの部分

モンスター図鑑の画像

https://github.com/TakaShinoda/my-mfe

今回は単一のリポジトリに各マイクロフロントエンドがあります。

.
├── app-shell
├── details
├── overview
└── stats

詳細

上述したように、Module Federation は webpack5 の機能です。Vite で同様なことを実現するには、現時点ではライブラリを使用する必要があります。今回は、vite-plugin-federation を使います。

リモート側とホスト側それぞれで、vite.config.tsvite-plugin-federation を使った Module Federation の設定を記述します。

リモート側

name

モジュール名

filename

リモートモジュールのエントリーファイル名。

任意項目でデフォルトは remoteEntry.js となる。

exposes

リモートモジュールとして、一般に公開されているコンポーネントのリスト。

'外部公開コンポーネント名': '外部公開コンポーネントアドレス' のように指定する。

この例では components/Overview.tsxOverview として公開。

shared

ローカルモジュールとリモートモジュールで共有される依存関係

これにより、例えば MFE が 3 つあり、それぞれ Vue3.5 を使っている場合、Vue3.5 を 3 回読み込む必要がなくなる。

vite.config.ts
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 リモートモジュールを指定

vite.config.ts
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 をインポートして使う。

App.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 のサポートが組み込まれる可能性があるためウォッチしていきたいです。

https://x.com/youyuxi/status/1891107914682696090

参考

https://webpack.js.org/concepts/module-federation/

https://www.oreilly.co.jp/books/9784814400027/

https://github.com/originjs/vite-plugin-federation

https://github.com/aws-samples/talk-dev-to-me-twitch/tree/main/micro-frontends-module-federation

GitHubで編集を提案

Discussion