Micro-frontend Learning
Bắt đầu

Chuẩn bị môi trường

Chuẩn bị Node.js, package manager, trình duyệt và công cụ debug cho các bài thực hành.

Bạn mở shell được nhưng catalog không hiện: lỗi nằm ở code, remote chưa chạy, hay browser đang tải nhầm port? Khi học micro-frontend, bạn thường chạy nhiều dev server cùng lúc, nên một môi trường chưa thống nhất dễ làm bạn mất thời gian trước cả khi viết dòng tích hợp đầu tiên.

Bài này giúp bạn chuẩn bị toolchain và kiểm tra đường đi terminal → HTTP server → browser. Mình chọn Node.js 22 và npm làm mặc định để khớp repository hiện tại; cấu trúc workspace và cấu hình Module Federation thuộc các bài sau.

Phân biệt site docs và ứng dụng thực hành

Repository này hiện chứa site Next.js + Fumadocs, chưa có source shop với shell, catalog và cart. Chạy npm run dev ở gốc repo chỉ mở site tài liệu, không khởi động host/remote. Bài này không yêu cầu cài plugin Federation hay tạo ứng dụng shop.

Mục lục

Bạn cần chuẩn bị những gì

Bạn chưa cần Docker, Kubernetes, backend hay tài khoản cloud để bắt đầu. Trước hết, cần chạy được JavaScript tooling và nhìn được request mà browser gửi; đó là hai nơi bạn sẽ kiểm tra thường xuyên nhất.

Công cụLựa chọn mặc địnhDùng để làm gì
Node.jsMajor 22, bản patch phù hợp trong major nàyChạy package manager, bundler và dev server
Package managernpm đi kèm bản Node đã chọnCài dependencies và chạy scripts
GitBản còn được hỗ trợ trên hệ điều hành của bạnKiểm tra thay đổi source và lockfile
Terminalbash/zsh trên Linux, macOS hoặc WSL; PowerShell nếu dùng Windows nativeChạy nhiều process và đọc log riêng từng app
EditorVS Code hoặc editor có hỗ trợ TypeScriptĐọc lỗi type, imports và cấu hình
BrowserChrome hoặc Edge bản stable đang được cập nhậtDùng DevTools để xem network, runtime và storage

Firefox cũng dùng được. Mình chọn browser Chromium cho hướng dẫn này để tên panel và thao tác dễ đối chiếu; đây không phải yêu cầu của kiến trúc micro-frontend.

Nếu chưa quen ES modules, React hoặc TypeScript, bạn có thể đọc Kiến thức cần có song song. Không cần nắm toàn bộ Module Federation để hoàn thành bước chuẩn bị này.

Cài và chọn đúng Node.js

Repository có .nvmrc với giá trị 22, còn package.json khai báo engines.node là >=22. Hai thứ này không làm cùng một việc: engines mô tả yêu cầu của package, còn .nvmrc là chỉ dẫn cho công cụ quản lý version. Mở một terminal mới không tự đảm bảo Node đã chuyển sang 22.

Mình khuyên dùng Node 22 khi theo bài này thay vì tự chọn major mới nhất. Nếu workspace thực hành sau này khai báo version khác, hãy theo cấu hình của workspace đó và kiểm tra yêu cầu của bundler/plugin trước khi đổi.

Major giống nhau chưa có nghĩa môi trường giống hệt

.nvmrc chứa 22 không pin một bản patch cụ thể, cũng không cố định version npm. Khi cần tái lập chính xác giữa máy cá nhân và CI, team nên ghi nhận hoặc pin cả version Node và package manager. Với bài này, hãy kiểm tra version thực tế thay vì suy ra từ tên file.

Linux và macOS

Nếu đã có nvm, vào thư mục gốc repository rồi chạy:

nvm install
nvm use
node --version
npm --version

Không truyền version cho nvm install và nvm use để nvm đọc .nvmrc. Nếu chưa có nvm, cài theo hướng dẫn chính thức, mở lại terminal rồi chạy các lệnh trên. nvm là shell function; dùng command -v nvm để kiểm tra nó đã được load, thay vì chỉ tìm một executable bằng which.

Kết quả cần đạt: node --version bắt đầu bằng v22. và npm --version in ra một số version. Số patch Node và version npm cụ thể có thể khác giữa các lần cài.

Nếu đã dùng một version manager khác, bạn không cần cài thêm nvm chỉ để theo bài. Điều quan trọng là terminal trong editor và terminal ngoài editor cùng dùng version đã chọn.

Windows

Chọn một trong hai cách, đừng trộn toolchain trong cùng workspace:

Cách chạyKhi nên chọnCách chuẩn bị
WSL 2Bạn muốn dùng bash và thao tác gần Linux/CICài Git, Node và nvm bên trong WSL, rồi dùng các lệnh ở phần Linux
Windows nativeBạn muốn giữ PowerShell và tooling WindowsCài Node 22 từ nguồn chính thức hoặc dùng một Windows version manager hỗ trợ Node 22

Mình ưu tiên WSL nếu bạn mới bắt đầu và muốn copy các lệnh bash trong series. Đặt source trong filesystem Linux của WSL, chẳng hạn ~/projects/, để giảm vấn đề file watching và I/O qua filesystem Windows. Với VS Code, mở folder qua chế độ WSL để terminal và extensions chạy đúng môi trường.

nvm của nvm-sh không chạy trực tiếp trong PowerShell. Nếu dùng nvm-windows, đó là dự án riêng: chọn bản Node 22 cụ thể theo hướng dẫn của nó, không giả định các lệnh không có tham số sẽ đọc .nvmrc giống nvm trên Linux.

Không dùng chung node_modules giữa Windows và WSL

Dependencies có thể chứa binary hoặc optional package theo hệ điều hành. Hãy cài và chạy trong cùng một môi trường; nếu chuyển môi trường, dừng các process rồi cài lại dependencies ở nơi sẽ chạy ứng dụng. Không copy node_modules từ Windows vào WSL hoặc ngược lại.

Kiểm tra trong từng terminal

Chạy các lệnh sau trong cả terminal ngoài editor lẫn terminal tích hợp:

node --version
npm --version
git --version
node -p "process.execPath"
node -p "process.platform + ' ' + process.arch"

process.execPath cho biết binary Node thật sự đang được dùng. Nếu hai terminal trả về hai đường dẫn khác nhau, hãy kiểm tra PATH và cấu hình shell trước khi cài dependencies. Sau khi đổi Node, terminal mới có thể cần chạy lại nvm use.

Với WSL, process.platform nên là linux; với Windows native, giá trị là win32. Đây là cách nhanh để phát hiện bạn đang mở nhầm terminal.

Thống nhất package manager

Dùng npm cho repository hiện tại

npm là lựa chọn mặc định vì README hiện tại dùng npm và Node thường được phân phối kèm npm. Bạn không cần cài global webpack, Vite, Next.js hay TypeScript: scripts trong project dùng binary từ dependencies của project để tránh lệch version giữa các máy.

Cách cài phụ thuộc vào trạng thái lockfile:

Trạng thái projectLệnh phù hợpLý do
Chưa có package-lock.json, cài lần đầunpm installResolve dependencies và tạo lockfile
Đã có lockfile khớp package.json, muốn cài lại đúng dependency graphnpm ciCài theo lockfile và không cập nhật nó
Chủ động thêm hoặc cập nhật dependencynpm install hoặc lệnh thêm package cụ thểThay đổi manifest/lockfile là một phần công việc

npm ci xóa node_modules hiện có trước khi cài, và báo lỗi nếu manifest không khớp lockfile. Dừng dev server trước khi dùng lệnh này. Nếu lệnh báo lệch lockfile, hãy xem diff và xác định thay đổi nào có chủ đích; đừng xóa lockfile để né lỗi.

Nếu chưa có lockfile, lần cài đầu vẫn phụ thuộc vào version mà registry resolve tại thời điểm đó. Sau khi cài và kiểm tra thành công, lưu lockfile vào Git để các máy khác có điểm bắt đầu giống bạn.

Một workspace, một package manager

Đừng luân phiên npm, pnpm, Yarn và Bun trong cùng workspace chỉ vì một lệnh cài thất bại. Các manager có cách resolve và bố trí dependencies khác nhau. Nếu project đã có packageManager và lockfile của manager khác, hãy theo cấu hình đó; nếu muốn chuyển, chuyển có chủ đích và review thay đổi. Với repo hiện tại, cứ dùng npm.

Kiểm tra kết nối registry

Trước khi cài một cây dependencies lớn, kiểm tra registry mà npm đang dùng:

npm config get registry
npm ping

Registry công khai mặc định là https://registry.npmjs.org/, nhưng máy trong công ty có thể dùng registry nội bộ. npm ping thành công cho biết npm liên lạc được với registry đã cấu hình; nó không chứng minh mọi package hoặc tarball đều tải được, hay bạn có quyền truy cập private package.

