
Micro-frontends là gì & tại sao cần?
Trong thời gian gần đây, khái niệm Micro-services trở nên cực kỳ phổ biến trong ngành IT nhờ khả năng giải quyết nhiều thách thức của kiến trúc truyền thống — như tách một ứng dụng lớn, phức tạp thành nhiều service độc lập, dễ mở rộng, tăng tính resilient, v.v.
Micro-frontend có thể hiểu là micro-service được triển khai và vận hành trên trình duyệt.
Dựa trên tư duy micro-services, micro-frontends xuất hiện vào năm 2016 như một giải pháp xử lý bài toán mở rộng ứng dụng. Khi ứng dụng phát triển lớn hơn, phức tạp hơn, việc maintain & phát triển feature mới dần trở nên khó khăn. Điều này khiến việc tách frontend thành nhiều ứng dụng độc lập trở nên hợp lý hơn. Việc áp dụng micro-frontends mang đến nhiều lợi ích rõ rệt - phần dưới đây sẽ phân tích chi tiết hơn.
Lợi ích của Micro-frontends
Scalability & Single Responsibility
Micro-frontend giúp đội ngũ kỹ thuật áp dụng kiến trúc Domain-Driven Design, chia hệ thống thành các module nhỏ, độc lập theo từng business domain. Mỗi team có thể sở hữu, phát triển và triển khai domain riêng của họ mà không ảnh hưởng các phần còn lại của hệ thống. Ví dụ trong một hệ thống e-commerce, chúng ta sẽ cần một trang tìm kiếm sản phẩm, một trang thanh toán, và một trang quản lý giỏ hàng. Với micro-frontends, các team có thể tập trung phát triển các module riêng biệt cho tìm kiếm sản phẩm, giỏ hàng, và thanh toán.
Sự phân chia này giúp nhiều nhóm có thể làm việc song song - phát triển tính năng mới, sửa lỗi, và triển khai (deploy) độc lập nhanh chóng hơn. Nhờ đó, tốc độ phát triển tổng thể của hệ thống được cải thiện đáng kể, cho phép doanh nghiệp phản ứng linh hoạt và nhanh hơn trước nhu cầu thị trường.

Hơn nữa, micro-frontends cho phép các nhóm toàn quyền sở hữu một domain nhất định trong ứng dụng. Kiến trúc này không chỉ giúp tổ chức mã nguồn rõ ràng hơn, dễ maintain hơn và tăng tính accountability, mà còn giảm sự xung đột và bottlenecks thường xảy ra khi nhiều team cùng phát triển trên một monolithic codebase.
Reliability
Tương tự như micro-services, micro-frontends mang lại mức độ tin cậy cao nhờ đặc tính tách biệt và độc lập của chúng. Nếu một micro-frontend gặp lỗi hoặc sự cố, các phần còn lại của ứng dụng vẫn tiếp tục hoạt động bình thường. Cơ chế fault isolation giúp ngăn chặn việc lỗi ở một module lan ra toàn hệ thống.
Reusability
Micro-frontends tăng khả năng tái sử dụng trong nhiều môi trường triển khai bằng cách khuyến khích xây dựng component độc lập, module hóa, dùng chung design system và common utilities. Điều này không chỉ giúp trải nghiệm người dùng nhất quán hơn, mà còn giảm effort phát triển lại những tính năng đã có.

Linh hoạt trong thiết kế & phát triển
Kiến trúc micro-frontends không bị ràng buộc bởi một công nghệ hay tech stack cụ thể, và cho phép nhiều team tự do đổi mới, lựa chọn công cụ phù hợp nhất với việc phát triển ứng dụng.

Triển khai nhanh hơn
Trong một ứng dụng monolith, thường chỉ có một pipeline CI/CD chịu trách nhiệm build và deploy toàn bộ ứng dụng lên production. Tuy nhiên, cách tiếp cận này có thể gây ra nhiều bất lợi, đặc biệt khi chỉ thực hiện những thay đổi nhỏ như chỉnh sửa style của một button hoặc một component nhỏ. Mỗi khi pipeline được kích hoạt, toàn bộ mã nguồn của ứng dụng sẽ được compile lại, dẫn đến việc deploy một bundle hoàn toàn mới. Quy trình này tạo ra các hạn chế sau:
- Thời gian build & deploy chậm: Việc compile toàn bộ ứng dụng có thể tốn nhiều thời gian, gây trì hoãn việc đưa thay đổi lên production.
- Ảnh hưởng đáng kể đến hiệu năng của người dùng: Mỗi khi deploy phiên bản mới, toàn bộ cache phía client sẽ bị vô hiệu hóa, buộc người dùng phải tải lại toàn bộ bundle ứng dụng một lần nữa.

Micro-frontends là một lựa chọn dễ quản lý hơn so với ứng dụng monolith. Với micro-frontends, mỗi ứng dụng có thể có CI/CD riêng. Do đó, bạn chỉ cần build và deploy phần code đã thay đổi, mà không ảnh hưởng đến các phần khác của ứng dụng. Ngoài ra, vì các ứng dụng khác không thay đổi nên không cần phải invalidate cache của chúng, giúp cải thiện hiệu năng và mang lại trải nghiệm người dùng tốt hơn.

Legacy Application Migration
Legacy application là những phần mềm đã lỗi thời hoặc lạc hậu nhưng vẫn đang được sử dụng. Những ứng dụng này thường trở thành bottleneck khi triển khai tính năng hoặc cải tiến mới do nhiều yếu tố, bao gồm giới hạn về công nghệ.
Bản chất của micro-frontends - với khả năng build và deploy độc lập cho từng component - giúp việc migrate ứng dụng cũ trở nên dễ dàng hơn, thích ứng tốt hơn với công nghệ mới và hỗ trợ mở rộng hệ thống. Cách tiếp cận này cho phép hiện đại hóa hệ thống dần dần, giúp team cập nhật hoặc thay thế các thành phần cũ theo từng bước mà không ảnh hưởng toàn bộ ứng dụng. Bằng cách sử dụng micro-frontends, tổ chức có thể vượt qua thách thức của legacy application và khai thác lợi ích từ các phương pháp và công nghệ phát triển hiện đại.

Nhược điểm của Micro-frontends
Thách thức trong việc xác định micro-frontends
Tương tự micro-services, việc xác định cách chia ứng dụng thành nhiều micro-frontends cần được cân nhắc kỹ. Nếu micro-frontends quá nhỏ, điều đó có thể dẫn đến phân mảnh quá mức, khiến việc quản lý nhiều ứng dụng trở nên phức tạp theo thời gian. Ngược lại, nếu micro-frontends quá lớn, chúng sẽ trở nên tightly coupled, làm mất đi lợi ích ban đầu của micro-frontends.
Một khía cạnh khác cần xem xét là giao tiếp giữa các ứng dụng. Nếu các ứng dụng cần giao tiếp với nhau quá thường xuyên, điều này có thể tạo ra coupling lớn và làm giảm hiệu quả của mô hình micro-frontends.
Kích thước Payload
Việc duplicate code giữa các micro-frontends có thể dẫn đến payload lớn. Ví dụ, nếu các micro-frontends dùng các phiên bản khác nhau của thư viện như React (ví dụ: ứng dụng A dùng phiên bản 16.0.0, ứng dụng B dùng phiên bản 18), client sẽ phải tải nhiều phiên bản thư viện, khiến payload tăng. Mặc dù có cách tối ưu để trình duyệt chỉ tải shared dependencies một lần, vẫn cần lưu ý khả năng xảy ra xung đột dependency, có thể gây lỗi hoặc hành vi không mong muốn.

Chi phí
Một nhược điểm của micro-frontends là chi phí đi kèm. Nhiều micro-frontends hơn đồng nghĩa sẽ có nhiều repository hơn, nhiều pipeline CI/CD hơn, nhiều server, nhiều domain hơn, v.v. Điều này làm tăng chi phí hạ tầng và tăng effort bảo trì.
Phối hợp giữa các nhóm
Mặc dù micro-frontends có thể được phát triển và triển khai độc lập, nhưng sự phối hợp và giao tiếp hiệu quả giữa các team vẫn là điều cần thiết, đặc biệt khi việc thay đổi ở một micro-frontend có thể ảnh hưởng đến micro-frontend khác. Đảm bảo sự cộng tác nhất quán giữa các team là yếu tố quan trọng để tránh xung đột và giữ trải nghiệm người dùng liền mạch.
Micro-frontends hoạt động như thế nào
Tích hợp ở build-time và tích hợp ở run-time
Build-time integration là phương pháp truyền thống trong chia sẻ code, nơi library được cài từ npm và được sử dụng lại trong ứng dụng. Tuy nhiên, cách này tạo ra một thách thức lớn: tất cả dependency sẽ nằm trong application bundle, làm kích thước ứng dụng tăng mỗi khi có thêm dependency mới.

