jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Webpack · Part 11 — Module Federation

Share code between independently deployed apps at runtime: hosts, remotes, exposes, remotes, and the shared singleton trick that stops React being downloaded twice. With a live federation visualizer.

Suốt mười phần, “bundle” nghĩa là một app build chung. Module Federation phá vỡ giả định đó: các app riêng biệt, build và triển khai độc lập, có thể import code của nhau lúc runtime. Đây là động cơ phía sau micro-frontend hiện đại.

Bấm các module được expose bên dưới để tải remote vào host, và bật/tắt shared để xem vì sao React không tải hai lần:


1. Vấn đề nó giải quyết

Một app lớn chia cho nhiều team: cart, profile, search. Không có federation, mọi thay đổi ở bất kỳ phần nào buộc build lại và deploy lại cả app. Với federation, mỗi team ship phần của mình độc lập và shell ghép chúng lại trong trình duyệt.

Thuật ngữNghĩa
hostapp shell tiêu thụ module remote
remoteapp expose module cho người khác
exposesremote cung cấp gì
remoteshost muốn tiêu thụ gì
sharedphụ thuộc tải một lần và dùng lại

2. Bên remote

Remote khai báo tên, tên file entry, và những gì nó expose:

const { ModuleFederationPlugin } = require("webpack").container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: "cart",
      filename: "remoteEntry.js", // the manifest other apps fetch
      exposes: {
        "./Cart": "./src/Cart",
        "./MiniCart": "./src/MiniCart",
      },
      shared: { react: { singleton: true } },
    }),
  ],
};

remoteEntry.js là một manifest nhỏ — bản đồ những gì được expose và cách lấy chúng. Chunk Cart thực tế chỉ tải khi có người import nó.


3. Bên host

Host liệt kê remote nào nó muốn và tìm remoteEntry.js của chúng ở đâu:

new ModuleFederationPlugin({
  name: "shell",
  remotes: {
    cart: "cart@https://cart.example.com/remoteEntry.js",
    profile: "profile@https://profile.example.com/remoteEntry.js",
  },
  shared: { react: { singleton: true }, "react-dom": { singleton: true } },
});

Rồi bạn import module remote như thể nó là local — nhưng nó phân giải qua mạng lúc runtime:

const Cart = React.lazy(() => import("cart/Cart"));

URL thậm chí có thể trỏ tới một remote chưa tồn tại khi host được build. Deploy remote, refresh, xong.


4. shared — tính năng sát thủ

Không có shared, host và mỗi remote sẽ tự bundle React riêng — ba bản, hook hỏng, lãng phí byte. shared biến React thành singleton: tải một lần, dùng lại khắp nơi.

shared: {
  react: { singleton: true, requiredVersion: "^18.0.0" },
  "react-dom": { singleton: true, requiredVersion: "^18.0.0" },
}
  • chỉ một bản tồn tại (bắt buộc cho React, vốn hỏng với hai bản).
  • Webpack thương lượng một phiên bản tương thích giữa các app lúc runtime.
  • tải trong chunk đầu thay vì async (dùng tiết kiệm).

Bật/tắt shared trong visualizer: khi bật, “react copies loaded” luôn là 1 dù bạn tải bao nhiêu remote.


5. Cảnh báo thực tế

  • Lệch phiên bản — nếu remote cần phiên bản major không tương thích, thương lượng singleton có thể cảnh báo hoặc hỏng.
  • Lỗi runtime — remote sập là lỗi runtime, không phải lỗi build; bọc trong error boundary và fallback.
  • An toàn kiểu — import remote không có kiểu local; sinh .d.ts từ remote.
  • Đừng tách quá nhỏ — federation thêm phức tạp vận hành; dùng cho ranh giới team thực sự.

6. Bài tập

1. Host import cart/Cart, nhưng cart còn chưa được deploy khi host build. Vì sao vẫn chạy?

Lời giải

Federation phân giải remote lúc runtime qua remoteEntry.js lấy qua mạng, không phải lúc build.

2. Ba app federated đều dùng React. Làm sao đảm bảo chỉ một bản tải và hook không hỏng?

Lời giải

shared: { react: { singleton: true } } trong config của mọi app.

3. Server remote Cart sập. Tác động tới người dùng và cách kiểm soát?

Lời giải

Đó là lỗi tải runtime — bọc remote lazy trong error boundary với UI fallback để phần còn lại của shell vẫn chạy.

Nâng cao:trong visualizer, tắt shared, tải cả bốn module remote, và để ý “react copies loaded” và KB chuyển tăng so với khi shared.


Điểm chính

  • Module Federation cho các app deploy độc lập import lẫn nhau lúc runtime.
  • remote exposes module qua remoteEntry.js; host liệt kê trong remotes.
  • shared + singleton ngăn bản trùng của React và bạn bè.
  • Lỗi remote là lỗi runtime — dùng error boundary và fallback.
  • Dùng ở ranh giới team thực sự, không để tách app nhỏ.

Tiếp theo

Phần 12 — Capstone production + di trú: ghép tất cả thành một config production thực chiến, rồi hướng dẫn thực tế khi nào (và cách) di trú sang Vite hoặc Rspack.