見出し画像

第五回:マイクロフロントエンドのルーティング戦略

「別々のアプリなのに、URLは一つにまとめたい...」
「戻るボタンを押すと変な動きをしてしまう...」
「アプリ間の画面遷移がスムーズにいかない...」

マイクロフロントエンドでよく悩むのが、画面遷移の処理です。今回は、実装例を交えながら、効果的なルーティング戦略を見ていきましょう。

まず、何が難しいの?

従来のSPA(シングルページアプリケーション)では

// React Routerの例
function App() {
  return (
    <Router>
      <Route path="/products" component={ProductList} />
      <Route path="/cart" component={Cart} />
    </Router>
  );
}

これが当たり前でしたが、マイクロフロントエンドでは

商品一覧アプリ(React Router)
└── /products

カートアプリ(Vue Router)
└── /cart

注文アプリ(独自ルーティング)
└── /orders

異なるアプリが、それぞれ独自のルーティングを持っています。これをどうまとめるか?というのが課題です。

3つの主要な実装パターン

1. 集中型ルーティング

メインのアプリ(コンテナ)で全てのルーティングを管理する方法です。

// コンテナアプリ
const routes = {
  '/products': () => loadApp('products'),
  '/cart': () => loadApp('cart'),
  '/orders': () => loadApp('orders')
};

function handleNavigation(path) {
  const route = routes[path];
  if (route) route();
}

// URL変更を監視
window.addEventListener('popstate', () => {
  handleNavigation(window.location.pathname);
});

メリット

  • URLの管理が簡単

  • 画面遷移の制御が容易

  • SEO対策がしやすい

デメリット

  • 各アプリの自由度が低下

  • 設定が中央集権的に

2. 分散型ルーティング

各アプリが独自のルーティングを持つ方法です。

// 商品一覧アプリ(React)
function ProductApp() {
  return (
    <Router basename="/products">
      <Route path="/list" component={ProductList} />
      <Route path="/detail/:id" component={ProductDetail} />
    </Router>
  );
}

// カートアプリ(Vue)
const router = new VueRouter({
  base: '/cart',
  routes: [
    { path: '/items', component: CartItems },
    { path: '/checkout', component: Checkout }
  ]
});

メリット

  • 各アプリの独立性が高い

  • 開発の自由度が高い

  • スケーラビリティが良い

デメリット

  • アプリ間の連携が複雑に

  • 全体の一貫性を保つのが難しい

3. ハイブリッド型

メインの遷移はコンテナで管理し、詳細な遷移は各アプリに任せる方法です。

// コンテナアプリ
const mainRoutes = {
  '/products': ProductApp,
  '/cart': CartApp,
  '/orders': OrderApp
};

// 商品一覧アプリの中での遷移
function ProductApp() {
  return (
    <Router basename="/products">
      <Route path="/list" component={ProductList} />
      <Route path="/detail/:id" component={ProductDetail} />
    </Router>
  );
}

実践的な実装例

実際のプロジェクトでよく使う実装例を見てみましょう

// イベントベースのルーティング連携
class RouterEventBus {
  constructor() {
    this.listeners = [];
  }

  // 画面遷移をリッスン
  listen(callback) {
    this.listeners.push(callback);
  }

  // 画面遷移を通知
  notify(path) {
    this.listeners.forEach(callback => callback(path));
  }
}

const routerBus = new RouterEventBus();

// 商品一覧アプリ
function ProductApp() {
  useEffect(() => {
    routerBus.listen((path) => {
      if (path.startsWith('/products')) {
        // 商品一覧アプリの処理
      }
    });
  }, []);
  
  return <ProductRouter />;
}

トラブルシューティング

よくある問題と解決策

1. 戻るボタンの問題

// 履歴の状態を管理
window.addEventListener('popstate', (event) => {
  if (event.state && event.state.app) {
    // アプリ固有の履歴処理
    handleAppSpecificNavigation(event.state);
  }
});

2. アプリ間のデータ受け渡し

// URLパラメータを使う
function navigateToCart(productId) {
  const url = `/cart?product=${productId}`;
  window.history.pushState({}, '', url);
  routerBus.notify(url);
}

まとめ

ルーティング戦略は、プロジェクトの規模や要件によって選択しましょう

  • 小規模なら集中型

  • 大規模なら分散型

  • 中規模ならハイブリッド型

次回は、もう一つの大きな課題である「状態管理」について詳しく見ていきます。

いいなと思ったら応援しよう!