日本語

Webpack 5のJavaScriptモジュールフェデレーションでマイクロフロントエンドの力を解き放ちましょう。スケーラブルで保守性が高く、独立したWebアプリケーションの構築方法を学びます。

Webpack 5のJavaScriptモジュールフェデレーション:マイクロフロントエンドへの包括的ガイド

進化し続けるWeb開発の世界において、大規模で複雑なアプリケーションを構築することは困難な作業となり得ます。従来のモノリシックなアーキテクチャは、開発時間の増加、デプロイのボトルネック、コード品質の維持における課題につながることがよくあります。マイクロフロントエンドは、これらの課題に対処するための強力なアーキテクチャパターンとして登場し、チームがより大きなWebアプリケーションの独立した部分を構築し、デプロイすることを可能にします。マイクロフロントエンドを実装するための最も有望な技術の1つが、Webpack 5で導入されたJavaScriptモジュールフェデレーションです。

マイクロフロントエンドとは?

マイクロフロントエンドは、フロントエンドアプリをより小さく独立したユニットに分解するアーキテクチャスタイルであり、これらのユニットは異なるチームによって自律的に開発、テスト、デプロイすることができます。各マイクロフロントエンドは特定のビジネスドメインや機能を担当し、実行時に組み合わされて完全なユーザーインターフェースを形成します。

これを会社に例えてみましょう。1つの巨大な開発チームを持つ代わりに、特定の分野に焦点を当てた複数の小規模なチームが存在します。各チームは独立して作業できるため、開発サイクルが速くなり、メンテナンスも容易になります。Amazonのような大規模なeコマースプラットフォームを考えてみてください。製品カタログ、ショッピングカート、チェックアウトプロセス、ユーザーアカウント管理などを、それぞれ異なるチームが管理しているかもしれません。これらはすべて独立したマイクロフロントエンドとなり得ます。

マイクロフロントエンドの利点:

マイクロフロントエンドの課題:

JavaScriptモジュールフェデレーションとは?

JavaScriptモジュールフェデレーションは、個別にコンパイルされたJavaScriptアプリケーション間で実行時にコードを共有できるWebpack 5の機能です。これにより、アプリケーションの一部を他のアプリケーションが利用できる「モジュール」として公開でき、npmのような中央リポジトリに公開する必要がなくなります。

モジュールフェデレーションは、各アプリケーションが独自の機能を提供し、他のアプリケーションから機能を消費できる、連合化されたアプリケーションのエコシステムを作成する方法だと考えてください。これにより、ビルド時の依存関係が不要になり、真に独立したデプロイが可能になります。

例えば、デザインシステムチームはUIコンポーネントをモジュールとして公開し、さまざまなアプリケーションチームはこれらのコンポーネントをnpmパッケージとしてインストールすることなく、デザインシステムアプリケーションから直接利用できます。デザインシステムチームがコンポーネントを更新すると、その変更はすべての利用側アプリケーションに自動的に反映されます。

モジュールフェデレーションの主要概念:

Webpack 5でモジュールフェデレーションを設定する:実践ガイド

Webpack 5でモジュールフェデレーションを設定する実践的な例を見ていきましょう。ホストアプリケーションとリモートアプリケーションという2つのシンプルなアプリケーションを作成します。リモートアプリケーションがコンポーネントを公開し、ホストアプリケーションがそれを消費します。

1. プロジェクトのセットアップ

アプリケーション用に `host` と `remote` という2つの別々のディレクトリを作成します。

```bash mkdir host remote cd host npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom cd ../remote npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom ```

2. リモートアプリケーションの設定

`remote` ディレクトリに、以下のファイルを作成します:

src/index.js:

```javascript import React from 'react'; import ReactDOM from 'react-dom/client'; import RemoteComponent from './RemoteComponent'; const App = () => (

Remote Application

); const root = ReactDOM.createRoot(document.getElementById('root')); root.render(); ```

src/RemoteComponent.jsx:

```javascript import React from 'react'; const RemoteComponent = () => (

This is a Remote Component!

Rendered from the Remote Application.

); export default RemoteComponent; ```

webpack.config.js:

```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3001, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'remote', filename: 'remoteEntry.js', exposes: { './RemoteComponent': './src/RemoteComponent', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```

基本的なHTML構造を持つ `public/index.html` を作成します。重要なのは `

` です。

3. ホストアプリケーションの設定

`host` ディレクトリに、以下のファイルを作成します:

  • `src/index.js`:アプリケーションのエントリーポイント。
  • `webpack.config.js`:Webpackの設定ファイル。

src/index.js:

