JavaScript Source Map Explorer: ดูให้ชัดว่าไฟล์ไหนทำให้ bundle ของคุณอ้วนที่สุด
Paste source map แล้วดูอันดับว่าไฟล์ต้นฉบับไหนกิน byte ใน bundle เยอะที่สุด ตรวจสอบและวิเคราะห์ด้วย JavaScript Source Map Explorer แบบ client-side 100% ไม่มีการอัปโหลดโค้ดออกจากเครื่อง
Table of Contents
JavaScript Source Map Explorer: ดูให้ชัดว่าไฟล์ไหนทำให้ bundle ของคุณอ้วนที่สุด
เมื่อ bundle โตขึ้นทีละ release คำถามที่ตามมาไม่ใช่ "มันอ้วนขึ้นหรือเปล่า" แต่คือ "ไฟล์ไหนทำให้อ้วน" minification บดโค้ดที่คุณจัดระเบียบไว้อย่างดีให้กลายเป็นกำแพงตัวอักษรก้อนเดียว ชื่อไฟล์ โครงสร้างโฟลเดอร์ และขอบเขตของ module หายไปหมดในกระบวนการนี้ source map คือไฟล์ที่คอยรักษาเส้นเชื่อมนี้ไว้ เป็น sidecar file ที่ถูกสร้างคู่กับ app.min.js ในชื่อ app.min.js.map โดยบันทึกว่าทุกตำแหน่งใน output ที่ถูก minify แล้ว มาจากไฟล์ต้นฉบับไหน JavaScript Source Map Explorer อ่านไฟล์ sidecar นี้แล้วเปลี่ยนเป็นอันดับไฟล์ต้นฉบับที่มีส่วนร่วมใน byte ของ bundle มากที่สุด
ขั้นตอนการใช้งานตั้งใจให้สั้นที่สุด เปิดเครื่องมือ paste เนื้อหาไฟล์ .map ลงไป แล้วภายในไม่กี่วินาทีคุณจะเห็นอันดับส่วนร่วมรายไฟล์ ว่า library ฝั่ง vendor ตัวไหนครองบัลลังก์ โค้ดส่วนไหนของตัวเองหนักกว่าที่คิด และน้ำหนักที่เหลือกระจายไปอย่างไร ไม่ต้องสมัครบัญชี ไม่ต้องติดตั้ง CLI และไม่มีขั้นตอนอัปโหลดให้รอ
ประเด็นสุดท้ายนี้สำคัญกว่าที่ฟังดู production bundle คือ asset ที่เป็นความลับทางการค้า เพราะมันเข้ารหัสสถาปัตยกรรมของสินค้า, endpoint ภายใน และ business logic ของคุณไว้ในรูปแบบที่เครื่องอ่านได้ explorer ตัวนี้ทำงานทั้งหมดในเบราว์เซอร์ของคุณ bundle และ source map จึงไม่เคยออกจากเครื่องเลย
ทำไมต้องใช้ JavaScript Source Map Explorer?
- โค้ดของคุณไม่หลุดออกจากเครื่อง การ parse, decode และจัดอันดับเกิดขึ้นฝั่ง client ทั้งหมด คุณตรวจ source map ของ dashboard ภายในองค์กรหรือสินค้า closed-source ได้โดยไม่ต้องส่ง byte เดียวไปที่ไหน
- ไม่ต้องติดตั้งอะไรเลย ไม่ต้องลง bundler plugin, Node script หรือ desktop app ขอแค่มีเบราว์เซอร์กับไฟล์ .map ก็วิเคราะห์ได้ทันที
- ตอบคำถาม "ไฟล์ไหน" ตรง ๆ แทนที่จะต้องแกะ treemap คุณจะได้รายการเรียงลำดับ ไฟล์ต้นฉบับทุกไฟล์เรียงตาม byte ที่มีส่วนร่วม ตัวใหญ่สุดอยู่บนสุด พร้อมสัดส่วนต่อทั้งหมดกำกับ
- คิดจากของจริงหลัง minify อันดับสะท้อนสิ่งที่ถูก build จริงใน bundle ที่ minify แล้ว ไม่ใช่ขนาดใน source tree ตอนพัฒนา ซึ่งต่างกันได้คนละเรื่อง
- ตรวจสอบ input อย่างปลอดภัยและชัดเจน เครื่องมือเช็กก่อนเสมอว่า JSON ที่ paste เข้ามาหน้าตาเหมือน source map จริง ถ้า paste ไฟล์ config หรือ response จาก API เข้าไปผิด คุณจะเจอ error ที่บอกสาเหตุ ไม่ใช่กราฟที่อ่านแล้วเข้าใจผิด
- ใช้ได้กับทุก bundler webpack, Vite, esbuild, Rollup และ tsup ล้วนสร้าง source map ฟอร์แมต version 3 เหมือนกัน เครื่องมือนี้จึงเข้ากับ build pipeline แบบไหนก็ได้
ฟีเจอร์หลัก
| ฟีเจอร์ | สิ่งที่ได้ |
|---|---|
| จัดอันดับ byte รายไฟล์ | ไฟล์ต้นฉบับทุกไฟล์เรียงตาม byte ที่มีส่วนร่วมใน bundle จากมากไปน้อย |
| สัดส่วนการมีส่วนร่วม | เปอร์เซ็นต์ของ byte ทั้งหมดต่อไฟล์ เห็นภาพรวมได้ทันที |
| ตรวจ source map | ยืนยันก่อนว่า JSON ที่ paste มี mappings จริงแล้วจึงเริ่มวิเคราะห์ |
| ภาพรวม sources | จำนวนไฟล์ต้นฉบับ และมีโค้ดต้นฉบับฝังอยู่ใน map หรือไม่ |
| Client-side 100% | decode และจัดอันดับทำงานในเบราว์เซอร์ ไม่มีการอัปโหลด ไม่มีการเก็บข้อมูล |
รายละเอียดที่น่ารู้อีกเล็กน้อย:
- จัดอันดับแบบสำรอง เมื่อ source map ไม่ได้ฝังโค้ดต้นฉบับมาด้วย (เจอบ่อยกับ map ฝั่ง vendor) explorer ยังจัดอันดับด้วยจำนวน mapping segment ให้ คุณจึงยังมีสัญญาณใช้งาน ไม่ใช่รายงานว่าง
- รองรับ map ขนาดจริง decoder เดินไล่ mappings string ทีละบรรทัด ทำให้ map production ที่มี segment เป็นแสนรายการยังจัดการได้สบาย
- ข้อความ error เจาะจง JSON พัง กับ JSON ที่ถูกต้องแต่ไม่ใช่ source map ได้คำอธิบายแยกกัน คุณจึงรู้ว่าต้องแก้การ paste หรือไปหาไฟล์ที่ถูกต้อง
วิธีการใช้งาน
- Build พร้อม source map แล้วหาไฟล์ .map สร้าง production build โดยเปิด source map ไว้ แล้วเข้าไปดูในโฟลเดอร์ output (dist, build หรือเทียบเท่า) จะมีไฟล์ชื่อเดียวกับ bundle ต่อท้ายด้วย .map เช่น app.min.js.map วางอยู่ข้าง app.min.js
- คัดลอกเนื้อหาไฟล์ .map เปิดไฟล์ด้วย text editor ตัวไหนก็ได้ เลือกทั้งหมดแล้ว copy source map เป็น JSON ธรรมดา ไม่ต้องเตรียมอะไรเพิ่ม
- Paste ลงใน explorer เข้าไปที่ JavaScript Source Map Explorer แล้ว paste JSON ลงช่อง input การตรวจสอบจะทำงานทันที ถ้า input ไม่ใช่ JSON ที่ถูกต้อง หรือขาด mappings ที่ source map ต้องมี คุณจะเห็น error ที่ชัดเจนแทนรายงานที่พัง
- อ่านอันดับส่วนร่วมรายไฟล์ ไฟล์ต้นฉบับจะเรียงตาม byte ที่มีส่วนร่วมใน bundle พร้อมสัดส่วนต่อทั้งหมด แถวบน ๆ คือเป้าหมาย optimize ของคุณ ส่วนหางอันดับบอกสุขภาพของโค้ดส่วนที่เหลือ
- ลงมือแก้ แล้ว build ใหม่มาเช็กซ้ำ แก้ตามที่ข้อมูลชี้ — lazy-load module หนัก, รวม utility ที่ซ้ำกัน หรือเปลี่ยน dependency ที่อ้วน — จากนั้น build ใหม่แล้ว paste map ใหม่เพื่อยืนยันว่าอันดับขยับจริง
สิ่งที่ source map บอกคุณเกี่ยวกับ bundle ของคุณ
mappings และ sources เก็บอะไรไว้จริง ๆ source map version 3 มี field ระดับบนไม่กี่ตัว ได้แก่ version, array sources ที่ลิสต์ path ของไฟล์ต้นฉบับ, sourcesContent (ไม่บังคับ) ที่ฝังโค้ดต้นฉบับมาด้วย, array names และ mappings ซึ่งเป็น base64 VLQ string แบบกระชับ mappings คือหัวใจของฟอร์แมตนี้ มันบันทึกว่าทุกบรรทัดและทุกคอลัมน์ใน output ที่ถูก minify แล้ว มาจากไฟล์ บรรทัด และคอลัมน์ไหนของต้นฉบับ พูดง่าย ๆ คือ source map คือรายการขนส่ง (shipping manifest) ของ bundle ที่ยังอยู่ครบแม้ minification จะเล่นงานทุกอย่างไปแล้ว
ส่วนแบ่ง byte คิดจากของจริงหลัง minify เพราะทุก generated segment ชี้กลับไปที่ไฟล์ต้นฉบับ น้ำหนักของ bundle จึงถูก attribute กลับไปที่ไฟล์ในรูปที่มันถูกส่งออกจริง ๆ มุมมองหลัง minification ที่แท้จริง explorer วัดขนาด byte แบบ UTF-8 ของไฟล์ต้นฉบับแต่ละไฟล์ที่ฝังอยู่ใน sourcesContent แล้วจัดอันดับตามสัดส่วนต่อทั้งหมด อันดับที่ได้จึงอธิบาย bundle ที่ผู้ใช้ดาวน์โหลด ไม่ใช่ repository ที่คุณเขียนโค้ดอยู่ ถ้า map ไม่มีโค้ดฝังมา จำนวน segment จะเข้ามาทำหน้าที่แทน ซึ่งยังสะท้อนปริมาณ output ที่แต่ละไฟล์ผลิตได้ใกล้เคียง
สิ่งที่มักเจอจากอันดับนี้ library วันที่เวลาที่ใหญ่กว่าโค้ด application ทั้งหมดรวมกันคือเรื่องคลาสสิก กฎการ format, logic การ parse และข้อมูล locale ของมันชนะตัวแอปที่ใช้แค่เสี้ยวเดียวของมันอยู่เสมอ อันดับสองคือ utility ที่ถูก copy ซ้ำข้าม chunk ฟังก์ชันชุดเดิมถูก bundle สองรอบใต้ชื่อ chunk ต่างกัน เสีย cost สองเท่าแบบเงียบ ๆ ที่เจอบ่อยอื่น ๆ ได้แก่ component library ที่ถูกดึงมาทั้งก้อนทั้งที่ใช้แค่ไม่กี่ตัว, icon set ที่ถูกฝังเป็นโค้ด และ polyfill ที่ยังไปดูแลเบราว์เซอร์ที่คุณเลิกรองรับไปหลายปี
เอาอันดับนี้ไปทำอะไรต่อ หัวอันดับคือ roadmap ของคุณ lazy-load module ที่ไม่จำเป็นตั้งแต่ first paint รวม utility ที่ซ้ำกันเป็น module เดียว tree-shake ด้วยการ import เฉพาะ named export ที่ใช้ และเปลี่ยน dependency หนักตัวเดียวเป็นตัวเบากว่า แล้ววิเคราะห์ซ้ำ — การแก้ที่ไม่เคยวัดซ้ำ ก็แค่การเดาที่ดูดี
กรณีการใช้งานจริง
สืบสวนว่า bundle โตขึ้นเพราะอะไร
หน้าเว็บหนักขึ้นแต่ไม่มีใครรู้สาเหตุ paste source map จาก release สุดท้ายที่ยังปกติ กับตัวปัจจุบันมาเทียบ อันดับจะชี้ไปที่ไฟล์หรือ dependency ตัวปัญหาภายในไม่กี่นาที บ่อยครั้งคือการ upgrade dependency ครั้งเดียวที่ลาก transitive ยักษ์ตัวใหญ่ตามมาด้วย
ตัดสินใจเปลี่ยน dependency
กำลังเลือกระหว่างสอง library? build หนึ่งรอบกับตัวเลือกแต่ละตัว paste map ทั้งคู่แล้วเทียบสัดส่วน byte กันตรง ๆ เทคนิคเดียวกันนี้ใช้ยืนยันได้ว่า migration ที่เสร็จไปแล้ว — เช่น เปลี่ยนจาก utility kit หนัก ๆ มาเป็นตัว modular — ให้ผลประหยัดเท่าที่เขียนไว้ใน RFC จริงหรือเปล่า
เทียบ build ย้อนเวลา
เก็บอันดับสิบอันดับแรกไว้หลังแต่ละ release แม้จะเป็นแค่ text ธรรมดา ผ่าน sprint ไม่กี่รอบคุณจะมีกราฟแนวโน้มน้ำหนัก bundle พร้อมชื่อผู้กระทำผิด โดยไม่ต้องสร้าง monitoring infrastructure และทุก regression ก็มีชื่อไฟล์ติดมาด้วย
รายงาน performance ที่ยืนหยัดได้
ประโยคว่า "bundle มันดูใหญ่" รอดจากประชุมวางแผนไม่ได้ แต่ตารางอันดับไฟล์พร้อม byte และเปอร์เซ็นต์รอดได้ พาไปประชุม review performance ครั้งหน้า แล้วบทสนทนาจะเปลี่ยนจากความเห็นเป็นลิสต์งานที่จัดลำดับความสำคัญได้ทันที
แนวปฏิบัติที่ดี
- วิเคราะห์ production build ไม่ใช่ dev bundle ตอน dev ไม่ถูก minify และมีโครงสร้างต่างออกไป อันดับจากมันจึงบอกอะไรเรื่องสิ่งที่ผู้ใช้ดาวน์โหลดได้น้อยมาก ให้ใช้ map จาก production build เสมอ
- เทียบก่อน-หลังบน commit เดียวกัน เวลาวัดผลการ optimize ตัวแปรเดียวที่ควรต่างกันคือการ optimize เอง — build map ทั้งสองชุดจาก source state เดียวกัน
- เริ่มจากสามอันดับแรกก่อน น้ำหนัก bundle กระจุกอยู่บนหัวอันดับอย่างหนัก การแก้สามไฟล์ใหญ่สุดมักยอดกว่าการ micro-optimize ยี่สิบจุดรวมกัน
- อย่า deploy ไฟล์ .map ขึ้น production hosting วิเคราะห์แบบ local แล้ว deploy โดยไม่เอามันไปด้วย source map ที่ดาวน์โหลดได้จากสาธารณะเท่ากับส่งโค้ดต้นฉบับให้คนอื่น
- เชื่อ byte มากกว่าจำนวนไฟล์ ไฟล์เล็ก ๆ สองร้อยไฟล์อาจเบากว่า vendor module ไฟล์เดียว optimize ตามตัวเลขขนาด ไม่ใช่ตามจำนวนแถวในรายการ
- วิเคราะห์ซ้ำหลังทุกการแก้ อันดับจะเป็น control loop ได้ก็ต่อเมื่อคุณปิดลูปมัน แก้, build, paste ใหม่ แล้วยืนยันว่า byte ลดลงจริง
คราวหน้าที่ใครถามว่าทำไม bundle ถึงหนัก อย่าเสียเวลาเดา หยิบไฟล์ .map จาก build output มา paste ลง JavaScript Source Map Explorer แล้วตอบคำถามด้วยตัวเลข byte พร้อมชื่อไฟล์ อันดับ และสัดส่วนที่ทุกคนลงมือตามได้
เครื่องมือที่เกี่ยวข้องที่คุณอาจสนใจ:
- JSON Formatter — จัดรูปแบบและอ่าน JSON ดิบของ .map เมื่ออยากเห็น field version, sources และ mappings โดยตรง
- HAR File Analyzer — เชื่อมน้ำหนัก bundle เข้ากับสิ่งที่ทำให้โหลดหน้าช้าจริง ๆ จาก network capture
- JSON Schema Visualizer — ดูโครงสร้าง payload ของ API ที่ bundle ของคุณสร้างและรับส่ง
ขอให้ vendor chunk ของคุณไม่มีวันหนักกว่าโค้ดของตัวเองอีกเลย
คำถามที่พบบ่อย
ถ: source map หรือ bundle ของฉันถูกอัปโหลดไปที่ไหนหรือเปล่า?
ตอบ: ไม่ การ decode, การนับ byte และการจัดอันดับเกิดขึ้นในเบราว์เซอร์ของคุณทั้งหมด ไม่มีการส่งข้อมูล เก็บข้อมูล หรือ log อะไรเลย เมื่อหน้าโหลดแล้วการวิเคราะห์ทำงานได้แม้ออฟไลน์
ถ: source map คืออะไร อธิบายในประโยคเดียวได้ไหม?
ตอบ: ได้ มันคือไฟล์ JSON sidecar ที่มี field version, รายชื่อไฟล์ต้นฉบับ, โค้ดต้นฉบับฝังอยู่ (ไม่บังคับ) และ mappings string ที่บันทึกว่าทุกตำแหน่งใน bundle ที่ถูก minify แล้ว มาจากไฟล์ บรรทัด และคอลัมน์ไหนของต้นฉบับ
ถ: หาไฟล์ .map ของโปรเจกต์ที่ไหน?
ตอบ: ในโฟลเดอร์ build output วางอยู่ข้าง ๆ JavaScript bundle โดยใช้ชื่อ bundle ต่อท้ายด้วย .map เช่น main.min.js.map อยู่ข้าง main.min.js อย่าลืมว่า production build ต้องเปิด source map เอาไว้ด้วย
ถ: map ของฉันไม่มีโค้ดต้นฉบับฝังมา ทำไมอันดับเลยดูต่างไป?
ตอบ: เมื่อไม่มีโค้ดฝังมา explorer วัดขนาด byte จริงไม่ได้ จึงเปลี่ยนไปจัดอันดับด้วยจำนวน mapping segment ซึ่งยังสะท้อนปริมาณ output ที่แต่ละไฟล์ผลิตได้ แต่แม่นยำน้อยกว่าการนับ byte จริง
ถ: เครื่องมือต้องใช้ไฟล์ JavaScript bundle จริงด้วยหรือเปล่า?
ตอบ: ไม่ต้อง ข้อมูลน้ำหนักทั้งหมดมาจาก source map เอง paste เฉพาะเนื้อหาไฟล์ .map ก็พอ ไม่จำเป็นต้องมีไฟล์ bundle ที่ถูก minify แล้วเลย