วิธีแก้หน้าขาวว่างเปล่าในเว็บแอปของคุณ
หน้าขาวว่างเปล่าเกือบทุกครั้งหมายถึงหนึ่งในสองกรณี: JavaScript ของแอปพังก่อนจะวาดอะไรออกมา หรือ JavaScript ไม่ได้โหลดเลย เปิด console ของเบราว์เซอร์แล้วอ่าน error สีแดงแรก จากนั้นตรวจแท็บ Network ดูไฟล์ที่โหลดไม่สำเร็จ สาเหตุส่วนใหญ่คือตัวแปรสภาพแวดล้อมที่หายไป base path ที่ผิด การบิลด์ที่ยังไม่เสร็จ หรือ crash ในคอมโพเนนต์เดียว
คู่มือนี้ครอบคลุมแอปแบบ single-page ที่สร้างด้วย React, Vue หรือเฟรมเวิร์กที่คล้ายกัน (รวมถึงแอปที่สร้างโดยเครื่องมือ AI) ซึ่งเป็นที่ที่หน้าขาวพบบ่อยที่สุด
ทำไมหน้าถึงขาว
แอป single-page (SPA) สมัยใหม่ส่ง HTML ที่แทบว่างเปล่าไปยังเบราว์เซอร์ ประมาณนี้:
<body>
<div id="root"></div>
<script type="module" src="/assets/index-a1b2c3.js"></script>
</body>
จากนั้น JavaScript จะสร้างหน้าทั้งหมดภายใน div ที่ว่างเปล่านั้น ถ้าสคริปต์โหลดไม่สำเร็จ หรือ throw error ก่อนเรนเดอร์ div จะว่างต่อไปและคุณจะเห็นสีขาว หน้าไม่ได้ "เสีย" ในลักษณะที่มองเห็นได้ มันแค่ไม่เคยถูกวาด
นั่นคือเหตุผลที่การแก้ไขเริ่มต้นจากเครื่องมือสำหรับนักพัฒนาเสมอ ไม่ใช่จากตัวหน้าเอง
ขั้นที่ 1: อ่าน console
เปิดเครื่องมือสำหรับนักพัฒนา: คลิกขวาที่หน้าแล้วเลือก Inspect หรือกด F12 (Cmd+Option+I บน Mac) ไปที่แท็บ Console แล้วรีโหลดหน้า
ดู error สีแดง แรก เพราะตัวถัด ๆ มาเป็นผลข้างเคียงบ่อยครั้ง สิ่งที่มันบอกจะชี้ไปยังสาเหตุ:
| ข้อความใน console (คำที่พบทั่วไป) | ความหมาย | ไปที่ |
|---|---|---|
Cannot read properties of undefined (reading '...') | โค้ดคาดหวังข้อมูลที่ไม่มี | ขั้นที่ 4 |
... is not defined / ... is not a function | import, ตัวแปร หรือการตั้งค่าที่หายไป | ขั้นที่ 4 หรือ 3 |
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html" | URL ของสคริปต์ตอบกลับเป็นหน้า HTML แทน JavaScript | ขั้นที่ 2 |
Uncaught SyntaxError: Unexpected token '<' | เหมือนกัน: มี HTML ในที่ที่คาดหวัง JavaScript | ขั้นที่ 2 |
supabaseUrl is required, Missing API key หรือคล้ายกัน | ตัวแปรสภาพแวดล้อมว่างเปล่า | ขั้นที่ 3 |
Access to fetch ... has been blocked by CORS policy | คำขอไปยังโดเมนอื่นถูกบล็อก | ดูวิธีแก้ error CORS |
| ไม่มี error เลย | เรนเดอร์ได้แต่ไม่แสดงอะไร หรือ CSS ซ่อนไว้ | ขั้นที่ 6 |
คัดลอกข้อความ error ทั้งหมด รวมชื่อไฟล์และหมายเลขบรรทัด ถ้าคุณใช้เครื่องมือสร้างด้วย AI ให้วางลงในแชตได้เลย
ขั้นที่ 2: ตรวจว่าไฟล์โหลดสำเร็จ
เปิดแท็บ Network ติ๊ก Disable cache แล้วรีโหลด ดูคำขอไปยังไฟล์ .js และ .css
- สถานะ 404 บนไฟล์ JavaScript: หน้าขอไฟล์ที่ไม่มีอยู่บนเซิร์ฟเวอร์
- สถานะ 200 แต่ type เป็น
text/html: เซิร์ฟเวอร์ส่งหน้า (มักเป็นindex.htmlเอง เพราะ SPA fallback) แทนสคริปต์ สาเหตุรากเดียวกัน: ไฟล์ไม่ได้อยู่ในที่ที่หน้าคาดไว้
เหตุผลที่พบบ่อย:
Base path ผิด ถ้าแอปให้บริการจากโฟลเดอร์ย่อย เช่น example.com/app/ แต่ถูกบิลด์ให้โหลดไฟล์จาก /assets/... คำขอสคริปต์ทุกตัวจะพลาด ใน Vite คือตัวเลือก base ใน vite.config ใน Create React App คือฟิลด์ homepage ใน Next.js คือ basePath ต้องตรงกับที่แอปถูกให้บริการจริง
index.html ที่ค้างอยู่ เครื่องมือบิลด์ตั้งชื่อไฟล์ด้วยแฮชของเนื้อหา เช่น index-a1b2c3.js หลังดีพลอยใหม่ ไฟล์เก่าจะหายไป ถ้าเบราว์เซอร์หรือ CDN ยังแคช index.html เก่าอยู่ มันจะขอไฟล์เก่าและไม่ได้อะไรกลับมา การ hard refresh (Cmd+Shift+R หรือ Ctrl+Shift+R) ยืนยันเรื่องนี้ได้ วิธีแก้ระยะยาวคือให้บริการ index.html พร้อม header ที่ไม่แคชหรือแคชสั้น ในขณะที่ไฟล์ที่มีแฮชถูกแคชไว้นาน
การบิลด์ยังไม่เสร็จหรือไม่ได้ดีพลอย ถ้าการบิลด์ล้มเหลว โฮสต์อาจให้บริการโฟลเดอร์ผลลัพธ์ที่เก่าหรือว่างเปล่า ตรวจบันทึกการบิลด์หา error
เผยแพร่โฟลเดอร์ผิด โฮสต์ต้องให้บริการผลลัพธ์ของการบิลด์ (มักคือ dist หรือ build) ไม่ใช่โฟลเดอร์ซอร์สของโปรเจกต์ การให้บริการซอร์สจะได้ index.html ที่ชี้ไปยัง /src/main.tsx ซึ่งเบราว์เซอร์รันไม่ได้
ขั้นที่ 3: ตรวจตัวแปรสภาพแวดล้อม
แอป frontend มักอ่านการตั้งค่าอย่าง URL ของ API หรือคีย์สาธารณะตอนบิลด์ ถ้าตัวแปรหายไปในบิลด์จริง โค้ดอย่าง createClient(undefined, undefined) จะ throw ทันที และหน้าจะขาว
สิ่งที่ควรรู้:
- ใน Vite มีเพียงตัวแปรที่ขึ้นต้นด้วย
VITE_เท่านั้นที่ใช้ได้ในโค้ดเบราว์เซอร์ อ่านด้วยimport.meta.env.VITE_NAMEใน Create React App คือREACT_APP_ใน Next.js คือNEXT_PUBLIC_ - ค่าเหล่านี้ถูก ฝังไว้ตอนบิลด์ การเพิ่มตัวแปรหลังบิลด์ไม่มีผลจนกว่าจะบิลด์และดีพลอยใหม่
- พรีวิวหรือเครื่องในเครื่องอาจมีไฟล์
.envที่บิลด์โปรดักชันไม่มี ให้ตั้งตัวแปรเดียวกันบนโฮสต์ - ทุกอย่างที่มีคำนำหน้าเหล่านี้จะไปอยู่ใน JavaScript สาธารณะ ใส่เฉพาะค่าสาธารณะ ไม่ใส่คีย์ลับ
การทดสอบอย่างรวดเร็ว: ค้นหาในข้อความ error ของ console ว่ามี undefined ใกล้ชื่อการตั้งค่าหรือไม่ หรือถามว่า:
หน้าที่เผยแพร่แสดงหน้าขาวว่างเปล่า ให้แสดงรายการตัวแปรสภาพแวดล้อมทุกตัวที่ frontend อ่าน ตรวจว่าตัวไหนหายหรือว่างในบิลด์จริง และทำให้แอปแสดงข้อความ error ที่ชัดเจนแทนหน้าว่างเมื่อขาดตัวแปรใดตัวหนึ่ง
ขั้นที่ 4: แก้ crash
ถ้า console แสดง error JavaScript ปกติ โค้ดพังระหว่างการเรนเดอร์ สาเหตุทั่วไปในแอปที่สร้างด้วย AI:
- ข้อมูลยังไม่ถูกโหลด คอมโพเนนต์อ่าน
user.nameก่อนที่userจะมาถึง วิธีแก้คือ loading state หรือ optional chaining (user?.name) - ข้อมูลว่าง บัญชีใหม่ไม่มีระเบียน และโค้ดสมมติว่ารายการมีอย่างน้อยหนึ่งรายการ
- รูปร่างข้อมูลไม่ตรง API ส่ง error object กลับมาแทนรายการที่โค้ดคาดหวัง
- import หาย หลังจากชื่อไฟล์ถูกเปลี่ยนหรือย้าย
- ใช้ API ที่มีเฉพาะเบราว์เซอร์ระหว่าง server-side rendering เช่น
windowหรือlocalStorageใน server component ของ Next.js
ให้ AI ทั้ง error เต็ม หน้าที่เกิดปัญหา และคุณล็อกอินเป็นใคร:
หน้า Dashboard ว่างเปล่าสำหรับผู้ใช้ใหม่ Console:
TypeError: Cannot read properties of undefined (reading 'map')ที่ProjectList.tsx:18ทำงานได้กับบัญชีของฉันที่มีโปรเจกต์ แก้ให้บัญชีว่างแสดง "ยังไม่มีโปรเจกต์" และทดสอบกับบัญชีใหม่ในพรีวิว
ขั้นที่ 5: เพิ่ม error boundary
ใน React คอมโพเนนต์ที่ crash เพียงตัวเดียวสามารถถอดแอปทั้งหมดออกได้ นั่นคือเหตุผลที่บั๊กเล็ก ๆ ทำให้หน้าว่างสนิท error boundary คือคอมโพเนนต์ที่จับ error ตอนเรนเดอร์ที่อยู่ด้านล่างและแสดงผลสำรองแทน
เพิ่ม error boundary รอบ route หลักที่แสดง "Something went wrong" พร้อมปุ่ม Reload และบันทึก error ลง console คง header และการนำทางไว้นอก boundary เพื่อให้ยังแสดงผลอยู่
มันไม่ได้แก้บั๊ก แต่ผู้เยี่ยมชมจะเห็นข้อความแทนหน้าจอว่าง และคุณจะเห็นว่าพังตรงไหน
ขั้นที่ 6: ไม่มี error แต่ยังขาวอยู่
ถ้า console สะอาดและสคริปต์โหลดได้:
- ตรวจแท็บ Elements มีเนื้อหาข้างใน
<div id="root">หรือไม่? ถ้ามี แสดงว่าเรนเดอร์แล้วแต่มองไม่เห็น: ข้อความสีขาวบนพื้นขาวopacity: 0display: noneหรือองค์ประกอบเต็มจอที่บังอยู่ - ตรวจ router ถ้าไม่มี route ตรงกับ URL ปัจจุบันและไม่มี route "ไม่พบ" router บางตัวจะไม่เรนเดอร์อะไรเลย เพิ่ม catch-all route ที่แสดงหน้า 404
- ตรวจจุดติดตั้ง (mount point) โค้ดต้องติดตั้งลงในองค์ประกอบที่มีอยู่จริง ถ้า
index.htmlมีid="app"แต่โค้ดหาrootจะไม่มีอะไรปรากฏ (และ React มักบันทึก error) - ตรวจส่วนเสริมของเบราว์เซอร์ ลองหน้าต่างส่วนตัว (private) บางครั้งตัวบล็อกโฆษณาบล็อกสคริปต์ที่มีชื่ออย่าง
analyticsหรือads
ขาวเฉพาะหลังรีเฟรชหน้า?
ถ้าหน้าแรกทำงานได้แต่รีเฟรช /dashboard แล้วขึ้นหน้าว่างหรือ 404 แสดงว่าเซิร์ฟเวอร์ไม่รู้ว่าต้องส่ง index.html สำหรับ route ของแอป นั่นคือปัญหา fallback ของ routing ซึ่งอธิบายไว้ในวิธีแก้ error 404 หลังดีพลอย
ข้อผิดพลาดที่พบบ่อย
- อ่าน error สุดท้ายแทนที่จะเป็นแรก บรรทัดสีแดงแรกมักเป็นสาเหตุ
- ตั้งตัวแปรสภาพแวดล้อมโดยไม่บิลด์ใหม่ ตัวแปรของ frontend ถูกกำหนดตอนบิลด์
- ทดสอบด้วยบัญชีของตัวเองเท่านั้น การ crash กับบัญชีว่างเป็นหนึ่งในสาเหตุหน้าขาวที่พบบ่อยที่สุด
- คิดว่าการดีพลอยสำเร็จแล้ว ตรวจบันทึกการบิลด์ก่อนดีบักโค้ด
- โทษแคชเบราว์เซอร์กับทุกอย่าง การ hard refresh ตัดประเด็นนี้ออกได้ในไม่กี่วินาที ถ้าหน้ายังว่างอยู่ ปัญหาเป็นอย่างอื่น
หน้าขาวใน Mythex
ถ้า พรีวิว ว่างเปล่า ให้ตรวจก่อนว่าแอปกำลังรันอยู่ (เปิด Code → terminal) จากนั้นขอให้ Mythex เริ่มเซิร์ฟเวอร์ที่ถูกต้อง กด Refresh ในแถบเครื่องมือพรีวิว หรือใช้ /fix สำหรับ URL ที่เผยแพร่แล้ว ที่ว่างเปล่า เอกสารแนะนำให้รอสักนาทีแล้ว hard refresh ยืนยันว่าตั้งค่าตัวแปรสภาพแวดล้อมและฐานข้อมูลแล้วก่อนเผยแพร่ และตรวจโควต้าการโฮสต์ของคุณ จำไว้ว่าแอปที่เผยแพร่เป็นสแนปชอต หลังแก้ไขอะไรแล้วให้เผยแพร่ใหม่ ถ้าการเปลี่ยนแปลงทำให้เกิดปัญหา Revert to this point ที่คำตอบที่ใช้งานได้ล่าสุดจะย้อนโปรเจกต์กลับไป ดูการแก้ปัญหา และการแก้ปัญหาการเผยแพร่ ในเอกสาร และคู่มือทั่วไปเรื่องการดีบักแอปที่สร้างด้วย AI
เช็กลิสต์หน้าขาว
- อ่าน error สีแดงแรกใน Console
- ตรวจแท็บ Network หาไฟล์
.js/.cssที่ขึ้น 404 หรือส่ง HTML กลับมา - base path ตรงกับที่แอปถูกให้บริการ
- การบิลด์เสร็จสมบูรณ์ และโฟลเดอร์ผลลัพธ์คือสิ่งที่ถูกเผยแพร่
- ตั้งตัวแปรสภาพแวดล้อมของ frontend ทั้งหมดบนบิลด์จริง แล้วบิลด์ใหม่
- แก้ crash แล้ว รวมถึงสำหรับบัญชีว่างและบัญชีใหม่
- มี error boundary เพื่อให้ crash ในอนาคตแสดงข้อความ
- มี catch-all route สำหรับ URL ที่ไม่รู้จัก
- ทดสอบหลัง hard refresh และในหน้าต่างส่วนตัว
คำถาม
ทำไมแอป React ของฉันขึ้นหน้าขาวว่างเปล่า?
ส่วนใหญ่เพราะ JavaScript crash ก่อนที่จะแสดงอะไรออกมา หรือไฟล์ JavaScript ไม่เคยโหลดสำเร็จ เปิด console ของเบราว์เซอร์ error สีแดงแรกจะบอกว่าเป็นกรณีไหน พร้อมไฟล์และบรรทัดที่เกิดปัญหา
ทำไมแอปทำงานในเครื่องได้แต่หลังดีพลอยขึ้นหน้าว่าง?
สาเหตุที่พบบ่อยที่สุดคือตัวแปรสภาพแวดล้อมที่ไม่เคยถูกตั้งค่าสำหรับบิลด์จริง ไฟล์ JavaScript และ CSS ที่ถูกร้องขอจาก path ที่ผิด (base path ไม่ตรงกัน) และ index.html ที่ถูกแคชไว้ชี้ไปยังไฟล์ที่ไม่มีอยู่แล้ว
"Failed to load module script" หมายความว่าอะไร?
เบราว์เซอร์ขอไฟล์ JavaScript แล้วได้หน้า HTML กลับมาแทน ซึ่งมักเป็น index.html ของเว็บไซต์หรือหน้า error path ของไฟล์ผิดหรือไฟล์ไม่มีอยู่บนเซิร์ฟเวอร์ ให้ตรวจผลลัพธ์ของการบิลด์และการตั้งค่า base path ของแอป
จะทำอย่างไรไม่ให้บั๊กเดียวทำให้ทั้งหน้าว่าง?
เพิ่ม error boundary ใน React error boundary คือคอมโพเนนต์ที่จับ error ตอนเรนเดอร์ในส่วนที่อยู่ด้านล่าง และแสดงข้อความสำรองแทนการถอดทุกอย่างออก