Metro Bundler là một trình đóng gói JavaScript chuyên dụng của Meta, được phát triển riêng cho React Native và nằm trong lõi của framework. Theo tài liệu chính thức của React Native 0.76 (2025), Metro cung cấp bản dựng gia tăng với Fast Refresh và phân giải module với các phần mở rộng dành riêng cho nền tảng .native.js, .ios.js và .android.js. Không giống như Webpack, Metro không sử dụng bộ nhớ đệm đồ thị module dài hạn — thay vào đó, nó xây dựng lại đồ thị mỗi khi tệp thay đổi, mang lại tải lại nóng tức thì trong quá trình phát triển.
Những điểm chính
Metro Bundler là một trình đóng gói JavaScript mã nguồn mở được Meta phát triển cho React Native và được sử dụng mặc định trong tất cả các dự án của framework. Nhiệm vụ của Metro là lấy mã JavaScript của dự án cùng với các phụ thuộc và đóng gói thành một hoặc nhiều bundle chạy trên thiết bị. Không giống như các trình đóng gói đa năng (Webpack, Rollup, Parcel), Metro được tối ưu hóa cho đặc thù phát triển di động: thời gian xây dựng tối thiểu, cập nhật gia tăng trong quá trình phát triển và xử lý chính xác các module nền tảng (module gốc Objective-C, Swift, Java, Kotlin). Metro được đi kèm trong React Native CLI và không yêu cầu cài đặt riêng. Bắt đầu từ React Native 0.72, Metro phiên bản 0.80+ hỗ trợ biên dịch song song các module, tăng tốc độ xây dựng trên bộ xử lý đa nhân lên đến 40%.
Kiến trúc của Metro được chia thành ba thành phần độc lập: Resolver, Transformer và Bundler. Resolver chịu trách nhiệm tìm kiếm và phân giải module — nó đọc các biểu thức import/require, tìm các tệp tương ứng có tính đến phần mở rộng nền tảng và trả về đường dẫn tuyệt đối. Transformer thực hiện biên dịch: áp dụng Babel với các preset và plugin, chuyển đổi JSX, TypeScript hoặc Flow thành JavaScript thuần túy. Bundler là giai đoạn cuối cùng: nó nhận đồ thị phụ thuộc từ Resolver và các tệp đã biến đổi từ Transformer, sau đó tuần tự hóa chúng thành một hoặc nhiều bundle (module bundles). Việc chia thành ba bước cho phép Metro lưu trữ kết quả của mỗi giai đoạn: nếu chỉ một tệp thay đổi, Resolver và Bundler có thể sử dụng bộ nhớ đệm cho các module còn lại, mang lại tốc độ xây dựng tăng lên đến 10 lần trong chế độ phát triển.
Resolver trong Metro triển khai thuật toán phân giải module tương thích một phần với phân giải module của Node.js. Sự khác biệt chính so với Node.js là hỗ trợ các phần mở rộng nền tảng: require(‘./Component’) tìm kiếm Component.native.js, Component.ios.js, Component.android.js theo thứ tự ưu tiên được chỉ định. Resolver cũng hỗ trợ trường package.json “react-native” để ánh xạ module sang các triển khai thay thế — đây là cơ chế tiêu chuẩn cho các thư viện có mã dành riêng cho nền tảng. Nếu không tìm thấy tệp, Resolver sẽ ném ra lỗi với toàn bộ ngăn xếp tìm kiếm.
Transformer bên trong Metro sử dụng Babel với preset metro-react-native-babel-preset. Cấu hình tiêu chuẩn bao gồm: chuyển đổi JSX thành React.createElement, hỗ trợ TypeScript (loại bỏ kiểu), hỗ trợ Flow và polyfill cho các chuẩn JavaScript hiện đại (async/await, optional chaining, nullish coalescing). Transformer hoạt động ở chế độ song song: mỗi module được biên dịch độc lập, sử dụng một nhóm các tiến trình worker (mặc định, số lượng tương ứng với số CPU). Bắt đầu từ Metro 0.80, Granular Transformer Cache được hỗ trợ — vô hiệu hóa bộ nhớ đệm ở cấp độ tệp riêng lẻ.
Một trong những tính năng chính của Metro là hỗ trợ các phần mở rộng tệp nền tảng. Một dự án React Native có thể chứa ba phiên bản của cùng một module: Component.ios.js (iOS), Component.android.js (Android) và Component.native.js (cả hai nền tảng). Khi import require(‘./Component’), Resolver tự động chọn phiên bản chính xác tùy thuộc vào nền tảng xây dựng mục tiêu. Điều này cho phép viết mã phụ thuộc nền tảng mà không cần cấu trúc Platform.OS có điều kiện. Thứ tự ưu tiên: name.platform.js > name.native.js > name.js. Phần mở rộng .native.js được sử dụng cho mã chung hoạt động trên cả hai nền tảng nhưng không tương thích với web. Các phần mở rộng .ios.js và .android.js phục vụ cho việc triển khai các tính năng cụ thể — điều hướng, cử chỉ, thao tác hệ thống tệp. Metro hỗ trợ các phần mở rộng tùy chỉnh thông qua cấu hình resolver.sourceExts.
// metro.config.js — thiết lập sourceExts và watchFolders
const config = {
resolver: {
sourceExts: ['jsx', 'js', 'tsx', 'ts', 'json'],
platformExtensions: ['ios', 'android', 'native'],
},
transformer: {
babelTransformerPath: require('metro-react-native-babel-transformer'),
},
watchFolders: [path.resolve('../shared')],
};
Fast Refresh là cơ chế tải lại nóng cho React Native được xây dựng trên Metro. Khi nhà phát triển thay đổi tệp, Metro chỉ biên dịch lại module đã thay đổi và gửi bản cập nhật đến ứng dụng qua WebSocket. Fast Refresh cập nhật giao diện mà không tải lại toàn bộ ứng dụng và giữ nguyên trạng thái component React nếu chỉ JSX hoặc kiểu thay đổi. Nếu mã có hook hoặc trạng thái thay đổi, Fast Refresh chỉ gắn kết lại component đã thay đổi. Metro hỗ trợ hai chế độ: Hot Module Replacement (HMR) để thay thế module nhanh và Live Reload để tải lại toàn bộ ứng dụng khi module gốc hoặc cấu hình thay đổi. Fast Refresh được bật mặc định trong React Native 0.76 và không yêu cầu cấu hình bổ sung — chỉ cần chạy npx react-native start.
| Chế độ | Tốc độ | Giữ trạng thái | Trình kích hoạt |
|---|---|---|---|
| Fast Refresh | 200-500ms | Có | Thay đổi tệp JS/TS |
| HMR | 100-300ms | Có | Thay đổi CSS/kiểu |
| Live Reload | 1-3s | Không | Thay đổi cấu hình gốc |
| Full Rebuild | 10-60s | Không | Thay đổi podspec/build.gradle |
Tệp metro.config.js là tệp cấu hình Metro nằm ở thư mục gốc của dự án React Native. Trong đó cấu hình: resolver (sourceExts, platformExtensions, extraNodeModules), transformer (babelTransformerPath, minifierConfig), server (port, host, enableFastRefresh) và watcher (watchFolders, healthCheck). Cấu hình Metro tiêu chuẩn kế thừa từ gói @react-native/metro-config (React Native 0.76+). Đối với dự án monorepo, hãy thêm watchFolders — điều này cho phép Metro theo dõi các thay đổi trong gói bên ngoài thư mục gốc dự án. Để cấu hình sourceExts, hãy thêm ‘svg’, ‘png’, ‘gql’ cho các bộ biến đổi tùy chỉnh. Metro hỗ trợ cấu hình bất đồng bộ thông qua async function — hữu ích cho việc tạo cấu hình động dựa trên môi trường.
Tối ưu hóa xây dựng Metro bắt đầu với cấu hình bộ nhớ đệm phù hợp. Đặt maxWorkers bằng số CPU trừ 1. Đối với bản phân phối, sử dụng resetCache trên CI. Giảm thiểu sourceExts — các phần mở rộng thừa làm chậm phân giải module. Đối với dự án lớn, cấu hình watchFolders chỉ cho các thư mục cần thiết. Metro hỗ trợ nén Hermes bytecode, cho kích thước bundle nhỏ hơn Terser tiêu chuẩn — sử dụng minifierPath: ‘metro-minify-terser’.
Metro hỗ trợ chế độ xây dựng trực tiếp thành Hermes bytecode — bỏ qua giai đoạn AST của JavaScript. Khi xây dựng với HermesTransformer, các module được biên dịch thành HBC (Hermes ByteCode) thay vì JavaScript thuần túy. Điều này mang lại: kích thước bundle nhỏ hơn (30-40%), khởi động ứng dụng nhanh hơn (20-30%) và tiêu thụ bộ nhớ thấp hơn. Để kích hoạt, đặt hermesCommand trong metro.config.js và kích hoạt cờ Hermes trong build.gradle (Android) hoặc Podfile (iOS). Xây dựng bundle Hermes được thực hiện trong hai giai đoạn: đầu tiên Metro xây dựng bundle JavaScript, sau đó Hermes CLI chuyển đổi nó thành HBC. Bắt đầu từ React Native 0.70, Hermes là công cụ mặc định trên Android, trên iOS cần kích hoạt tường minh.
Sự khác biệt giữa Metro và Webpack là do các mục tiêu khác nhau. Webpack là trình đóng gói đa năng cho web với hệ sinh thái plugin và loader khổng lồ. Metro là trình đóng gói chuyên dụng cho React Native, nơi ưu tiên là tốc độ xây dựng gia tăng và hoạt động chính xác với module gốc. Webpack sử dụng đồ thị module dài hạn với vô hiệu hóa bộ nhớ đệm thông minh — điều này mang lại khả năng xây dựng lại nhanh trên web nhưng tạo ra vấn đề với phần mở rộng nền tảng. Metro không lưu trữ đồ thị giữa các lần xây dựng mà xây dựng nó mỗi lần — điều này đơn giản hóa việc xử lý phần mở rộng nền tảng và module Haste. Webpack hỗ trợ import động với chunk, Metro cũng vậy — thông qua React.lazy() và Suspense, nhưng với giới hạn một yêu cầu hoạt động. Hệ sinh thái của Metro nhỏ hơn đáng kể: không có thay thế cho style-loader, css-loader, file-loader — những tác vụ này được giải quyết khác trong React Native.
Metro là lựa chọn đúng đắn duy nhất cho các dự án React Native. Webpack không hỗ trợ phân giải nhận biết nền tảng mặc định và việc thiết lập React Native với Webpack đòi hỏi nỗ lực đáng kể (haul bundler, expo web packager). Metro được tích hợp vào React Native CLI, được hỗ trợ bởi nhóm chính thức của Meta và nhận cập nhật với mỗi bản phát hành React Native. Đối với dự án React Native Web, bạn có thể sử dụng Webpack cho bản dựng web trong khi giữ Metro cho bundle di động.
Câu hỏi thường gặp
Chạy npx react-native start --reset-cache hoặc xóa thư mục $TMPDIR/metro-* và thư mục .metro-health-check* trong thư mục gốc dự án. Thay thế: npx react-native clean — lệnh này xóa tất cả tệp tạm thời của Metro, bao gồm bộ nhớ đệm Babel và bản đồ Haste. Sau khi xóa, bản dựng đầu tiên sẽ là bản dựng đầy đủ (60-120 giây), nhưng các bản dựng gia tăng tiếp theo sẽ trở lại tốc độ bình thường.
Kiểm tra rằng gói nằm trong dependencies của package.json (không phải devDependencies). Nếu module nằm trong monorepo, hãy thêm đường dẫn vào watchFolders trong metro.config.js. Metro không theo dõi symlink theo mặc định — sử dụng resolver.extraNodeModules để ánh xạ tường minh. Đối với Yarn PnM, đặt resolver.useWatchman: false. Nếu module sử dụng phần mở rộng nền tảng, hãy đảm bảo rằng tệp .ios.js hoặc .android.js tồn tại tại đường dẫn đã chỉ định.
Tăng maxWorkers trong metro.config.js lên số CPU trừ 1. Cấu hình watchFolders chỉ cho các thư mục cần thiết. Sử dụng Hermes bytecode cho bản dựng sản xuất — tăng tốc bản dựng cuối cùng bằng cách bỏ qua nén JS. Đối với phát triển, bật Fast Refresh (nó được bật mặc định). Giới hạn sourceExts chỉ ở các phần mở rộng cần thiết. Cân nhắc chia bundle thành các chunk thông qua tải lười.
Về mặt kỹ thuật có, nhưng không được khuyến nghị. Metro không được tối ưu hóa cho bản dựng web: không hỗ trợ CSS, HTML, hình ảnh như module, không có code splitting với import động ở cấp trình duyệt. Đối với web, hãy sử dụng Webpack, Vite hoặc Parcel. Metro là giải pháp chuyên dụng cho React Native và cố gắng thích ứng nó cho web sẽ dẫn đến mất hiệu suất và thiếu hệ sinh thái loader.
Re.Pack là công cụ cộng đồng để thay thế Metro bằng Webpack trong các dự án React Native. Nó cung cấp quyền truy cập vào hệ sinh thái loader Webpack (css-loader, svg-loader) và code splitting nâng cao. Tuy nhiên, Re.Pack phức tạp hơn để cấu hình, không được Meta hỗ trợ chính thức và không đảm bảo tương thích với các phiên bản React Native mới. Metro vẫn là trình đóng gói duy nhất được hỗ trợ chính thức, mang lại sự ổn định và tương thích được đảm bảo với mỗi phiên bản.
Tóm tắt
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm