Rspackにモジュールフェデレーションが追加されました

2024年1月9日

Rspack 0.5.0 の紹介

最新の Rspack 0.5.0 では、待望のモジュールフェデレーションが新しい "v1.5" フェデレーション API と共に導入されました。これは、フェデレーションの開始以来、最も大幅な刷新となります。v1.5 は、エンドユーザーとフレームワークの作成者に追加の機能を提供し、元の設計では達成できなかった偉業を成し遂げます。

Rspack with Infinity Gauntlet

Webpack フェデレーションがさらに改善されました!

フェデレーション API は、ユーザーがライフサイクルを充実させ、拡張し、管理できるように公開されました。v1.5 にはいくつかの新機能が搭載されていますが、元のモジュールフェデレーションに関する API には破壊的な変更は導入されていません。

v1.5 は、@module-federation/enhanced を介して webpack でも利用でき、next.js フェデレーションや node.js フェデレーションプラグインなどの上位プラグインエコシステムは、すでにカナリアリリースで v1.5 を利用しています。

Rspack では、モジュールフェデレーション v1.5 は rspack.container.ModuleFederationPlugin を介して使用でき、元のモジュールフェデレーションは rspack.container.ModuleFederationPluginV1 を介して使用できます。

移行の機会

Rspack でのモジュールフェデレーションのサポートにより、ランタイムでコードを共有することにより、バンドラーツールを高速化するためのいくつかの創造的な移行オプションが開かれます。Webpack と Rspack はどちらも、v1.5 でモジュールフェデレーショングループが導入した同じ集中型ランタイムに依存してコードを共有できます。これにより、機能のパリティを維持することが管理可能になり、モジュールフェデレーションをカスタマイズするために追加のフォークは必要ありません。

Rspack への段階的な移行は、フェデレーションを介して実現できます。webpack ロックされたプラグインがある場合や、rspack への完全な切り替えを実行できない場合は、モジュールフェデレーションを介して、Rspack と webpack が依存関係とコードを共有できるようにすることができます。つまり、webpack ホストの作業量を減らしながらも同じ結果を得られるため、より多くのコードを Rspack を介して構築できるようになります。 例:Webpack Rspack 相互運用

フェデレーションを介して node_modules を共有することで、ビルドを高速化します。webpack に import: false にするように指示し、Rspack がすべての共有モジュールをコンパイルすることで、解析オーバーヘッドと webpack パーツが行う必要のあるコードの量を減らすことができます。これは、同様のワークロードの実行に数ミリ秒しかかからない Rspack に委任することで実現します。 例:Rspack ベンダーの Webpack アプリへのオフロード

一度に1つずつ移行します。webpack(@module-federation/enhanced)と Rspack の間のインターフェースは共有されているため、ユーザーは既存のフェデレーションビルドまたはリモートを Rspack に切り替えることができます。新しい設計を活用し、ModuleFederationPlugin をエクスポートする @module-federation/enhanced を使用している残りの webpack ビルドをお勧めします。ただし、webpack コアに同梱されている標準のプラグインを引き続き使用できます。Rspack は、既存のフェデレーションアプリケーションにシームレスに組み込まれるはずです。

webpack フェデレーションとの速度比較

モジュールフェデレーションのを使用した簡単な比較では

  • アプリ:5
  • Webpack:1ビルドあたり500〜3000ms - 本番環境
  • Rspack:1ビルドあたり130〜350ms - 本番環境

一般に、フェデレーションアプリケーションのビルド速度で 5〜10 倍のゲインが観察されており、rspack で見られる典型的なパフォーマンスゲインとほぼ一致しています。モジュールフェデレーションの例のほとんどのビルド。変換した開発ビルドは通常、コールドスタートに 150ms 未満しかかかりません。

Rsbuild のサポート

Rsbuild は、ビルド構成への簡略化されたアプローチを提供し続けています。これにより、Rspack の操作が webpack ベースのビルドシステムを処理するよりも簡単になります。モジュールフェデレーションと互換性がありますが、Rsbuild はモジュールフェデレーションでより合理化されたエクスペリエンスを提供するために利用されます。たとえば、react 用の Rsbuild プラグインはデフォルトを自動的に共有したり、Rsbuild は便利なプリセットとパターンを提供したりできます。

すでに、一部のモジュールフェデレーションの例を Rspack および Rsbuild に移行を開始しました。注目すべき例の 1 つは、CRA から Rsbuild への切り替えがシームレスで数分で完了した CRA の移行です。こちら。このガイドは、古くなったビルドのパフォーマンスを簡単に向上させたい CRA ユーザーにも役立ちます。 Rsbuild 移行ガイド。Rsbuild は、vue-cli からより高速で簡単でフェデレーションフレンドリーなものに Vue の例を移行するのにも非常に役立ちました。

フェデレーション v1 と v1.5 の違い

当初、フェデレーションは非常に簡素でした。RemoteEntry は {get, init} インターフェースを公開し、それ以外はほとんど何も公開しませんでした。これは非常に制限的でしたが、単純でした。複雑な使用方法が増え、より多くの機能が発見されるにつれて、ビルド間でのコードの共有とロードという最初のアイデアを超えて、より多くの制御が必要であることが明確になりました。

v1.5 では、runtimePlugins が導入されました。これらは、runtimePlugins オプションを介してコンパイル時に追加できます。ただし、JavaScript ファイルで実行時に動的に登録することもできます。

Rspack で

const rspack = require('@rspack/core');

new rspack.container.ModuleFederationPlugin({
  name: 'app1',
  filename: 'static/js/remoteEntry.js',
  exposes: {
    './Button': './src/components/button.js',
  },
  runtimePlugins: [require.resolve('./my-custom-plugin')]
  remotes: {
    app2: 'app2@http://localhost:3002/static/js/remoteEntry.js',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
})

そして Webpack の場合

const { ModuleFederationPlugin } = require('@module-federation/enhanced');

new ModuleFederationPlugin({
  name: 'app1',
  filename: 'static/js/remoteEntry.js',
  exposes: {
    './Button': './src/components/button.js',
  },
  runtimePlugins: [require.resolve('./my-custom-plugin')]
  remotes: {
    app2: 'app2@http://localhost:3002/static/js/remoteEntry.js',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
})

フェデレーションは、コンパイル時のプラグインなしで動的に使用することもできます。v1.5 ランタイムの詳細については、こちらを参照してください。

// Can load modules using only the runtime SDK without relying on build plugins
// When not using build plugins, shared dependencies cannot be automatically reused
import { init, loadRemote } from '@module-federation/runtime-tools';
import customPlugin from './runtimePlugin';

init({
  name: 'app1',
  remotes: [
    {
      name: 'runtime_remote1',
      alias: 'app2',
      entry: 'http://localhost:3006/remoteEntry.js',
    },
  ],
  shared: {
    react: {
      version: '18.2.0',
      scope: 'default',
      lib: () => React,
      shareConfig: {
        singleton: true,
        requiredVersion: '>17',
      },
    },
    'react-dom': {
      version: '18.2.0',
      scope: 'default',
      lib: () => ReactDOM,
      shareConfig: {
        singleton: true,
        requiredVersion: '>17',
      },
    },
  },
  plugins: [customPlugin()],
});

// Load by alias
loadRemote <
  { add: (...args: Array<number>) => number } >
  'app2/util'.then(md => {
    md.add(1, 2, 3);
  });

フェデレーション 1.5 の更新の詳細については、モジュールフェデレーション 1.5 を参照してください。