Nếu gặp lỗi proxy, certificate hoặc timeout, sửa kết nối theo chính sách mạng của bạn. Đừng đặt strict-ssl=false hoặc tắt xác minh TLS để làm lệnh cài chạy qua. Với CA nội bộ, dùng cấu hình certificate được team cung cấp.

Chuẩn bị editor và browser

Editor và Git

Mở đúng folder gốc có package.json trong editor. Nếu dùng VS Code, chọn TypeScript version của workspace khi project đã cài TypeScript; như vậy lỗi type trong editor sẽ gần với kết quả typecheck của project hơn.

Có thể cài ESLint hoặc formatter extension nếu project có cấu hình tương ứng. Extension không thay thế scripts kiểm tra, và repo hiện tại không khai báo script lint — đừng xem việc không có gạch đỏ trong editor là bằng chứng build sẽ thành công.

Trước và sau khi chạy lệnh cài, dùng:

git status --short

Bạn nên nhìn thấy những thay đổi giải thích được, ví dụ lockfile mới sau lần cài đầu. Không commit node_modules, cache build hay file sinh tự động của tooling. Riêng site docs này, .source/ được sinh bởi Fumadocs; không cần viết tay hoặc commit nó.

Các panel DevTools cần dùng

Mở DevTools bằng menu browser hoặc F12 trên hệ thống có hỗ trợ phím này. Chuẩn bị các panel sau:

PanelBạn sẽ tìm gì khi debug micro-frontend
ConsoleException runtime, lỗi import, thông báo CORS hoặc CSP
NetworkURL thật của remote entry/chunks, status, response và request initiator
SourcesBreakpoint và source map để truy ngược lỗi về source
ApplicationlocalStorage, cookies, cache và service worker trên các origin liên quan

Trong Network, bật Preserve log nếu muốn giữ request qua navigation/reload. Bật Disable cache khi cần kiểm tra lượt tải mới; tùy chọn này có tác dụng khi DevTools đang mở. Chọn No throttling và bỏ chế độ offline cho lần kiểm tra đầu tiên.

Để nhìn remote assets sau này, dùng All hoặc bộ lọc JS, không chỉ Fetch/XHR. Một remote entry được tải bằng script tag có thể không xuất hiện trong bộ lọc Fetch/XHR.

Một response 200 chưa đủ: mở Response để xác nhận server trả JavaScript chứ không phải HTML fallback. Request của browser mới là bằng chứng ứng dụng đang tải từ đâu, không phải URL bạn nghĩ mình đã cấu hình.

React Developer Tools hữu ích khi các bài thực hành React đã chạy. Đây là công cụ bổ sung; bạn vẫn cần Console và Network để tìm lỗi remote chưa tải được.

Hiểu port và origin trước khi chạy nhiều app

Origin được xác định bởi scheme, hostname và port. Đổi một trong ba phần là đổi origin, dù tất cả server đều chạy trên cùng máy.

URLQuan hệ với http://localhost:4300
http://localhost:4300/shopCùng origin; path không làm đổi origin
http://localhost:4301Khác origin vì khác port
http://127.0.0.1:4300Khác origin vì khác hostname
https://localhost:4300Khác origin vì khác scheme

Như hai cửa hàng ở hai địa chỉ, các app có thể gần nhau nhưng browser vẫn phân biệt nơi lấy tài nguyên. Phép so sánh chỉ giúp nhớ địa chỉ: quy tắc cụ thể vẫn do browser áp dụng theo loại request và security policy, không phải cứ khác origin là mọi request đều bị cấm.

Khác origin có thể ảnh hưởng tới CORS, storage và cách gửi credentials. Riêng cookies không tách đơn giản theo port như origin; còn bị chi phối bởi domain, path, Secure và SameSite. Khi mới chạy local, giữ hostname và scheme nhất quán sẽ dễ kiểm tra hơn.

Không sửa CORS bằng cách tắt bảo mật browser

Mở URL remote trực tiếp được không có nghĩa host có quyền dùng mọi tài nguyên của remote. fetch, ESM và script cổ điển có quy tắc tải khác nhau. Khi tích hợp, kiểm tra Console, request headers và cấu hình server cho loại request thực tế; đừng khởi động browser với chế độ vô hiệu hóa web security.

Port của các app nên được thống nhất trong workspace, thay vì để server tự đổi port khi bị chiếm. Nếu host vẫn trỏ đến port cũ, remote có thể chạy bình thường ở một địa chỉ mà host không hề tải.

Trong repo hiện tại, site docs mặc định dùng port 3000 nếu còn trống. Các port 4300 và 4301 bên dưới chỉ dành cho phép thử của bài này, không phải cấu hình đã có cho shell/catalog/cart.

Kiểm tra môi trường bằng HTTP server nhỏ

Phép thử này dùng module có sẵn của Node, không tạo file và không cài package. Nó giúp tách lỗi môi trường khỏi lỗi bundler hoặc Federation.

Khởi động server

Ở một terminal đã chọn Node 22, chạy:

node -e "const http = require('node:http'); http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end('environment-ok'); }).listen(4300, '127.0.0.1', () => console.log('Ready: http://127.0.0.1:4300'));"

Lệnh dùng được trong bash/zsh và PowerShell. Kết quả mong đợi:

Ready: http://127.0.0.1:4300

Terminal tiếp tục bận vì server vẫn chạy; đó là trạng thái đúng. Server bind vào loopback 127.0.0.1, không mở ra toàn bộ mạng LAN. Nếu không xuất hiện dòng Ready, đọc lỗi terminal trước khi thử trên browser.

Kiểm tra từ browser và terminal

Mở http://127.0.0.1:4300 trên browser. Bạn nên thấy nội dung:

environment-ok

Mở Network trước rồi reload trang. Request document cần có status 200, body environment-ok và Content-Type là text/plain; charset=utf-8. Console không nên có lỗi tải document; extension của browser có thể phát log riêng, nên hãy xem URL và nguồn của thông báo.

Ở terminal thứ hai, chạy:

node -e "fetch('http://127.0.0.1:4300').then(async (res) => { console.log('status:', res.status); console.log('body:', await res.text()); }).catch((error) => { console.error(error); process.exitCode = 1; });"

Kết quả mong đợi:

status: 200
body: environment-ok

Nếu terminal nhận được response nhưng browser không mở được trang, kiểm tra proxy, extension và việc browser có đang dùng đúng địa chỉ không. Với WSL hoặc container, 127.0.0.1 thuộc môi trường chạy process; phép thử từ terminal xác nhận server bên trong môi trường đó, còn truy cập từ browser bên ngoài phụ thuộc vào forwarding/network của môi trường.

Thử hai server cùng lúc

Giữ server đầu chạy. Ở terminal thứ hai, khởi động một server khác:

node -e "const http = require('node:http'); http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end('second-server-ok'); }).listen(4301, '127.0.0.1', () => console.log('Ready: http://127.0.0.1:4301'));"

Mở cả hai URL và kiểm tra mỗi trang trả đúng nội dung riêng. Bạn vừa xác nhận máy có thể chạy hai process trên hai port và quan sát chúng từ browser:

direction: right
browser: Browser
s1: "127.0.0.1:4300"
s2: "127.0.0.1:4301"
ok1: environment-ok
ok2: second-server-ok
browser -> s1 -> ok1
browser -> s2 -> ok2
Browser127.0.0.1:4300127.0.0.1:4301environment-oksecond-server-ok
Browser127.0.0.1:4300127.0.0.1:4301environment-oksecond-server-ok
Thử hai server cùng lúc

Đây chưa phải host/remote: không server nào tải module từ server còn lại, và chưa có phép kiểm tra CORS hay shared dependencies. Bước này chỉ xác nhận phần môi trường nền tảng.

Nhấn Ctrl+C trong từng terminal server để dừng cả hai process và trả lại port trước khi chuyển bài.

Chạy site tài liệu nếu cần

Bạn có thể bỏ qua phần này nếu đang đọc site đã deploy. Nếu muốn xem docs ngay trên máy, vào gốc repository và cài dependencies bằng lệnh phù hợp với trạng thái lockfile ở phần trên, sau đó chạy:

npm run check:docs
npm run dev

Lệnh cài thông thường sẽ chạy postinstall để sinh metadata Fumadocs. Đừng tắt lifecycle scripts nếu chưa hiểu tác động tới bước sinh này.

Mở http://localhost:3000/docs nếu terminal báo port 3000; nếu server chọn port khác, dùng địa chỉ thực tế trong log. Trang này có đường dẫn /docs/bat-dau/moi-truong.

Để kiểm tra source và bản build, dừng dev server nếu không còn cần rồi chạy lần lượt:

