Micro frontend với React và Vite

7 min read

Trong bài viết này, mình sẽ giới thiệu về cách sử dụng micro frontends trong Vite. Trước tiên mình sẽ giải thích Micro Frontend là gì, lợi ích khi sử dụng Micro Frontend

Micro frontend là gì?

Microfrontend là một phương pháp kiến ​​trúc cho phép các nhà phát triển chia nhỏ một ứng dụng web phức tạp thành các mô-đun giao diện người dùng tự động, nhỏ hơn. Mỗi microfrontend là một đơn vị độc lập, chịu trách nhiệm về một tính năng hoặc chức năng cụ thể. Các mô-đun này có thể được phát triển, triển khai và duy trì độc lập, cho phép các nhóm làm việc riêng biệt và giảm thiểu tác động của những thay đổi trong mô-đun này lên các mô-đun khác.

Lợi ích của Micro Frontend.

  1. Khả năng mở rộng: Các nhóm có thể làm việc đồng thời trên các phần khác nhau của ứng dụng mà không cần phải xen vào nhau.
  2. Tính linh hoạt: Các micro frontend khác nhau có thể sử dụng các công nghệ và khuôn khổ khác nhau, miễn là chúng tuân thủ hợp đồng đã thỏa thuận.
  3. Sự độc lập: Mỗi micro frontend có thể được triển khai độc lập, giảm rủi ro triển khai và cho phép phát hành thường xuyên hơn.
  4. Khả năng bảo trì: Các codebase nhỏ hơn thường dễ bảo trì và tái cấu trúc hơn.

Các cách tích hợp Micro frontend vào App.

  1. IFRAMEs: Cách này đơn giản nhưng lại có hạn chế về mặt giao tiếp và style các component.
  2. Web Components: Custom component có thể gói gọn Function và Style.
  3. JavaScript Bundles: Mỗi micro frontend gửi một JavaScript package được tải và thực thi trong ứng dụng chính.
  4. Module Federation: Tính năng của Vite cho phép chia sẻ mô-đun giữa các bản build riêng biệt và cho phép dynamic import.
    +----------------+
    |   Host App     |
    +----------------+
             |
             |
             |  Dynamically Load and Integrate Microfrontends
             |
    +----------------+      +----------------+      +----------------+
    | Microfrontend 1| ---> | Microfrontend 2| ---> | Microfrontend 3|
    +----------------+      +----------------+      +----------------+

Đây là sơ đồ kiến trúc

Host app đóng vai trò là điểm truy cập chính và điều phối việc tải và tích hợp các micro frontend. Mỗi micro frontend, được biểu thị là Microfrontend 1, Microfrontend 2 và Microfrontend 3, được phát triển dưới dạng một ứng dụng React riêng biệt.

Trong runtime, Host app sử dụng Vite’s Module Federation để tải remote entry file của mỗi micro frontend. Tệp này chứa thông tin và cấu hình cần thiết để microfrontend hiển thị các thành phần, chức năng và tài nguyên của nó.

Sau khi tải một microfrontend, Host app có thể truy cập và hiển thị các thành phần từ microfrontend này. Giao tiếp giữa Host app và microfrontend có thể được thiết lập bằng nhiều kỹ thuật khác nhau, chẳng hạn như Event, public/subcription patterns hoặc API.

Bản chất mô-đun của microfrontends cho phép mỗi mô-đun được phát triển, triển khai và duy trì độc lập, mang lại tính linh hoạt và khả năng mở rộng trong quá trình phát triển.

Tích hợp Microfrontend với React và Vite như thế nào?

Để bắt đầu, hãy tạo Host app bằng cách chạy cmd bên dưới.

npm create vite@latest host -- --template react

tiếp tục bằng cách tạo một Remote app.

npm create vite@latest remote -- --template react

Sau khi tạo cả Host app và Remote app, hãy chạy npm install bên trong các dự án tương ứng.

Bước 1: Cài đặt @originjs/vite-plugin-federation

Cài đặt plugin @originjs/vite-plugin-federation trong cả Host app và Remote app bằng cách chạy lệnh bên dưới.

npm i -D @originjs/vite-plugin-federation

Bước 2: Cập nhật file vite.config.js in Remote app.

Sau khi cài đặt plugin, hãy truy cập tệp vite.config.js của Remote app và thay thế toàn bộ mã bằng mã bên dưới.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from '@originjs/vite-plugin-federation';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'remote',
      filename: 'remoteEntry.js',
      exposes: {
      },
      remotes: {
      },
      shared: ['react', 'react-dom'],
    }),
  ],
  build: {
    modulePreload: false,
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
  },
});

Ở đây, chúng ta đang thêm modular federation và cấu hình bản build trong vite.config.js của ứng dụng.

Sau khi dán đoạn mã trên, hãy cập nhật thuộc tính name bằng tên dự án của bạn, nếu có khoảng trống trong tên, hãy thay thế bằng “_”.

Tiếp theo tên tệp build cho modular federation là remoteEntry.js. Đây là hai thông tin được sử dụng trong cấu hình Host app

Tiếp theo, đối tượng expose là nơi chúng tôi liệt kê tất cả các thành phần mà chúng tôi đang cố gắng export từ ​​ứng dụng này và đối tượng Remote sẽ cấu hình các ứng dụng microfrontend khác sẽ được cấu hình. Mảng shared sẽ chứa tất cả các depedencies của ứng dụng.

Bước 3: Cấu hình port cho ứng dụng

Khi chạy ứng dụng mỗi lần, ứng dụng có thể chạy ở port khác, vì vậy hãy giữ cho ứng dụng nhất quán và cập nhật các đoạn mã trong package.json như bên dưới.

"scripts": {
    "dev": "vite --port 5001 --strictPort",
    "build": "vite build",
    "preview": "vite preview --port 5001 --strictPort",
    "serve": "vite preview --port 5001 --strictPort",
    "start": "npm run build && npm run serve"
 },

Sau khi hoàn thành ba bước, hãy chạy ứng dụng và xác thực ứng dụng đang hoạt động.

npm run dev

Sau khi định cấu hình Remote app, hãy lặp lại ba bước trên trong Host app và cập nhật port thành “5002”

Sau khi hoàn tất cấu hình trong cả Host app và Remote, hãy bắt đầu viết code.

Đi tới thư mục “src” trong Remote app và tạo hai tệp bên dưới và dán mã đã cho.

Header.jsx

export default function Header() {
  return (
    <div
      style={{
        width: '100vw',
        height: '64px',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'space-between',
        padding: '0 16px',
        background: '#004644',
        color: '#fff',
        fontSize: '24px',
        fontWeight: 700,
      }}
    >
      Remote Server
    </div>
  );
}

Footer.jsx

export default function Footer() {
  return (
    <div
      style={{
        width: '100vw',
        height: '48px',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        padding: '0 16px',
        background: '#004644',
        color: '#ccc',
        fontSize: '12px',
        fontWeight: 400,
      }}
    >
      @ Remote 2024
    </div>
  );
}

Tiếp theo, vào tệp App.jsx và dán mã bên dưới.

import Header from './Header.jsx';
import Footer from './Footer.jsx'

export default function App() {
  return (
    <div>
      <Header />
      <div>Remote App</div>
      <Footer />
    </div>
  );
}
micro frontend
Remote app

Sau khi build components cần export, hãy truy cập vite.config.js trong Remote app và cập nhật đối tượng expose như bên dưới.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from '@originjs/vite-plugin-federation';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'remote',
      filename: 'remoteEntry.js',
      exposes: {
        './Header': './src/Header',
        './Footer': './src/Footer',
      },
      remotes: {},
      shared: ['react', 'react-dom'],
    }),
  ],
  build: {
    modulePreload: false,
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
  },
});

Sau khi expose các component trong Remote app, hãy truy cập vite.config.js của Host app và cấu hình Remote app trong đối tượng remotes của Host app như hiển thị bên dưới.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from '@originjs/vite-plugin-federation';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'host',
      filename: 'remoteEntry.js',
      exposes: {},
      remotes: {
        remote: 'http://127.0.0.1:5173/assets/remoteEntry.js',
      },
      shared: ['react', 'react-dom'],
    }),
  ],
  build: {
    modulePreload: false,
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
  },
});

Định dạng cấu hình sẽ như hình dưới đây.

remotes: {
  APP_NAME: 'remote_app_url/assets/remoteEntry.js'
}

APP_NAME giống với tên được đưa ra trong vite.config.js của Remote app.
remote_app_url sẽ là url nơi ứng dụng được lưu trữ hoặc chạy.

Sau khi định cấu hình trong vite.config.js, hãy truy cập tệp App.jsx của Host app và dán mã bên dưới.

import Header from 'remote/Header';
import Footer from 'remote/Footer';

function App() {
  return (
    <div className="App">
      <Header />
      <div>HOST</div>
      <Footer />
    </div>
  );
}

export default App;

Khi bạn chạy lệnh npm run dev trong Host app, bạn sẽ thấy lỗi như bên dưới.

micro frontend

Để sửa lỗi này, mở Remote app và ứng dụng đang chạy và chạy lệnh bên dưới khi chúng tôi cập nhật lệnh này trong tập lệnh của tệp pack.json.

npm start

Vì vậy, lệnh trên sẽ build và run code được build.

Sau đó đến Host app và chạy ứng dụng bằng lệnh bên dưới.

npm run serve

Note: Trong trường hợp bạn đang chia sẻ bất kỳ components/code nào từ Host app thì bạn phải chạy npm start.

Sau khi hoàn tất, bạn sẽ thấy Host app như bên dưới.

micro frontend

Cảm ơn bạn đã đọc!

Tôi hy vọng bạn thấy nó hữu ích và nhiều thông tin. Nếu bạn có bất kỳ câu hỏi hoặc phản hồi nào, vui lòng để lại nhận xét bên dưới. Sự hỗ trợ và tham gia của bạn có ý nghĩa rất lớn đối với tôi.

Happy coding!

Source:

Avatar photo

Clean Code: Nguyên tắc viết hàm trong lập trình…

Trong quá trình phát triển phần mềm, việc viết mã nguồn dễ đọc, dễ hiểu là yếu tố then chốt để đảm bảo code...
Avatar photo Dat Tran Thanh
3 min read

Clean Code: Nguyên tắc comment trong lập trình

Trong lập trình, code không chỉ là một tập hợp các câu lệnh để máy tính thực thi, mà còn là một hình thức...
Avatar photo Dat Tran Thanh
3 min read

Clean Code: Nguyên tắc xử lý lỗi (Error Handling)

Trong quá trình phát triển phần mềm, việc xử lý lỗi không chỉ là một phần quan trọng mà còn ảnh hưởng trực tiếp...
Avatar photo Dat Tran Thanh
4 min read

Leave a Reply

Your email address will not be published. Required fields are marked *