不確定從哪一版 CLI 開始,當執行 ng serve
時,命令視窗的進度表,就會出現很混亂的數字後,才會正常的顯示編譯結果,想說一開始就算了,GitHub 上也找不到相關的 Issue,就這樣子擺著。今天實在受不了,就開始追到底是什麼原因造成這神奇的現象
這神奇的現象,用簡單的影片表示一下 (使用字型: 細明體)
開始追蹤
當然一開始是從 Angular CLI 下手,但很不幸的,Angular CLI 所使用的進度顯示是透過 Webpack 的 ProgressPlugin
來完成的
1 2 3 4 5 6
| ... const ProgressPlugin = require('webpack/lib/ProgressPlugin'); ... if (buildOptions.progress) { extraPlugins.push(new ProgressPlugin({ profile: buildOptions.verbose, colors: true })); }
|
只好前往 ProgressPlugin
探索了,還好 ProgressPlugin
只是單純一隻 js 檔案,應該很容易找 (才怪)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| const defaultHandler = (percentage, msg, ...args) => { let state = msg; const details = args; if (percentage < 1) { percentage = Math.floor(percentage * 100); msg = `${percentage}% ${msg}`; if (percentage < 100) { msg = ` ${msg}`; } if (percentage < 10) { msg = ` ${msg}`; } for (let detail of details) { if (!detail) continue; if (detail.length > 40) { detail = `…${detail.substr(detail.length - 39)}`; } msg += ` ${detail}`; } } if (profile) { state = state.replace(/^\d+\/\d+\s+/, ""); if (percentage === 0) { lastState = null; lastStateTime = Date.now(); } else if (state !== lastState || percentage === 1) { const now = Date.now(); if (lastState) { const stateMsg = `${now - lastStateTime}ms ${lastState}`; goToLineStart(stateMsg); process.stderr.write(stateMsg + "\n"); lineCaretPosition = 0; } lastState = state; lastStateTime = now; } } goToLineStart(msg); process.stderr.write(msg); };
const goToLineStart = nextMessage => { let str = ""; for (; lineCaretPosition > nextMessage.length; lineCaretPosition--) { str += "\b \b"; } for (var i = 0; i < lineCaretPosition; i++) { str += "\b"; } lineCaretPosition = nextMessage.length; if (str) process.stderr.write(str); };
return defaultHandler; };
|
這是很接近尾巴的搜尋結果,我知道畫面顯示出亂子,一定是這裡面的某一行有問題。經過 1 個小時的驗證,上述的程式碼並沒有錯,但是有抓到一個關鍵點,當我把 …
換成其他符號時,執行結果就會很漂亮的顯示進度表,
這樣應該既是這個符號在作怪,但到底是哪裡出錯了。最後與保哥研究的結果,竟然是字型的關係
觀察結果
我電腦 windows 下命令視窗所使用的字型是預設字型,細明體,就我自己的了解,細明體應該是等寬字型,所謂的等寬字型是指,英文數字在畫面上所顯示的寬度是一樣的,而中文字因為是兩個字元,所以是兩個英文字的寬度
同樣的文字換成新細明體就會視不同的顯示方式
Fira Code
字型
到這裡,我們知道字型的不同,對於每一個字寬度的認定是不同的,而 webpack 的 ProgressPlugin
是使用字串長度做一些黑魔法的事情,(刪除原本的顯示文字,並在原本位置上顯示新的文字)
而 …
在不同字體上的顯示方式又是如何呢?
沒錯,細明體的 …
竟然被判斷成全型字(兩個字元),難怪在計算要刪除文字長度跟顯示時會出亂子,兇手就是你
驗證一下,將命令視窗的字型改成【點陣字體】後再跑一次,看看會不會正常
解決方案
- 無視他,既然知道是字型的問題而非程式問題,可以選擇無視他
- 修正命令視窗的預設字體,設定方式可以參考保哥這篇 讓你的命令提示字元或 WSL 擁有一個美麗等寬的字型設定
參考資料