npm run typecheck
npm run build
npm run check:export

check:docs chỉ kiểm tra cấu trúc tài liệu, không thay thế MDX compilation hoặc build. Site dùng static export: bản build nằm trong out/, không chạy bằng next start. Chi tiết preview và deploy nằm trong README của repo, không cần hoàn thành để chuyển sang bài toán shop.

Xử lý lỗi môi trường thường gặp

Đọc lỗi đầu tiên và xác định nó xuất hiện ở terminal cài đặt, terminal server hay browser. Ba nơi đó kiểm tra ba đoạn khác nhau của đường đi; sửa dependencies sẽ không giải quyết được một URL đang trỏ nhầm port.

Triệu chứngKiểm tra trướcHướng xử lý
node hoặc npm không được tìm thấyPATH, terminal hiện tại và command -v nvm nếu dùng nvmMở lại terminal, load version manager và chọn Node 22
Editor dùng Node khác terminal ngoàinode -p "process.execPath" ở cả hai nơiKiểm tra shell tích hợp, khởi động lại terminal/editor nếu cần
EBADENGINE hoặc cảnh báo engineVersion Node thực tế và engines của package bị báo lỗiChọn version đáp ứng cả project lẫn tooling; không dùng --force để che cảnh báo
npm ci báo không có hoặc không khớp lockfilepackage.json, lockfile và Git diffCài lần đầu bằng npm install nếu chưa có lockfile; nếu lệch, đồng bộ thay đổi có chủ đích
EACCES khi cài packageQuyền sở hữu folder và vị trí Node/npmDùng workspace thuộc user của bạn, sửa quyền theo môi trường; không dùng sudo npm install làm mặc định
Registry timeout, EAI_AGAIN hoặc lỗi certificatenpm config get registry, DNS, proxy và CASửa mạng/certificate theo chính sách; giữ xác minh TLS bật
EADDRINUSEPort bị chiếm và các terminal còn chạyDừng process bạn nhận diện được, hoặc chọn port thử khác rồi cập nhật URL tương ứng
Browser báo connection refused hoặc Node fetch thất bạiDòng Ready, process server, hostname và portChạy server trước, sửa URL; với WSL/container kiểm tra forwarding
Server chạy ở port khác dự kiếnLog startup và cấu hình portDọn port hoặc cập nhật các địa chỉ liên quan; không chỉ sửa URL mở trên browser
Sửa source nhưng không thấy thay đổiNetwork cache, file watching và service workerReload với Disable cache khi debug; kiểm tra đúng folder/process, chỉ xóa storage của origin thử nghiệm nếu cần

Nếu cần tìm process đang giữ port 4300, dùng công cụ phù hợp với hệ điều hành:

Linux
ss -ltnp 'sport = :4300'
macOS
lsof -nP -iTCP:4300 -sTCP:LISTEN
Windows PowerShell
Get-NetTCPConnection -LocalPort 4300 -State Listen |
  Select-Object LocalAddress, LocalPort, OwningProcess

Một số môi trường không cài sẵn các công cụ này, và thông tin process có thể bị giới hạn bởi quyền. Ưu tiên quay lại terminal đã khởi động server và nhấn Ctrl+C. Đừng kill hàng loạt process Node vì có thể làm dừng project khác hoặc tooling của editor.

Checklist trước bài tiếp theo

Bạn sẵn sàng bắt đầu dựng ví dụ khi kiểm tra được những điểm sau:

  • Terminal ngoài editor và terminal tích hợp cùng dùng Node 22; biết binary Node nằm ở đâu.
  • npm --version và git --version chạy được; đã chọn npm cho repo hiện tại.
  • Truy cập được registry cần dùng, hoặc đã biết giới hạn mạng cần giải quyết trước khi cài package.
  • Biết khi nào dùng npm install, khi nào dùng npm ci, và không trộn lockfile của nhiều manager.
  • Mở được Console, Network, Sources và Application trong browser.
  • Hai HTTP server thử nghiệm trả đúng nội dung; đã dừng cả hai bằng Ctrl+C.
  • Phân biệt được site docs với shop thực hành; không kỳ vọng npm run dev của repo hiện tại chạy shell/catalog/cart.

Nếu một mục chưa đạt, hãy sửa ngay ở phép thử nhỏ. Khi thêm bundler và Federation, lỗi sẽ có nhiều lớp hơn và khó xác định nguyên nhân hơn.

Đọc tiếp

Tài liệu tham khảo

On this page