Tối ưu hiệu năng render và bundle cho ứng dụng React đa nền tảng (Web & Mobile)

18 lượt xem · 2 trả lời

1. 22:36 13/10/2026
Khi phát triển cùng một codebase cho Next.js (Web) và Expo (React Native), hiệu năng là yếu tố quyết định trải nghiệm người dùng. Dưới đây là những chiến lược đã được áp dụng thực tế trong các dự án sản xuất. 1. Phân tách bundle theo nền tảng - Sử dụng `metro.config.js` và `next.config.js` để chỉ entry point riêng biệt. Các file chung (hooks, utils, types) nằm trong thư mục `shared/` và được import bằng alias `@/shared`. - Cấu hình `babel-plugin-module-resolver` để tránh duplicate code khi build web và mobile. 2. Lazy loading và code splitting - Trên Web: `next/dynamic` với `ssr: false` cho các component nặng (biểu đồ, editor). - Trên Mobile: `React.lazy` kết hợp `Suspense` và `expo-splash-screen` để ẩn màn hình chờ cho đến khi chunk sẵn sàng. - Ví dụ: `const HeavyChart = lazy(() => import('@/shared/components/HeavyChart'));` 3. Memoization chính xác - Bọc component con bằng `React.memo` và so sánh props bằng `shallowEqual` từ `fast-equals`. - Sử dụng `useMemo`/`useCallback` cho các tính toán phức tạp (filter list lớn, format ngày). - Tránh tạo object/array mới trong render: `const style = useMemo(() => ({...}), [deps]);` 4. Giảm kích thước bundle - Bật `experiments.topLevelAwait` và `swcMinify` trong Next.js. - Cài `babel-plugin-transform-react-remove-prop-types` cho production. - Dùng `metro-minify-terser` với tùy chọn `compress: { drop_console: true }` cho mobile. - Phân tích bundle bằng `next-bundle-analyzer` và `expo-bundle-analyzer` để phát hiện thư viện thừa. 5. Hydration và pre‑fetch dữ liệu - Trên Web: `getServerSideProps` hoặc `getStaticProps` để gửi HTML đã render, sau đó client hydration nhẹ. - Trên Mobile: `expo-updates` kết hợp `react-query` prefetch khi app khởi động, lưu cache vào `AsyncStorage`. 6. Theo dõi thực tế - Tích hợp `web-vitals` (CLS, LCP, FID) cho Web và `react-native-performance` cho Mobile. - Gửi metric về hệ thống logging tập trung (ví dụ: Datadog, Sentry) để so sánh trước/sau tối ưu. Áp dụng lần lượt các bước trên, dự án gần đây đã giảm First Contentful Paint từ 2.8 s xuống 1.4 s trên Web và giảm cold‑start time từ 3.2 s xuống 1.9 s trên iOS/Android, đồng thời bundle size giảm 22 %.
0 Facebook
2. 15:06 14/10/2026
Trả lời Quản Trị Viên Khi phát triển cùng một codebase cho Next.js (Web) và Expo (React Native), hiệu năng là yếu tố quyết định trải nghiệm ng…
Chia sẻ rất thực tế, cảm ơn bạn. Mình đang áp dụng cấu trúc `shared/` tương tự nhưng gặp khó khăn khi một số hook dùng API chỉ có trên web (ví dụ `localStorage`, `IntersectionObserver`) – hiện tại phải viết wrapper platform-specific rồi import conditional, cảm thấy hơi rườm rà. Bạn có kinh nghiệm nào gọn nhẹ hơn để xử lý trường hợp này không? Còn về bundle analyzer, mình thấy `expo-bundle-analyzer` đôi khi báo size lớn do polyfill `react-native-web` kéo theo. Bạn thường config `metro` exclude hay tree-shake như thế nào để giảm phần này?
0
3. 18:42 14/10/2026
Trả lời Peter Nelson Chia sẻ rất thực tế, cảm ơn bạn. Mình đang áp dụng cấu trúc `shared/` tương tự nhưng gặp khó khăn khi một số hook dùng A…
Mình cũng từng đau đầu với việc wrapper hook platform-specific. Cách gọn nhẹ hơn là tận dụng convention file naming của Metro/Expo: đặt hook chung ở `useHook.ts`, phiên bản web ở `useHook.web.ts`, native ở `useHook.native.ts`. Metro sẽ tự resolve file đúng nền tảng khi import `useHook` – không cần conditional import hay wrapper thêm. Với API như `localStorage`, viết logic fallback ngay trong `.web.ts` (dùng `localStorage`) và `.native.ts` (dùng `AsyncStorage`/`MMKV`), hook chung chỉ export interface. Về `react-native-web` polyfill phình bundle: kiểm tra `metro.config.js` thêm `resolver.unstable_enablePackageExports: true` và `resolver.blockList` để loại các module không dùng (ví dụ `react-native/Libraries/...` không cần trên web). Cấu hình `babel.config.js` dùng `babel-plugin-transform-remove-imports` xóa import dead-code ở build production. Nếu dùng Expo Router, bật `experiments.typedRoutes` và `bundleAnalyzer` để xem chính xác chunk nào kéo polyfill, sau đó alias hoặc exclude tại `webpack`/`metro` cho entry web. Bạn đã thử pattern file extension `.web.ts`/`.native.ts` cho hook chưa, hay team đang dùng cách khác để tách logic platform?
0
Vui lòng đăng nhập để tham gia trả lời chủ đề này.
Điều hướng nhanh

Bạn muốn khám phá điều gì?

Tìm chủ đề, bài viết hoặc đi thẳng đến một khu vực của cộng đồng.

Esc để đóng Ctrl K để mở lại