前陣子分享將 Git diff 文件轉成網頁版程式異動對照表(Compare List)的做法,上路沒多久便觸礁。原因是一次新增大量檔案(例如:網站新增內容,包含大量 HTML、CSS、JS 檔全文)的 diff 檔可能超過 10MB,轉換產生的 HTML DOM 過於龐大讓瀏覽器很卡。Chrome 還勉強堪用,但產生頁面過程會無回應,捲動過程畫面會空白,需要愛與包容才能用下去;至於 IE 更慘(對,有使用者還在用 IE),絕大部分時間處於無回應狀況,有時網頁還會崩潰,就算有滿滿的愛與包容也無法克服。

為解決大檔開啟問題,我寫了一個改良版,先只列出清單,點擊檔名後才顯示新舊版逐行對照,再點一次則收合對照檢視。如此讓 HTML DOM 單純化,顯示速度跟操作流暢度改善很多,10MB 1441 筆異動的 diff 檔用 IE 也還能開啟及正常檢視。另外我也設計了全部展開按鈕,可一次展開所有新舊對照內容,讓較小的 diff 文件保持原有的呈現模式。

註:若檔案太大處理過久讓 IE 頁籤重啟,可開 F12 Dev Tools 避免,但仍需耐心等候。參考

如下圖,以下是個 10MB git diff 的檢視結果,標準 diff2html 產生的 HTML DOM 過於肥大,在 IE 會完全卡死無法使用,改為互動顯示後仍可操作(雖然處理過程要等快兩分鐘):

以下是完整程式碼,有需要的同學請自取:

<!DOCTYPE html>

<html>

<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <link rel="stylesheet" type="text/css" href="https://www.unpkg.com/diff2html@2.12.1/dist/diff2html.css" />
    <script src="https://www.unpkg.com/diff2html@2.12.1/dist/diff2html.js"></script>
    <style>
        html,body {    height: 100%; margin: 0; padding: 6px; }
        .d2h-file-name{ font-size: 9pt; cursor: pointer; }
        .d2h-file-list-line { display: block; }
        .d2h-file-list-title button { font-size: 9pt; }
    </style>
</head>

<body>
    <input type="file" id="diffSrc" />
    <div id=report>
        <div id=list></div>
    </div>
    <script>
        function showLineByLine(a) {
            if (a.showDiff) {
                //IE doesn't support element.remove()
                var div = a.parentNode.nextElementSibling;
                div.parentNode.removeChild(div); 
                a.showDiff = false;
            }
            else {
                var div = document.createElement("div");
                div.innerHTML = Diff2Html.getPrettySideBySideHtmlFromJson(a.diffContent);
                a.parentNode.parentNode.appendChild(div);
                a.showDiff = true;
            }
        }
        function toggleAll(expand) {
            [].forEach.call(document.querySelectorAll('a.d2h-file-name'), function(a) {
                if (expand != a.showDiff) showLineByLine(a);
            });
        }
        function readFile(e) {
            var file = e.target.files[0];
            if (!file) return;
			document.getElementById("diffSrc").style.display = "none";
			document.getElementById('list').innerHTML = "Processing...";		
            var reader = new FileReader();
            reader.onload = function (re) {
                var diffText = re.target.result;
                var diffFiles = Diff2Html.getJsonFromDiff(diffText);            
                var diffHtml = Diff2Html.getPrettyHtmlFromJson(diffFiles, {
                    showFiles: true,
                    matching: 'lines',
                    outputFormat: 'side-by-side',
                });
                //get the file list part
                var listHtml = diffHtml.substr(0, diffHtml.indexOf('<div class="d2h-wrapper"'));
                document.getElementById('list').innerHTML = listHtml;
                [].forEach.call(document.querySelectorAll('a[href]'), function(a, i) {
                    a.diffContent = [diffFiles[i]];
                    a.removeAttribute("href");
                    a.onclick = function() { showLineByLine(a); };
                });
                var title = document.querySelector('.d2h-file-list-title');
                title.innerHTML = title.innerText + 
                    " <button onclick='toggleAll(true)'>Expand All</button>" +
                    " <button onclick='toggleAll(false)'>Collapse All</button>";
            };
            reader.readAsText(file);
        }
        document.getElementById("diffSrc").addEventListener("change", readFile, false);
    </script>
</body>

</html>

diff2html.js can convert the git diff result to HTML. When the diff is large, the HTML DOM will be too large to view, especially in IE. The interactive version providering list first and show the compare view file-by-file can solve the problem.


Comments

# by 小黑

好猛! 謝謝分享 ~

Post a comment