Metro Bundler เป็นตัวรวม JavaScript เฉพาะทางจาก Meta ที่พัฒนาขึ้นสำหรับ React Native โดยเฉพาะและรวมอยู่ในแกนหลักของเฟรมเวิร์ก ตามเอกสารอย่างเป็นทางการของ React Native 0.76 (2025) Metro มีการสร้างแบบเพิ่มหน่วยด้วย Fast Refresh และการแก้ไขโมดูลด้วยส่วนขยายเฉพาะแพลตฟอร์ม .native.js, .ios.js และ .android.js ต่างจาก Webpack ตรงที่ Metro ไม่ใช้แคชกราฟโมดูลระยะยาว — แต่จะสร้างกราฟใหม่ทุกครั้งที่ไฟล์เปลี่ยนแปลง ซึ่งให้ การโหลดซ้ำแบบร้อนทันที ระหว่างการพัฒนา
ประเด็นสำคัญ
Metro Bundler เป็นตัวรวม JavaScript โอเพนซอร์สที่พัฒนาโดย Meta สำหรับ React Native และใช้เป็นค่าเริ่มต้นในทุกโปรเจกต์ของเฟรมเวิร์ก หน้าที่ของ Metro คือนำโค้ด JavaScript ของโปรเจกต์พร้อมกับ dependencies มารวมเป็นหนึ่งหรือหลายบันเดิลที่ทำงานบนอุปกรณ์ ต่างจากตัวรวมทั่วไป (Webpack, Rollup, Parcel) Metro ได้รับการปรับให้เหมาะสมกับลักษณะเฉพาะของการพัฒนามือถือ: เวลาสร้างน้อยที่สุด การอัปเดตแบบเพิ่มหน่วยระหว่างการพัฒนา และการจัดการโมดูลแพลตฟอร์มที่ถูกต้อง (โมดูลเนทีฟ Objective-C, Swift, Java, Kotlin) Metro มาพร้อมกับ React Native CLI และไม่ต้องการการติดตั้งแยกต่างหาก ตั้งแต่ React Native 0.72 เป็นต้นไป Metro เวอร์ชัน 0.80+ รองรับการแปลงโค้ดแบบขนานของโมดูล ซึ่งเพิ่มความเร็วในการสร้างบนโปรเซสเซอร์แบบหลายคอร์ได้ถึง 40%
สถาปัตยกรรมของ Metro แบ่งออกเป็นสามคอมโพเนนต์อิสระ: Resolver, Transformer และ Bundler Resolver มีหน้าที่ค้นหาและแก้ไขโมดูล — มันอ่านนิพจน์ import/require ค้นหาไฟล์ที่เกี่ยวข้องโดยคำนึงถึงส่วนขยายแพลตฟอร์มและส่งคืนพาธแบบสัมบูรณ์ Transformer ทำการแปลงโค้ด: ใช้ Babel กับ presets และ plugins แปลง JSX, TypeScript หรือ Flow เป็น JavaScript บริสุทธิ์ Bundler เป็นขั้นตอนสุดท้าย: มันรับกราฟ dependencies จาก Resolver และไฟล์ที่แปลงแล้วจาก Transformer จากนั้นทำให้เป็นอนุกรมเป็นหนึ่งหรือหลายบันเดิล (module bundles) การแบ่งเป็นสามขั้นตอนช่วยให้ Metro แคชผลลัพธ์ของแต่ละขั้นตอนได้: ถ้ามีเพียงไฟล์เดียวที่เปลี่ยน Resolver และ Bundler สามารถใช้แคชสำหรับโมดูลที่เหลือ ซึ่งเพิ่มความเร็วในการสร้างได้ถึง 10 เท่าในโหมดพัฒนา
Resolver ใน Metro ใช้อัลกอริทึมการแก้ไขโมดูลที่เข้ากันได้บางส่วนกับการแก้ไขโมดูลของ Node.js ความแตกต่างหลักจาก Node.js คือการรองรับส่วนขยายแพลตฟอร์ม: require(‘./Component’) ค้นหา Component.native.js, Component.ios.js, Component.android.js ตามลำดับความสำคัญที่ระบุ Resolver ยังรองรับฟิลด์ package.json “react-native” สำหรับการแมปโมดูลไปยังการใช้งานทางเลือก — นี่เป็นกลไกมาตรฐานสำหรับไลบรารีที่มีโค้ดเฉพาะแพลตฟอร์ม ถ้าไม่พบไฟล์ Resolver จะโยนข้อผิดพลาดพร้อมสแต็กการค้นหาที่สมบูรณ์
Transformer ภายใน Metro ใช้ Babel กับ preset metro-react-native-babel-preset การกำหนดค่ามาตรฐานรวมถึง: การแปลง JSX เป็น React.createElement, การรองรับ TypeScript (การลบชนิด), การรองรับ Flow และ polyfill สำหรับมาตรฐาน JavaScript สมัยใหม่ (async/await, optional chaining, nullish coalescing) Transformer ทำงานในโหมดขนาน: แต่ละโมดูลถูกแปลงอย่างอิสระ โดยใช้พูลของกระบวนการ worker (โดยค่าเริ่มต้น จำนวนจะสอดคล้องกับจำนวน CPU) ตั้งแต่ Metro 0.80 เป็นต้นไป รองรับ Granular Transformer Cache — การทำให้แคชไม่ถูกต้องที่ระดับไฟล์แต่ละไฟล์
หนึ่งในคุณสมบัติหลักของ Metro คือการรองรับส่วนขยายไฟล์แพลตฟอร์ม โปรเจกต์ React Native สามารถมีสามเวอร์ชันของโมดูลเดียวกัน: Component.ios.js (iOS), Component.android.js (Android) และ Component.native.js (ทั้งสองแพลตฟอร์ม) เมื่อนำเข้า require(‘./Component’) Resolver จะเลือกเวอร์ชันที่ถูกต้องโดยอัตโนมัติตามแพลตฟอร์มเป้าหมายของการสร้าง ซึ่งช่วยให้เขียนโค้ดที่ขึ้นกับแพลตฟอร์มได้โดยไม่ต้องใช้โครงสร้าง Platform.OS แบบมีเงื่อนไข ลำดับความสำคัญ: name.platform.js > name.native.js > name.js ส่วนขยาย .native.js ใช้สำหรับโค้ดทั่วไปที่ทำงานบนทั้งสองแพลตฟอร์มแต่เข้ากันไม่ได้กับเว็บ ส่วนขยาย .ios.js และ .android.js ใช้สำหรับการใช้งานคุณสมบัติเฉพาะ — การนำทาง ท่าทาง การดำเนินการกับระบบไฟล์ Metro รองรับส่วนขยายที่กำหนดเองผ่านการกำหนดค่า resolver.sourceExts
// metro.config.js — การตั้งค่า sourceExts และ 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 เป็นกลไกการโหลดซ้ำแบบร้อนสำหรับ React Native ที่สร้างบน Metro เมื่อนักพัฒนาเปลี่ยนไฟล์ Metro จะแปลงโค้ดเฉพาะโมดูลที่เปลี่ยนเท่านั้นและส่งอัปเดตไปยังแอปผ่าน WebSocket Fast Refresh อัปเดต UI โดยไม่โหลดแอปพลิเคชันทั้งหมดซ้ำและรักษาสถานะของคอมโพเนนต์ React ถ้ามีเพียง JSX หรือสไตล์ที่เปลี่ยน ถ้าโค้ดที่มี hooks หรือสถานะเปลี่ยน Fast Refresh จะ mount เฉพาะคอมโพเนนต์ที่เปลี่ยนเท่านั้น Metro รองรับสองโหมด: Hot Module Replacement (HMR) สำหรับการเปลี่ยนโมดูลทันทีและ Live Reload สำหรับการโหลดแอปพลิเคชันทั้งหมดซ้ำเมื่อโมดูลเนทีฟหรือการกำหนดค่าเปลี่ยน Fast Refresh เปิดใช้งานโดยค่าเริ่มต้นใน React Native 0.76 และไม่ต้องการการกำหนดค่าเพิ่มเติม — แค่รัน npx react-native start
| โหมด | ความเร็ว | รักษาสถานะ | ตัวกระตุ้น |
|---|---|---|---|
| Fast Refresh | 200-500ms | ใช่ | การเปลี่ยนไฟล์ JS/TS |
| HMR | 100-300ms | ใช่ | การเปลี่ยน CSS/สไตล์ |
| Live Reload | 1-3s | ไม่ | การเปลี่ยน config เนทีฟ |
| Full Rebuild | 10-60s | ไม่ | การเปลี่ยน podspec/build.gradle |
ไฟล์ metro.config.js เป็นไฟล์กำหนดค่า Metro ที่อยู่ในรูทของโปรเจกต์ React Native ในนั้นกำหนดค่า: resolver (sourceExts, platformExtensions, extraNodeModules), transformer (babelTransformerPath, minifierConfig), server (port, host, enableFastRefresh) และ watcher (watchFolders, healthCheck) การกำหนดค่า Metro มาตรฐานสืบทอดจากแพ็กเกจ @react-native/metro-config (React Native 0.76+) สำหรับโปรเจกต์แบบ monorepo ให้เพิ่ม watchFolders — ซึ่งช่วยให้ Metro ติดตามการเปลี่ยนแปลงในแพ็กเกจนอกรูทโปรเจกต์ ในการกำหนดค่า sourceExts ให้เพิ่ม ‘svg’, ‘png’, ‘gql’ สำหรับตัวแปลงที่กำหนดเอง Metro รองรับการกำหนดค่าแบบอะซิงโครนัสผ่าน async function — มีประโยชน์สำหรับการสร้างการกำหนดค่าแบบไดนามิกตามสภาพแวดล้อม
การปรับแต่ง การสร้าง Metro เริ่มต้นด้วยการกำหนดค่าแคชที่เหมาะสม ตั้งค่า maxWorkers เป็นจำนวน CPU ลบ 1 สำหรับการแจกจ่าย ใช้ resetCache บน CI ลด sourceExts — ส่วนขยายที่เกินมาทำให้การแก้ไขโมดูลช้าลง สำหรับโปรเจกต์ขนาดใหญ่ ให้กำหนดค่า watchFolders เฉพาะไดเรกทอรีที่จำเป็น Metro รองรับการย่อ Hermes ไบต์โค้ด ซึ่งให้ขนาดบันเดิลที่เล็กกว่า Terser มาตรฐาน — ใช้ minifierPath: ‘metro-minify-terser’
Metro รองรับโหมดสร้างโดยตรงเป็น Hermes ไบต์โค้ด — ข้ามขั้นตอน AST ของ JavaScript เมื่อสร้างด้วย HermesTransformer โมดูลจะถูกคอมไพล์เป็น HBC (Hermes ByteCode) แทนที่จะเป็น JavaScript ทั่วไป ซึ่งให้: ขนาดบันเดิลเล็กลง (30-40%), การเริ่มต้นแอปพลิเคชันเร็วขึ้น (20-30%) และการใช้หน่วยความจำน้อยลง ในการเปิดใช้งาน ให้ตั้งค่า hermesCommand ใน metro.config.js และเปิดใช้งานแฟล็ก Hermes ใน build.gradle (Android) หรือ Podfile (iOS) การสร้างบันเดิล Hermes ทำในสองขั้นตอน: ขั้นแรก Metro สร้างบันเดิล JavaScript จากนั้น Hermes CLI แปลงเป็น HBC ตั้งแต่ React Native 0.70 เป็นต้นไป Hermes เป็นเครื่องมือเริ่มต้นบน Android บน iOS ต้องการการเปิดใช้งานอย่างชัดแจ้ง
ความแตกต่างระหว่าง Metro และ Webpack เกิดจากเป้าหมายที่ต่างกัน Webpack เป็นตัวรวมทั่วไปสำหรับเว็บที่มีระบบนิเวศปลั๊กอินและโหลดเดอร์ขนาดใหญ่ Metro เป็นตัวรวมเฉพาะสำหรับ React Native ที่ให้ความสำคัญกับความเร็วในการสร้างแบบเพิ่มหน่วยและการทำงานที่ถูกต้องกับโมดูลเนทีฟ Webpack ใช้กราฟโมดูลระยะยาวที่มีการทำให้แคชไม่ถูกต้องอย่างชาญฉลาด — ซึ่งให้การสร้างใหม่ที่รวดเร็วบนเว็บแต่สร้างปัญหากับส่วนขยายแพลตฟอร์ม Metro ไม่แคชกราฟระหว่างการสร้าง แต่สร้างทุกครั้ง — ซึ่งทำให้การจัดการส่วนขยายแพลตฟอร์มและโมดูล Haste ง่ายขึ้น Webpack รองรับการนำเข้าแบบไดนามิกกับชังค์ Metro ก็รองรับ — ผ่าน React.lazy() และ Suspense แต่มีข้อจำกัดหนึ่งคำขอที่ทำงานอยู่ ระบบนิเวศของ Metro เล็กกว่าอย่างมาก: ไม่มีตัวแทนสำหรับ style-loader, css-loader, file-loader — งานเหล่านี้แก้ไขต่างกันใน React Native
Metro เป็นตัวเลือกที่ถูกต้องเพียงอย่างเดียวสำหรับโปรเจกต์ React Native Webpack ไม่รองรับการแก้ไขที่รับรู้แพลตฟอร์มตั้งแต่เริ่มต้น และการตั้งค่า React Native ด้วย Webpack ต้องใช้ความพยายามอย่างมาก (haul bundler, expo web packager) Metro ถูกรวมเข้ากับ React Native CLI รองรับโดยทีมงานทางการของ Meta และรับอัปเดตกับทุกการเปิดตัวของ React Native สำหรับโปรเจกต์ React Native Web คุณสามารถใช้ Webpack สำหรับการสร้างเว็บในขณะที่คง Metro ไว้สำหรับบันเดิลมือถือ
คำถามที่พบบ่อย
รัน npx react-native start --reset-cache หรือลบโฟลเดอร์ $TMPDIR/metro-* และไดเรกทอรี .metro-health-check* ในรูทโปรเจกต์ อีกทางเลือก: npx react-native clean — คำสั่งนี้ล้างไฟล์ชั่วคราวทั้งหมดของ Metro รวมถึงแคช Babel และแผนที่ Haste หลังจากล้าง การสร้างครั้งแรกจะเป็นการสร้างเต็มรูปแบบ (60-120 วินาที) แต่การสร้างแบบเพิ่มหน่วยครั้งต่อไปจะกลับมาที่ความเร็วปกติ
ตรวจสอบว่าแพ็กเกจอยู่ใน dependencies ของ package.json (ไม่ใช่ devDependencies) ถ้าโมดูลอยู่ใน monorepo ให้เพิ่มพาธใน watchFolders ใน metro.config.js Metro ไม่ติดตาม symlinks โดยค่าเริ่มต้น — ใช้ resolver.extraNodeModules สำหรับการแมปอย่างชัดแจ้ง สำหรับ Yarn PnM ให้ตั้งค่า resolver.useWatchman: false ถ้าโมดูลใช้ส่วนขยายแพลตฟอร์ม ตรวจสอบให้แน่ใจว่าไฟล์ .ios.js หรือ .android.js มีอยู่ในพาธที่ระบุ
เพิ่ม maxWorkers ใน metro.config.js เป็นจำนวน CPU ลบ 1 กำหนดค่า watchFolders เฉพาะไดเรกทอรีที่จำเป็น ใช้ Hermes ไบต์โค้ดสำหรับการสร้างแบบโปรดักชัน — เพิ่มความเร็วในการสร้างสุดท้ายโดยข้ามการย่อ JS สำหรับการพัฒนา เปิดใช้งาน Fast Refresh (เปิดใช้งานโดยค่าเริ่มต้น) จำกัด sourceExts เฉพาะส่วนขยายที่จำเป็น พิจารณาแบ่งบันเดิลเป็นชังค์ผ่านการโหลดแบบ Lazy
ในทางเทคนิคได้ แต่ไม่แนะนำ Metro ไม่ได้รับการปรับให้เหมาะสมสำหรับการสร้างเว็บ: ไม่รองรับ CSS, HTML, รูปภาพเป็นโมดูล ไม่มีการแบ่งโค้ดด้วยการนำเข้าแบบไดนามิกระดับเบราว์เซอร์ สำหรับเว็บ ใช้ Webpack, Vite หรือ Parcel Metro เป็นโซลูชันเฉพาะสำหรับ React Native และการพยายามปรับให้เข้ากับเว็บจะทำให้ประสิทธิภาพลดลงและขาดระบบนิเวศของโหลดเดอร์
Re.Pack เป็นเครื่องมือชุมชนสำหรับแทนที่ Metro ด้วย Webpack ในโปรเจกต์ React Native มันให้เข้าถึงระบบนิเวศโหลดเดอร์ของ Webpack (css-loader, svg-loader) และการแบ่งโค้ดขั้นสูง อย่างไรก็ตาม Re.Pack กำหนดค่าได้ซับซ้อนกว่า ไม่ได้รับการสนับสนุนอย่างเป็นทางการจาก Meta และไม่รับประกันความเข้ากันได้กับเวอร์ชันใหม่ของ React Native Metro ยังคงเป็นตัวรวมเดียวที่รองรับอย่างเป็นทางการ ให้ความเสถียรและความเข้ากันได้ที่รับประกันกับทุกการเปิดตัว
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม