Metro: định nghĩa, các tính năng chính và nguyên lý hoạt động

Tác giả: IT Sectr Đã đăng: 2026-05-19 Thời gian đọc: 8 phút

Metro là một bundler JavaScript được phát triển đặc biệt cho React Native và được sử dụng mặc định để xây dựng ứng dụng di động trên nền tảng này. Không giống như các bundler đa năng, Metro được tối ưu hóa cho tài nguyên hạn chế của thiết bị di động và cung cấp tích hợp với công cụ Hermes và Fast Refresh. Theo Metro Documentation (2026), bundler này xử lý hơn 90% dự án React Native trên thế giới.

Những điểm chính

  • Metro là bundler mặc định cho React Native, được tối ưu hóa cho phát triển di động trên iOS và Android.
  • Kiến trúc ba pha của Metro bao gồm giải quyết module, biến đổi và tuần tự hóa thành bundle đầu ra.
  • Fast Refresh là cơ chế tải lại nóng các component mà không mất trạng thái ứng dụng.
  • Inline Requires trì hoãn việc tải module cho đến lần gọi đầu tiên, giảm kích thước bundle ban đầu.
  • Hermes là công cụ JavaScript của Meta sử dụng Metro để tạo mã byte đã được biên dịch trước.

Metro là gì?

Metro là một bundler JavaScript mã nguồn mở được tạo bởi nhóm Meta cho React Native. Nó đã thay thế Packager từ các phiên bản đầu của React Native và trở thành công cụ build tiêu chuẩn cho nền tảng này. Metro không được thiết kế cho phát triển web: kiến trúc của nó tập trung hoàn toàn vào các ứng dụng di động chạy trên công cụ JavaScript JSC (JavaScriptCore) hoặc Hermes.

Lịch sử phát triển và định vị

Metro xuất hiện vào năm 2018 để thay thế React Native Packager cũ. Lý do chính cho sự ra đời của nó là nhu cầu về một bundler hoạt động hiệu quả với hàng triệu module trong các ứng dụng di động lớn. Không giống như Webpack, Metro không hỗ trợ CSS, HTML hoặc hình ảnh như các module — những tài nguyên này được xử lý bởi các công cụ React Native riêng biệt. Facebook sử dụng Metro để xây dựng ứng dụng chính của mình, chứa hơn 100 nghìn tệp tin.

Metro được phân phối qua npm dưới dạng gói metro và được cài đặt tự động cùng với React Native CLI. Phiên bản Metro gắn liền với phiên bản React Native, vì vậy việc cập nhật bundler diễn ra cùng với cập nhật nền tảng.

Bundler Metro hoạt động như thế nào?

Metro nhận đầu vào là điểm vào của ứng dụng, xây dựng đồ thị phụ thuộc, biến đổi mỗi module và tuần tự hóa kết quả thành một bundle duy nhất. Quá trình trải qua ba pha: Resolve (giải quyết module), Transform (biến đổi) và Serialize (tuần tự hóa).

Quy trình build trong Metro

js
// Ví dụ cấu hình Metro cho biến đổi tùy chỉnh
const metroConfig = {
  transformer: {
    babelTransformerPath: require('metro-babel-transformer'),
    async transform({ src, filename, options }) {
      const result = await babelTransform({ src, filename, options });
      return {
        ast: result.ast,
        code: result.code,
        map: result.map,
        dependencies: [],
      };
    },
  },
  serializer: {
    createModuleIdFactory() {
      let nextId = 0;
      const moduleIds = new Map();
      return ({ path }) => {
        if (!moduleIds.has(path)) {
          moduleIds.set(path, nextId++);
        }
        return moduleIds.get(path);
      };
    },
  },
};

Trong pha Resolve, Metro xác định vị trí của mỗi module được import, tính đến các bí danh và node_modules. Trong pha Transform, mỗi tệp tin đi qua bộ biến đổi Babel để chuyển đổi JSX, TypeScript và các phần mở rộng khác thành JavaScript thuần túy. Pha cuối cùng Serialize thu thập tất cả các module đã biến đổi thành một hoặc nhiều tệp bundle.

Kiến trúc của Metro

Metro được xây dựng trên kiến trúc mô-đun, nơi mỗi giai đoạn build được triển khai như một thành phần riêng biệt. Điều này cho phép thay thế các module tiêu chuẩn bằng module tùy chỉnh mà không cần thay đổi lõi của bundler. Kiến trúc Metro bao gồm ba gói chính: metro, metro-configmetro-resolver.

Các thành phần chính của Metro

Metro Server — máy chủ phát triển được khởi động bằng lệnh npx react-native start. Nó phục vụ các yêu cầu biến đổi module theo thời gian thực, cung cấp Fast Refresh. Module Store — bộ đệm lưu trữ các module đã biến đổi trong bộ nhớ để tăng tốc độ rebuild. Dependency Graph — đồ thị phụ thuộc được cập nhật gia tăng khi các tệp tin thay đổi.

Watchman — trình theo dõi tệp tin của Meta mà Metro sử dụng để phát hiện các thay đổi trong hệ thống tệp tin. Nếu không có Watchman, Metro phải quét lại toàn bộ cấu trúc tệp tin mỗi khi có thay đổi, làm chậm đáng kể quá trình phát triển. Cài đặt Watchman là bắt buộc để làm việc thoải mái với Metro trên các dự án ở mọi quy mô.

Cấu hình Metro trong dự án React Native

Cấu hình của Metro được đặt trong tệp metro.config.js ở thư mục gốc của dự án. Một tệp điển hình xác định các thư mục bổ sung để tìm kiếm module, danh sách chặn để loại trừ các tệp không cần thiết và các bộ biến đổi tùy chỉnh. Trong React Native 0.72+, tính năng tự động phát hiện cấu hình được sử dụng, nhưng đối với monorepo, cấu hình là bắt buộc.

Cấu hình Metro cơ bản cho React Native

js
// metro.config.js
const config = {
  resolver: {
    sourceExts: ['js', 'jsx', 'ts', 'tsx', 'json'],
    nodeModulesPaths: ['node_modules'],
    blockList: [/\.test\.js$/, /__tests__\/.*/],
    extraNodeModules: {
      'shared-components': path.resolve(__dirname, '../shared/src'),
    },
  },
  transformer: {
    minifierConfig: {
      keep_classnames: true,
      keep_fnames: true,
      mangle: { reserved: ['React', 'Component'] },
    },
  },
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);

blockList loại trừ các tệp kiểm thử khỏi build, giảm kích thước bundle. nodeModulesPaths chỉ định các đường dẫn bổ sung để tìm kiếm gói — rất quan trọng đối với monorepo. extraNodeModules tạo bí danh cho các gói dùng chung được sử dụng trong các dự án khác nhau của monorepo.

Tối ưu hóa build Metro

Metro cung cấp một số cơ chế để tối ưu hóa kích thước bundle và tốc độ build. Inline Requires — kỹ thuật hiệu quả nhất, chuyển đổi các import cấp cao nhất thành các lệnh gọi require cục bộ bên trong hàm. RAM bundles cho phép tải module gia tăng. Hermes biên dịch JavaScript thành mã byte, giảm kích thước ứng dụng từ 20–30%.

Bật Inline Requires và Hermes

js
// metro.config.js — tối ưu hóa cho production
const config = {
  transformer: {
    async transform({ src, filename, options }) {
      const inlineRequires = options.dev ? false : true;
      return await defaultTransform({ src, filename, options: { ...options, inlineRequires } });
    },
  },
  serializer: {
    polyfillModuleNames: [],
  },
};

// Để bật Hermes — trong build.gradle (Android):
// project.ext.react = [enableHermes: true, bundleInRelease: true]
// Cho iOS — trong Podfile: :hermes_enabled => true

Để chẩn đoán kích thước bundle, Metro cung cấp cờ --bundle-output với đầu ra thống kê. Sử dụng bundle-visualizer để phân tích thành phần bundle và tìm các module lớn có thể tải lazy. Kiểm tra kích thước bundle thường xuyên nên là một phần của quy trình CI/CD trong dự án React Native.

Delta Bundles và build gia tăng

Metro hỗ trợ delta bundle — cơ chế mà sau lần build đầy đủ đầu tiên, máy chủ chỉ gửi các thay đổi (delta) giữa phiên bản bundle cũ và mới. Điều này tăng tốc đáng kể các lần build tiếp theo: thời gian cập nhật giảm từ giây xuống còn hàng chục mili giây. Delta bundle đặc biệt hiệu quả trong giai đoạn phát triển, khi nhà phát triển thường xuyên lưu thay đổi và tải lại ứng dụng.

Để bật delta bundle trong React Native, sử dụng cờ --delta trong lệnh npx react-native bundle. Về phía máy khách, delta bundle được hỗ trợ từ React Native 0.64. Trong các bản build production, delta bundle không được sử dụng — thay vào đó, một bundle đầy đủ với mã byte Hermes được sử dụng để đạt hiệu suất khởi động tối đa. Điều này đạt được vì lợi ích về tốc độ phát triển bù đắp cho chi phí của lần build đầy đủ đầu tiên.

Hermes và Metro: làm việc cùng nhau

Hermes là một công cụ JavaScript được Meta phát triển đặc biệt cho React Native. Metro tạo mã byte Hermes tại thời điểm build, cho phép ứng dụng khởi động mà không cần biên dịch JavaScript tốn kém trên thiết bị. Để bật Hermes, chỉ cần thêm enableHermes: true vào metro.config.js và cấu hình build.gradle hoặc Podfile. Hermes giảm thời gian khởi động ứng dụng từ 30–50% và giảm kích thước APK từ 20–30% so với JavaScriptCore.

Khi sử dụng Hermes, điều quan trọng là phải nhớ các hạn chế: công cụ này không hỗ trợ Proxy, Reflect và một số tính năng ES6. Hầu hết các ứng dụng React Native không sử dụng trực tiếp các tính năng này, nhưng một số thư viện có thể xung đột. Trước khi bật Hermes, hãy kiểm tra tính tương thích của tất cả các phụ thuộc dự án thông qua danh sách kiểm tra tương thích chính thức. Metro tự động chuyển sang chế độ tạo mã byte khi Hermes được kích hoạt.

Giám sát hiệu suất Metro

Để theo dõi hiệu quả build của Metro, hãy sử dụng các số liệu tích hợp có sẵn thông qua Flipper — công cụ gỡ lỗi React Native. Metro công bố các sự kiện: bundle_request, transform, resolve với thời gian thực thi của mỗi giai đoạn. Phân tích dữ liệu này giúp xác định các điểm nghẽn: nếu pha transform chiếm hơn 70% thời gian, vấn đề nằm ở bộ biến đổi Babel. Bật ghi log Metro qua cờ --verbose để chẩn đoán chi tiết.

Các câu hỏi thường gặp

Có thể thay thế Metro bằng Webpack trong React Native không?

Về mặt kỹ thuật là có — có các dự án thử nghiệm như react-native-webpack, nhưng chúng không được hỗ trợ chính thức. Metro được tích hợp với cầu nối React Native, Turbo Modules và Hermes ở mức độ mà Webpack không thể tiếp cận. Việc thay thế Metro sẽ dẫn đến mất Fast Refresh và hỗ trợ chính thức.

Tại sao Metro không hỗ trợ CSS?

React Native không sử dụng CSS để tạo kiểu — thay vào đó, kiểu JavaScript được áp dụng thông qua StyleSheet.create. Vì Metro được tạo ra dành riêng cho React Native, nên không cần hỗ trợ CSS. Đối với kết xuất web qua React Native Web, CSS được xử lý bởi các công cụ riêng biệt bên ngoài Metro.

Metro xử lý hình ảnh và phông chữ như thế nào?

Metro không xử lý hình ảnh hoặc phông chữ như các module. Tài nguyên được import qua require('./image.png'), nhưng Metro chỉ đăng ký chúng dưới dạng phụ thuộc chuỗi. Việc tải hình ảnh thực tế được thực hiện bởi mã gốc React Native thông qua component Image, và Metro sao chép tài nguyên vào bundle.

Metro khác Rollup như thế nào?

Rollup tạo ra các module ES với tree shaking ở cấp module, mang lại kích thước bundle tối thiểu cho thư viện. Metro tạo ra bundle CommonJS với biến đổi nội dòng và tối ưu hóa cho công cụ di động. Rollup không hỗ trợ Fast Refresh và không thể hoạt động với các module gốc của React Native.

Làm thế nào để tăng tốc build nguội của Metro?

Build nguội của Metro bị chậm do quét toàn bộ node_modules. Giải pháp: thêm watchFolders cho monorepo, sử dụng maxWorkers để biến đổi song song và cài đặt Watchman. Đối với các dự án có hơn 10.000 tệp, hãy cân nhắc metro-memory-fs để lưu đệm trong bộ nhớ.

Tổng kết

  • Metro là bundler tiêu chuẩn của React Native, được tối ưu hóa cho các nền tảng di động có tài nguyên hạn chế.
  • Kiến trúc ba pha (Resolve, Transform, Serialize) cho phép build gia tăng và Fast Refresh.
  • Fast Refresh — tải lại nóng các component đã thay đổi mà không mất trạng thái ứng dụng.
  • Inline Requires trì hoãn tải module cho đến lần gọi đầu tiên, giảm bundle ban đầu 15–30%.
  • Hermes — công cụ JavaScript của Meta biên dịch JS thành mã byte qua Metro để khởi động nhanh hơn.
  • Watchman — trình theo dõi tệp tin bắt buộc để làm việc thoải mái với Metro trên các dự án có số lượng lớn tệp tin.
  • Đối với monorepo, cần cấu hình watchFoldersextraNodeModules để giải quyết module chính xác.

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.

Thảo luận dự án

Đọc thêm