Node.js template literal 嵌入 JavaScript 的地雷:\n 和 \' 會讓整個 script 靜默崩潰
直接回答
Node.js template literal 裡的 \n 和 \' 等 escape 序列會被 Node.js 處理成真實字元,輸出到瀏覽器的 JavaScript 因此語法錯誤,整個 script block 靜默崩潰。症狀是 HTML 顯示正常但頁面功能完全失效,console 沒有報錯。解法是把 template literal 裡的 \ 全部雙寫(\\n 輸出成 \n、\\' 輸出成 \')。
同一個 bug 踩了兩次,第一次花了兩個小時才找到原因,第二次認出來只用了十分鐘。
症狀每次都一樣:HTML 顯示正常,頁面功能完全不動,console 沒有報錯,資料清單空白。
原因每次也都一樣:Node.js template literal 裡的 escape 序列。
—
第一次踩的是 \'。
在 Vercel serverless function 裡用 template literal 產生 HTML 頁面,img 的 onerror attribute 裡有這樣的字串:
const html = `<img onerror="this.parentNode.textContent=\\'${name}\\'">`;
Node.js 處理 template literal 的時候,\' 被轉成了 ',輸出到瀏覽器的變成:
<img onerror="this.parentNode.textContent='Ken'">
看起來沒問題,但整個 script block 在這之前其實已經因為另一段語法錯誤崩潰了。那段 \' 出現在字串拼接裡,產生了 textContent='' + name + '' 的語法,在某些位置讓 JS parser 解讀出問題。
修法:把 onerror 邏輯抽成全域函式,attribute 只留 onerror="handleImgError(this)"。
—
第二次踩的是 /\n/g。
幾個月後在同一個專案,要在輸出的 JavaScript 裡把換行轉成 <br>:
const html = `...content.replace(/\n/g, '<br>')...`;
Node.js 處理 template literal,\n 被換成真實換行字元。瀏覽器看到的是:
content.replace(/
/g, '<br>')
regex literal 裡有真實換行,語法錯誤,整個 script block 崩潰。
修法:改成 /\\n/g,template literal 輸出 /\n/g,瀏覽器看到正確語法。
—
根本規則只有一條:Node.js template literal 會處理所有 \x escape 序列。
要輸出給瀏覽器看的 JavaScript,裡面的每一個 \ 都要雙寫,Node.js 消耗一層,瀏覽器拿到正確的一層。
不確定的時候,把複雜邏輯抽成全域函式,完全避開 attribute 嵌入字串的需求。這個解法更根本,不會因為字串內容改變而重新踩坑。