不確定從哪一版 CLI 開始,當執行 ng serve 時,命令視窗的進度表,就會出現很混亂的數字後,才會正常的顯示編譯結果,想說一開始就算了,GitHub 上也找不到相關的 Issue,就這樣子擺著。今天實在受不了,就開始追到底是什麼原因造成這神奇的現象
這神奇的現象,用簡單的影片表示一下 (使用字型: 細明體)
開始追蹤
當然一開始是從 Angular CLI 下手,但很不幸的,Angular CLI 所使用的進度顯示是透過 Webpack 的 ProgressPlugin 來完成的
| 12
 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 檔案,應該很容易找 (才怪)
| 12
 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 擁有一個美麗等寬的字型設定
參考資料