Building a region‑aware, SEO‑friendly global web app
Bài tóm tắt Mercari 2025 4. Điều chỉnh Độ khó: Trung bình
Mercari · 2025 · 4. Điều chỉnh · Độ khó: Trung bình — bài gốc
Một bài trong series Global App (ngoài sheet). Bối cảnh: Mercari 2025. Bài tiếp của cùng tác giả: Mercari 2025; chi tiết lấy dữ liệu: Mercari 2025.
Bối cảnh
- 2024: để khách nước ngoài mua trực tiếp, đội nhỏ chọn dùng lại web Nhật (jp.mercari.com): khách Đài Loan đăng ký, xem, mua qua đối tác Buyee; đã có i18n nên thêm ngôn ngữ dễ. Ra nhanh, số liệu tốt, rồi mở cho Hồng Kông và thêm giỏ hàng gộp vận chuyển. Nhưng phát triển ngày càng vất vả; mở rộng tiếp web Nhật không bền.
- Web Nhật: ban đầu là JAMstack trên Gatsby với pre-render động cho SEO (dựng headless browser cho mỗi request, đắt), vài năm trước chuyển Next.js Pages Router nhưng vẫn là app client lớn được bơm dữ liệu để SSR trang SEO. Trang chi tiết sản phẩm cần hơn 20 lần fetch, có chuỗi nối tiếp qua API gateway.
- Trang dùng chung giữa các vùng: tiền tệ suy ra từ IP nên cùng URL trả HTML khác nhau theo nơi gọi; bot search thường gọi từ Mỹ nên SEO theo vùng gần như bất khả; QA phải dùng VPN theo vùng; tính năng chỉ dành cho Nhật hay lọt sang khách quốc tế.
Thay đổi chính
- Một BFF dùng chung cho web, iOS, Android: backend nghĩ theo resource, frontend nghĩ theo view model; ở web Nhật, có tính năng mới mà frontend cần hơn 100 dòng chỉ để biến đổi dữ liệu. Cân nhắc GraphQL nhưng chọn Protobuf + ConnectRPC, cùng giao thức với giao tiếp giữa module backend, để ít công nghệ hơn. BFF viết bằng Go, nằm ở backend nhưng sở hữu chung giữa client và backend. Theo tác giả, lần viết lại web Nhật trước mất khoảng 18 tháng, lần này phát triển tính năng xong trong 6 tháng, phần lớn nhờ điều phối và logic nghiệp vụ nằm ở BFF.
- Next.js App Router + React Server Components cho app mới (dựng bằng công cụ Web Bootstrap của đội Frontend Enabling, sinh cả PR Terraform và manifest Kubernetes): RSC render ra chuỗi, không phải gửi cả app để hydrate. Hệ sinh thái RSC còn non: test chuyển từ Jest + React Testing Library sang Storybook với wrapper cho component async lồng nhau, chạy trên CI bằng Vitest. Theo real user metrics, dù chưa tối ưu hay cache gì, hiệu năng đã tốt hơn rõ so với web Nhật.
- Subdomain theo vùng (
tw.mercari.com,hk.mercari.com) thay cho ccTLD hay thư mục theo vùng: tín hiệu rõ cho bot, giống jp.mercari.com, dễ quản lý hơn nhiều ccTLD, định tuyến tới server gần qua DNS, sau này tách riêng một vùng dễ. App Router chỉ hiểu đường dẫn nên middleware rewritehk.mercari.com/enthành/hk/ennội bộ; thư mụcapp/[region]/[locale]; tham số vùng truyền xuống BFF (ví dụ giá theo HKD). Local dùngtw.localhost. <html lang="en-TW">vàlink rel="alternate" hreflangcho mọi biến thể để các subdomain không cạnh tranh nhau trên kết quả search.
Vì sao
- Mỗi trang phải tất định theo URL để SEO và QA được; logic điều phối nhân ba trên ba client là nguồn chậm và lỗi.
Bài học cho SWE
- Dùng lại sản phẩm cũ cho thị trường mới là đường nhanh nhất để kiểm nhu cầu; khi đã chứng minh, chi phí đắp thêm tăng nhanh hơn chi phí làm lại.
- Nội dung phụ thuộc vị trí người gọi mà không nằm trong URL phá cả cache, SEO lẫn QA.
- BFF chung cho nhiều client chuyển logic ghép dữ liệu khỏi ba nơi về một.
Liên quan
- Kiến trúc frontend
- Cùng series: Mercari 2025 · Mercari 2025 · Mercari 2025 · Mercari 2025
- Hai nguồn rời Next.js cùng năm: Railway 2026 · Inngest 2026
- Tầng aggregation trước microservice: Dream11 2021
#BFF#ConnectRPC#Protobuf#GraphQL#Next.js App Router#React Server Components#Pages Router#Gatsby#SEO#regional subdomain#middleware rewrite#hreflang#Storybook#Vitest
Được nhắc tới trong
Công ty (1)
Bài tóm tắt (3)