Hình trên minh họa trường hợp Team B thay đổi Package B và Team D cần deploy phiên bản cập nhật lên production. Quy trình bao gồm:
- Team B build và publish package mới lên Package Registry.
- Team D cập nhật Package A lên phiên bản mới nhất.
- Team D build lại và deploy bundle mới lên production.
Mặt khác, run-time integration thì hiệu quả hơn trong việc chia sẻ code. Mỗi micro-frontend có thể build và deploy độc lập. Thông thường, một host application sẽ render các remote application bằng cách tải bundle của chúng tại run-time khi cần. Có ba dạng composition:
- Server-Side Composition
- Edge-Side Composition
- Client-Side Composition
Server-Side Composition
Khi client gửi request đến một URL, sẽ có một service hoặc backend nằm giữa browser và ứng dụng thực tế, chịu trách nhiệm kết hợp và render nhiều fragment hoặc micro-frontends thành một trang HTML hoàn chỉnh trước khi trả về client.

Edge-Side Composition
Tương tự Server-Side Composition, nhưng CDN sẽ đảm nhiệm việc rendering.
Client-Side Composition
Client-side composition sử dụng script trên browser để ghép nhiều micro-frontends thành một trang. Cách này cho phép preload, load và render từng phần khi cần. Ví dụ: khi truy cập homepage, chỉ tải bundle home.js; khi điều hướng sang product page, trình duyệt sẽ tải product.js. Bạn có thể preload để tăng tốc. Lợi thế lớn so với Server-Side & Edge-Side Composition là không cần reload lại trang khi render nội dung động.

Có nhiều cách triển khai run-time integration, đơn giản nhất là dùng iframe để compose ứng dụng trong host. Tuy nhiên, đây là phương pháp cũ và có nhiều hạn chế. Hiện nay đã có các công cụ tốt hơn như Webpack 5 Module Federation, Single SPA, qiankun, v.v.
Module Federation — công nghệ thay đổi cuộc chơi
Module Federation là một tính năng chính thức của Webpack cho phép dynamic load module từ nhiều hệ thống build độc lập.
Core concept của Module Federation là phân biệt module local và remote. Local là module nằm trong ứng dụng của bạn. Remote là module từ ứng dụng bên ngoài. Các remote module được load tại runtime, cho phép chia sẻ code linh hoạt giữa các hệ thống build khác nhau. Điều này cải thiện đáng kể khả năng phát triển web, đặc biệt trong micro-frontends.

Các lựa chọn thay thế Module Federation
Ngoài Module Federation còn nhiều framework và library phục vụ phát triển micro-frontends như SystemJS, Single SPA, qiankun.
Những framework này đã chứng minh được độ ổn định, cung cấp nhiều tính năng built-in. Tuy nhiên, dùng chúng có thể khiến ứng dụng bị phụ thuộc framework. Ngược lại, Module Federation không phải framework - mà chỉ là plugin của Webpack - giúp bạn linh hoạt chọn build tool.
Bằng cách áp dụng Module Federation, bạn có thể tận hưởng lợi ích của việc chia sẻ code và dynamic module loading, đồng thời vẫn giữ được sự tự do lựa chọn môi trường phát triển phù hợp với nhu cầu và yêu cầu của bạn. Tính linh hoạt này cho phép bạn tích hợp Module Federation một cách liền mạch vào workflow phát triển hiện tại mà không bị ràng buộc vào một framework cụ thể. Tóm lại, mỗi giải pháp thay thế đều có những điểm mạnh và điểm cần cân nhắc riêng. Việc đánh giá đúng yêu cầu và giới hạn của dự án sẽ giúp bạn xác định phương pháp phù hợp nhất.
Kết luận
Frontend hiện đại đã trở nên phức tạp hơn, và micro-frontends giúp giải quyết hạn chế của kiến trúc monolithic. Việc tách hệ thống thành nhiều ứng dụng độc lập giúp team làm việc tự chủ hơn, sử dụng công nghệ phù hợp nhất với họ. Micro-frontends mang lại lợi ích lớn về maintainability, reusability và adaptability cho ứng dụng web hiện đại.
Micro-frontends hiện đã phát triển ổn định và được hỗ trợ tốt bởi nhiều công cụ. Tuy nhiên mọi kiến trúc đều có trade-off. Micro-frontends cũng có độ phức tạp riêng, đòi hỏi thiết kế kỹ lưỡng và phù hợp nhất với hệ thống lớn. Với ứng dụng nhỏ và vừa, mô hình này có thể là dư thừa.
Trong bài tiếp theo, chúng tôi sẽ chia sẻ cách xây dựng micro-frontends với Module Federation và Vite. Hẹn gặp lại!
References
- https://martinfowler.com/articles/micro-frontends.html
- https://webpack.js.org/concepts/module-federation/
- https://single-spa.js.org/docs/microfrontends-concept
Bài viết được thực hiện bởi Duc Ta – Front-end Software Developer tại Home Credit Vietnam