```javascript import React, { Suspense } from 'react'; import ReactDOM from 'react-dom/client'; const RemoteComponent = React.lazy(() => import('remote/RemoteComponent')); const App = () => (

Host Application

Loading Remote Component...
}>
); const root = ReactDOM.createRoot(document.getElementById('root')); root.render(); ```

webpack.config.js:

```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3000, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'host', remotes: { remote: 'remote@http://localhost:3001/remoteEntry.js', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```

基本的なHTML構造を持つ `public/index.html` を作成します(リモートアプリと同様)。重要なのは `

` です。

4. Babelのインストール

`host` と `remote` の両方のディレクトリで、Babelの依存関係をインストールします:

```bash npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader ```

5. アプリケーションの実行

`host` と `remote` の両方のディレクトリで、`package.json`に以下のスクリプトを追加します:

```json "scripts": { "start": "webpack serve" } ```

では、両方のアプリケーションを起動します:

```bash cd remote npm start cd ../host npm start ```

ブラウザを開き、`http://localhost:3000`にアクセスしてください。ホストアプリケーション内にリモートコンポーネントがレンダリングされているのが見えるはずです。

主要な設定オプションの説明:

高度なモジュールフェデレーション技術

モジュールフェデレーションは、さらに洗練されたマイクロフロントエンドアーキテクチャを構築するのに役立つ多くの高度な機能を提供します。

動的リモート

Webpackの設定にリモートアプリケーションのURLをハードコーディングする代わりに、実行時に動的にロードすることができます。これにより、ホストアプリケーションを再ビルドすることなく、リモートアプリケーションの場所を簡単に更新できます。

例えば、リモートアプリケーションのURLを設定ファイルやデータベースに保存し、JavaScriptを使用して動的にロードすることができます。

```javascript // In webpack.config.js remotes: { remote: `promise new Promise(resolve => { const urlParams = new URLSearchParams(window.location.search); const remoteUrl = urlParams.get('remote'); // Assume remoteUrl is something like 'http://localhost:3001/remoteEntry.js' const script = document.createElement('script'); script.src = remoteUrl; script.onload = () => { // the key of module federation is that the remote app is // available using the name in the remote resolve(window.remote); }; document.head.appendChild(script); })`, }, ```

これで、クエリパラメータ `?remote=http://localhost:3001/remoteEntry.js` を付けてホストアプリをロードできます。

バージョン管理された共有モジュール

モジュールフェデレーションは、共有モジュールのバージョニングと重複排除を自動的に処理し、互換性のあるバージョンの各モジュールが1つだけロードされるようにします。これは、多くの依存関係を持つ大規模で複雑なアプリケーションを扱う場合に特に重要です。

Webpackの設定で、各共有モジュールのバージョン範囲を指定できます。

```javascript // In webpack.config.js shared: { react: { singleton: true, eager: true, requiredVersion: '^18.0.0' }, 'react-dom': { singleton: true, eager: true, requiredVersion: '^18.0.0' }, }, ```

カスタムモジュールローダー

モジュールフェデレーションでは、異なるソースから、または異なる形式でモジュールをロードするために使用できるカスタムモジュールローダーを定義できます。これは、CDNやカスタムモジュールレジストリからモジュールをロードするのに役立ちます。

マイクロフロントエンド間の状態共有

マイクロフロントエンドアーキテクチャの課題の1つは、異なるマイクロフロントエンド間で状態を共有することです。この課題に対処するために、いくつかのアプローチがあります:

モジュールフェデレーションでマイクロフロントエンドを実装するためのベストプラクティス

モジュールフェデレーションでマイクロフロントエンドを実装する際に留意すべきベストプラクティスをいくつか紹介します:

モジュールフェデレーションの実世界での活用例

具体的なケーススタディは機密情報であることが多いですが、モジュールフェデレーションが非常に役立つ一般的なシナリオをいくつか紹介します:

結論

Webpack 5のJavaScriptモジュールフェデレーションは、マイクロフロントエンドアーキテクチャを構築するための強力で柔軟な方法を提供します。これにより、個別にコンパイルされたJavaScriptアプリケーション間で実行時にコードを共有でき、独立したデプロイ、技術の多様性、チームの自律性の向上を実現します。このガイドで概説したベストプラクティスに従うことで、モジュールフェデレーションを活用して、スケーラブルで保守性が高く、革新的なWebアプリケーションを構築できます。

フロントエンド開発の未来は、間違いなくモジュール化され分散化されたアーキテクチャに向かっています。モジュールフェデレーションは、これらの現代的なシステムを構築するための重要なツールを提供し、チームがより速く、より柔軟に、そしてより回復力のある複雑なアプリケーションを作成できるようにします。技術が成熟するにつれて、さらに革新的なユースケースやベストプラクティスが登場することが期待されます。