Module Federation с Preact

Module Federation — механизм, представленный в Webpack 5, который позволяет приложениям динамически обмениваться модулями во время выполнения. В контексте Preact это открывает возможности для построения микрофронтендов, когда разные части интерфейса могут быть загружены из отдельных сборок без необходимости объединять весь код на этапе сборки.

Принципы работы Module Federation

  1. Remote и Host приложения

    • Remote — приложение, которое предоставляет модули для использования другими.
    • Host — приложение, которое потребляет модули из remote.
  2. Динамическая загрузка Module Federation позволяет подключать компоненты или библиотеки по URL в рантайме, что сокращает время сборки и снижает дублирование кода.

  3. Совместное использование зависимостей Общие зависимости (например, preact и preact/hooks) могут быть вынесены в shared, чтобы избежать дублирования и уменьшить размер бандла.

Настройка Module Federation для Preact

Конфигурация Webpack для remote

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const path = require("path");

module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    publicPath: "http://localhost:3001/",
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "remoteApp",
      filename: "remoteEntry.js",
      exposes: {
        "./Button": "./src/components/Button",
      },
      shared: {
        preact: {
          singleton: true,
          requiredVersion: "^10.5.14"
        },
        "preact/hooks": {
          singleton: true,
          requiredVersion: "^10.5.14"
        }
      }
    })
  ],
  resolve: {
    extensions: [".js", ".jsx"],
    alias: {
      react: "preact/compat",
      "react-dom": "preact/compat"
    }
  }
};

Конфигурация Webpack для host

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  mode: "development",
  entry: "./src/index.js",
  output: {
    publicPath: "http://localhost:3000/",
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "hostApp",
      remotes: {
        remoteApp: "remoteApp@http://localhost:3001/remoteEntry.js",
      },
      shared: {
        preact: {
          singleton: true,
          requiredVersion: "^10.5.14"
        },
        "preact/hooks": {
          singleton: true,
          requiredVersion: "^10.5.14"
        }
      }
    })
  ],
  resolve: {
    extensions: [".js", ".jsx"],
    alias: {
      react: "preact/compat",
      "react-dom": "preact/compat"
    }
  }
};

Импорт remote-компонентов в Preact

После настройки Module Federation можно динамически импортировать компоненты из remote-приложения. Например, использование Button из remoteApp:

import { h } from 'preact';
import { lazy, Suspense } from 'preact/compat';

const RemoteButton = lazy(() => import("remoteApp/Button"));

export default function App() {
  return (
    <div>
      <h1>Пример Preact с Module Federation</h1>
      <Suspense fallback={<div>Загрузка кнопки...</div>}>
        <RemoteButton />
      </Suspense>
    </div>
  );
}

Управление зависимостями

  • Singleton гарантирует, что общие зависимости будут использоваться из единственного экземпляра, предотвращая конфликты версий.
  • Strict version позволяет контролировать точную версию пакета, что важно при использовании preact/compat с Preact и при интеграции с внешними микрофронтендами.

Советы по производительности

  1. Минимизация remote-модулей — лучше разделять крупные функциональные блоки на отдельные remote-приложения, чем загружать весь бандл целиком.
  2. Использование Suspense и lazy — обеспечивает плавную загрузку и предотвращает блокировку рендеринга.
  3. Кеширование remoteEntry.js — позволяет повторно использовать загруженные remote-модули без повторных HTTP-запросов.

Особенности Preact в контексте Module Federation

  • Лёгкий вес Preact сокращает размер бандлов, что особенно важно при частой загрузке микрофронтендов.
  • Полная совместимость через preact/compat с React-плагинами Module Federation облегчает миграцию с React на Preact.
  • Внутренние хуки (useState, useEffect) работают корректно при использовании remote-компонентов, если версии Preact и preact/hooks синхронизированы.

Отладка и распространённые ошибки

  1. Несовпадение версий Preact — приводит к рендеринговым сбоям. Проверять версии через shared обязательно.
  2. Неправильный publicPath — remoteEntry.js может не загружаться, если URL указан неверно.
  3. Несовместимость Suspense — необходимо использовать preact/compat для корректного использования React-подобных функций.

Практическое применение

Module Federation с Preact идеально подходит для крупных проектов, где интерфейс делится на независимые модули. Это позволяет:

  • Обновлять отдельные компоненты без пересборки всего приложения.
  • Делать постепенную миграцию с React на Preact.
  • Снижать время загрузки за счет ленивой загрузки и кеширования микрофронтендов.

Использование Module Federation в Preact создаёт гибкую архитектуру микрофронтендов, оптимизируя как процесс разработки, так и производительность конечного приложения.