Dạo gần đây mình nhận được một yêu cầu từ sếp về việc chuyển đổi product hiện tại thành Microfrontend. Mới nghe thì như sét đánh ngang tai vì product này đã phát triển được gần 3 năm tới giờ mới chuyển đổi, nghe thôi đã thấy nhứt hết cả đầu. 

Nhưng nói qua cũng phải nói lại về tình hình hiện tại của cái product. Product có gần 20 Modules, trước chỉ có 1 team bên Việt Nam build nhưng giờ có thêm 2 team bên nước ngoài cũng join vào nữa đủ thấy độ phức tạp và rối rắm của cái product này rồi.

Thêm vào đó team Backend hiện tại cũng đã sử dụng Microservices để xây dựng kiến trúc phía BE nên dù muốn dù không tổn thương nhất vẫn chính là team FE.

 

Trước khi bắt đầu xây dựng Microfrontend cho hệ thống thì chúng ta cùng tìm hiểu qua Microfrontend là gì, nó giải quyết vấn đề gì, những khó khăn cũng như lợi ích khi xây dựng Microfrontend.

 

I. Vấn đề đặt ra

Như mình đã giới thiệu ở trên về tình hình hiện của team mình đó là hệ thống mà team đang build có đến gần 20 modules, đã phát triển được 3 năm và hiện tại có đến 3 team cùng join vào. Do đó để có thể scale và maintain hệ thống này ra chính là một thách thức vô cùng lớn với team.

Mỗi team đều có các dev, leader và cả PM khác nhau nên bên mình cũng không muốn can thiệp quá nhiều vào các team khác, nhưng với tình hình hiện tại bên phía FE thì các team đều dùng chung một codebase dẫn đến việc không thống nhất về: coding style, kiến trúc code khác nhau, commit convention khác nhau, thậm chí là sử dụng các công nghệ khác nhau.

 

II. Giải pháp hiện tại

Để giải quyết bài toán trên thì team mình đã quyết định chuyển dần dự án hiện tại sang microfrontend, trước mắt là xây dựng các module mới và refactor các module cũ sang Microfrontend.

 Hiểu đơn giản thì Microfrontend cho phép chúng ta chia nhỏ app thành các thành phần nhỏ, riêng biệt, các thành phần này có thể là 1 module, 1 màn hình, hay 1 component, được deploy ở những nơi khác nhau và được phát triển một cách độc lập. 

Tuyệt vời! Nghe đến đây thì có vẻ như vấn đề đã được giải quyết. Nhưng không, mọi chuyện chỉ mới bắt đầu :D

 

III. Microfrontend có thật sự tốt hay chỉ là một kiến trúc ăn theo Microservices ?

 

Trước khi bắt đầu Microfrontend chúng ta cùng xem những thách thức, khó khăn và nhược điểm của Microfrontend

  • Đầu tiên phải kể đến phần cấu hình Microfrontend, việc setup một hệ thống Microfrontend vẫn còn rất phức tạp và gặp nhiều khó khăn.
  • Việc phân chia các Component, shared các common UI, utils, function hay thậm chí là config về linter, git, coding convention,... đều là những thách thức trong kiến trúc Microfrontend.
  • Làm thế nào để các Module có thể liên kết được với nhau, hay việc tái sử dụng các common components, common functions,... ?
  • Vì hệ thống được chia nhỏ thành các module riêng biệt nên việc quản lý State chung cũng là một khó khăn.
  • Nếu mỗi module được xây dựng bằng một công nghệ khác nhau (team A code React JS, team B code Angular) thì làm thê nào tái sử dụng các common components?
  • Trùng lặp CSS: Mỗi một module sử dụng 1 bộ css khác nhau, do đó khi nhúng các module vào host app sẽ dẫn đấy việc trùng lặp css.
  • Có thể còn nhiều thách thức khác mà mình chưa gặp phải :D

 

IV. Xây dựng Microfrontend

Để xây dựng một hệ thống theo kiến trúc Microfrontend chúng ta sẽ giải quyết từng vấn đề được đặt ra ở trên để xem có nên chuyển đổi sang Microfrontend hay không nhé.

 

1. Kiến trúc của Microfrontend

Microfrontend là một mô hình kiến trúc trong phát triển frontend, trong đó một ứng dụng web lớn được phân chia thành các phần nhỏ hơn gọi là microfrontend. Các microfrontend có thể giao tiếp với nhau thông qua cơ chế như cổng (portal), qua APIs hoặc sử dụng liên kết Module bằng Webpack.

Trong Microfrontend cơ chế liên kết các microfrontend với nhau là một trong những thách thức chính của kiến trúc này. Một trong những cách phổ biến nhất là sử dụng Module Federation của Webpack để liên kết các module lại với nhau. 

 

2. Module Federation

