我的遊戲在自己電腦跑超順,一上線就整片黑畫面!
遊戲在本機玩得好好的,一部署上線、點開始就黑畫面。build 還顯示成功、沒半個錯。這不是你運氣差——你缺的詞叫「打包後模組初始化順序被重排」(TDZ)。這頁教你為什麼「build 過」不等於「能跑」。
先說結論:你沒有做錯任何事。你只是相信了「build 成功」這四個字。
情境還原:遊戲在你電腦上跑得跟絲綢一樣順,你信心滿滿部署上線。點「開始遊戲」——
黑。畫。面。
啥都沒有。你回頭看 build log,綠燈,exit code 0,零錯誤,一切完美。你整個問號:「build 明明過了啊???」
於是你開始亂改、亂試、亂重新部署,改到懷疑自己是不是根本不會 code。
停。這鍋不是你的。這是一個超陰險的坑,圈內人管它叫 TDZ。
你缺的詞 = Temporal Dead Zone(模組初始化順序被打包工具重排)
為什麼「自己電腦好好的」上線就爆?(人話版)
你電腦上跑的是「開發模式」,上線的是「打包後的正式版」。這兩個根本不是同一個東西。
- 開發模式:每個檔案乖乖各自載入,按你寫的順序來。所以沒事。
- 正式版:打包工具(像 Vite)為了讓檔案更小更快,會把你的程式碼重新排列組合、壓縮。
問題就出在這個「重新排列」。
假設你的 A 檔在最上面 import 了 B 檔裡的一個東西(比如一張設定表)。打包工具重排之後,可能變成 A 檔已經開始執行了,但 B 檔那張設定表還沒生出來。A 檔伸手去拿一個還不存在的東西——
Cannot access 'X' before initialization。翻成白話就是:「你在東西還沒出生前就想抱它。」
這就是 Temporal Dead Zone(暫時性死區)——那個東西在「已經被宣告」和「真正被賦值」之間,有一小段啥都不是的空窗期,你剛好在那個瞬間去碰它,當場暴斃。
而最靠北的是:這個錯只在瀏覽器 runtime 才現形,build 完全抓不到。 所以 build 給你綠燈,你以為穩了,結果上線黑畫面。
正確做法:不要跨檔案硬 import,用「傳」的
觸發這個坑最常見的寫法,就是在某個模組的最上層,去 import 另一個模組的 const。
解法:別 import,改成用參數把資料「傳」進去。
// ❌ 危險:cow.ts 最上面 import 另一個檔的 UPGRADES
// → 打包重排後,UPGRADES 可能還沒初始化就被碰
// ✅ 安全:不 import,改成「建立時把需要的資料當參數傳進來」
export function createCowSystem(ctx, padPositions = []) {
// 用傳進來的 padPositions,而不是去 import 全域的 UPGRADES
}
// 在主檔呼叫時,才把資料餵進去
const cowSystem = createCowSystem(runtime, UPGRADES.map(u => ({ x: u.x, z: u.z })));
差別在哪?用 import,等於「我自己去別的房間硬搬東西,管他生出來沒」。用參數傳,等於「你把東西準備好了,親手交到我手上」——時機由你控制,不會撲空。
⚖️ 誠實說清楚:這個坑不是遊戲專屬,任何用 Vite/類似打包工具的網頁專案都可能中。而且它不一定每次都爆——要看打包工具剛好怎麼排。核心教訓其實是一句更大的話:「build 成功」只代表「文法沒錯」,不代表「跑得起來」。部署前,一定要真的在瀏覽器打開正式版點一輪,不能只看 build 有沒有綠燈。
你會搜錯的關鍵字 vs 該搜的正確詞彙
| 你崩潰時會打的(搜不到) | 該搜的正確詞彙 |
|---|---|
| 「遊戲上線黑畫面 build 卻成功」 | Temporal Dead Zone / TDZ production build |
| 「本機正常部署後壞掉」 | Vite module initialization order |
| 「Cannot access before initialization」 | circular import / module load order |
把右邊那欄丟進 Google、或直接貼給你的 AI。這就是我們在幹的事——把你崩潰時打出來的髒話,翻譯成能找到答案的詞。
🎁 直接貼給你的 ChatGPT / Claude
這一段免費。複製、貼上、送出——先讓你的 AI 動起來。
我做的網頁遊戲(用 Vite 打包)在 dev 模式跑得很好,但 production build 部署後點「開始」就黑畫面,瀏覽器 console 報 `Cannot access 'X' before initialization`。 請告訴我: 1. 為什麼 dev 模式正常、但 production build 會出這種錯?(我聽說跟模組初始化順序 / Temporal Dead Zone 有關) 2. 通常是什麼寫法會觸發它?(例如跨檔案 import 某個 const) 3. 怎麼改才安全?請給我「用參數傳資料」取代「跨模組 import」的範例。 4. 為什麼 build 會顯示成功、卻在瀏覽器才爆?我以後部署前該怎麼先抓到?
想更進一步?
上面免費的三層已經能讓你動起來。如果你想要「照著做不迷路」甚至「我們幫你跑好」——往下看。
- 免費 這個坑是什麼、誰會踩
- 免費 人話解釋:錯在哪、正確的詞彙
- 免費 一段可直接貼給 AI 的 prompt
完整實作文件
未來新增- 一份「部署前必跑」的檢查清單,抓出 build 過但會在瀏覽器爆的問題
- TDZ 常見觸發寫法對照表 + 每種的安全改法
- 怎麼設定「本機就模擬 production」的流程,不用等上線才發現
可跑的 codebase / skill
未來新增- 現成的模組相依結構範本(用參數注入取代跨模組 import)
- ✅ 本機 production 預覽腳本 ✅ 部署前煙霧測試
本文首發於 AI 許願池(https://kaowan.pages.dev/articles/game-works-local-blank-online/),發佈日 2026年7月5日。 轉載請註明出處——原創者不怕考古,只有小偷怕。🕳️