Để sử dụng cơ chế Module Federation, bạn cần tạo các container và entry points cho các ứng dụng cần chia sẻ module. Dưới đây là các khái niệm quan trọng trong cơ chế Module Federation:

  1. Container (container): Container là ứng dụng hoặc microfrontend chứa các module và đóng vai trò là host (máy chủ) cho các module remote khác. Container đảm nhận vai trò quản lý và tương tác với các module remote, cho phép truy cập và sử dụng các module đó.

  2. Remote (remote module): Remote module là một module độc lập được triển khai trong một ứng dụng độc lập (gọi là remote application) và có thể được chia sẻ và truy cập từ container hoặc các remote khác. Các remote module có thể được nhúng và sử dụng trong container thông qua cơ chế Module Federation.

  3. Entry (entry point): Entry point là một điểm vào (entry) cho mỗi ứng dụng cần chia sẻ module. Mỗi ứng dụng sẽ có một entry point riêng, quy định các module cần chia sẻ và cung cấp thông tin về cách truy cập và tương tác với các module đó.

  4. Shared (shared dependencies): Shared dependencies là các thư viện hoặc module chung được sử dụng trong nhiều ứng dụng hoặc remote. Bằng cách xác định shared dependencies, bạn có thể tránh tải trùng lặp và giữ phiên bản nhất quán của các thư viện chung giữa các ứng dụng.

 

3. Hướng tiếp cận mới với NextJS Multi Zones

Trong Microfrontend với Next.js, việc liên kết giữa các microfrontend được thực hiện thông qua cơ chế nhúng và gọi các thành phần từ microfrontend khác trong ứng dụng Next.js chính. Các microfrontend có thể được nhúng như một thành phần trong ứng dụng chủ và giao tiếp thông qua các API hoặc truyền dữ liệu qua các sự kiện.

 

Multi Zones trong Next.js cho phép bạn tạo ra các vùng độc lập trong ứng dụng của mình, mỗi vùng chứa một hoặc nhiều microfrontend.

Dưới đây là các khái niệm quan trọng trong cơ chế Microfrontend trong Next.js với Multi Zones:

  1. Zone (vùng): Zone là một phạm vi độc lập trong ứng dụng Next.js, chứa một hoặc nhiều microfrontend. Mỗi vùng có thể đại diện cho một phần của ứng dụng hoặc một tính năng cụ thể.

  2. Microfrontend: Microfrontend là một phần của ứng dụng web, được phát triển và triển khai độc lập. Nó có thể là một ứng dụng hoàn chỉnh hoặc một phần của ứng dụng chính. Mỗi microfrontend có thể được triển khai và quản lý bởi một nhóm phát triển riêng.

  3. Vùng độc lập: Mỗi vùng trong ứng dụng Next.js được cấu hình và triển khai độc lập. Nó có thể có cấu trúc thư mục riêng, chứa các file cần thiết cho microfrontend trong vùng đó.

  4. Quản lý định tuyến: Cơ chế Microfrontend với Multi Zones trong Next.js cung cấp cách tiếp cận cho việc quản lý định tuyến và điều hướng giữa các vùng và microfrontend trong ứng dụng. Bạn có thể sử dụng các cơ chế định tuyến của Next.js như next/linknext/router để điều hướng giữa các vùng và microfrontend.

  5. Giao tiếp giữa các Microfrontend: Các microfrontend trong cùng một vùng có thể giao tiếp với nhau một cách trực tiếp thông qua việc chia sẻ dữ liệu hoặc gửi thông điệp giữa chúng. Mỗi microfrontend có thể nhúng và sử dụng các microfrontend khác trong cùng vùng.

 

V. Microfrontned với Turborepo và NextJS

Dưới đây là ví dụ về việc cấu hỉnh Microfrontend với Turborepo và NextJS

 

Project Structure

.
├── README.md                                           # README file
├── .vscode                                             # VSCode configuration
├── app
│   ├── expenso                                   # Expenso app
│   ├── storybook                                       # Storybook helps you build UI components
│   ├── ...                                             # Other app ...
├── packages
│   ├── eslint-config-custom                            # eslint configurations
│   ├── tailwind-config                                 # tailwind configurations
│   ├── tsconfig                                        # tsconfig configurations
│   ├── utils                                              # Utils
│   ├── ui                                              # UI Component
├── .eslintrc.json              
├── .prettierrc.json
├── .npmrc 
├── package.json                                    
└── turbo.json                                          # Turbo configuration

 

Ví dụ trên là một monorepo được xây dựng với Turborepo và NextJS:

 

  • Trong ./apps là các ứng dụng Micorfontend sử dụng NextJS
  • Trong ./packages là các packages dùng chung cho các microfrontend bao gồm UI components, utils, tsconfig, eslint-custom-config,...
  • Project sử dụng TailwindCss để xây dựng các component
  • Storybook phục vụ việc build UI components.

Link Repo: https://github.com/tranquocviet226/Microfrontend-with-Turborepo-and-NextJS-Storybook-Tailwindcss