GitMaster 是如何定製 file-icons/atom

GitMaster裏面展現項目結構時,同時也顯示了對應的iconjavascript

看起來和Octotree是沒什麼區別,但其實在維護和更新上是有顯著區別的。css

Octotree是直接從file-icons/atom複製相關樣式和字體文件到項目裏,這樣耦合的方式很不利於維護,因此我在處理文件圖標時進行了額外的處理,把全部文件圖標經過npm包的形式引入。前端

你們可能好奇爲何不直接用file-icons/atom,沒有采用的緣由有幾個:java

  • css樣式通過Content Script方式注入會污染全局樣式
  • 缺乏Octicons圖標
  • woff2文件指向不對

方案

通過考量,最終採用經過腳本處理文件,而後發佈npm包: ineo6/file-iconsnode

下載 file-icons/atom

使用download-git-repoGitHub下載代碼。webpack

還使用npm開發過程當中經常使用的chalkoragit

ora是一個終端加載動畫的庫,有了它,你的終端不會再蒼白。github

image.png

chalk的做用是豐富終端文字樣式。web

image.png

const path = require('path');
const chalk = require('chalk');
const fs = require('fs');
const os = require('os');
const ora = require('ora');
const download = require('download-git-repo');

const cwd = process.cwd();

const origin = 'file-icons/atom';
const branch = "#master";

const tmpDirPrefix = path.join(os.tmpdir(), '.tmp');
const tmpDir = fs.mkdtempSync(tmpDirPrefix);

const spinner = ora(`downloading ${origin}...`);
spinner.start();

download(`${origin}${branch}`, tmpDir, { clone: false }, function (err) {
  spinner.stop();
  if (err) {
    console.log(chalk.red(`Failed to download repo https://github.com/${origin}${branch}`, err));
  } else {
    console.log(chalk.green(`Success to download repo https://github.com/${origin}${branch}`));

    const spinnerExtract = ora('Extract Data...');
    spinnerExtract.start();

    try {
      // 處理代碼的邏輯

      spinnerExtract.stop();
      console.log(chalk.green('Done!'));
    } catch (e) {
      spinnerExtract.stop();
      console.log(e.message);
    }
  }
})

less處理

替換@font-face url

文件 styles/fonts.less 裏面的內容是以下格式:chrome

@font-face {
    font-family: FontAwesome;
    font-weight: normal;
    font-style: normal;
    src: url("atom://file-icons/fonts/fontawesome.woff2");
}

這個顯然沒法在前端項目甚至Chrome擴展里正確引用woff2字體。

由於在Chrome擴展裏沒法引入遠程的woff2,因此改成引入擴展目錄中的字體,即改爲以下格式:

@font-face {
    font-family: FontAwesome;
    font-weight: normal;
    font-style: normal;
    src: url("@{ICON_PATH}/fonts/fontawesome.woff2");
}

而後在webpack裏設置less變量ICON_PATH

'less-loader',
          {
            loader: 'less-loader',
            options: {
              javascriptEnabled: true,
              modifyVars: {
                ICON_PATH: 'chrome-extension://__MSG_@@extension_id__'
              },
            },
          },

如何修改less文件

推薦使用gonzales-pe,它可以解析SCSS, Sass, LESS,並轉爲AST抽象語法樹。

而後咱們根據須要修改AST的結構,最終調用astNode.tostring()轉換獲得代碼。

const { parse } = require('gonzales-pe');
const fs = require('fs');
const chalk = require('chalk');

function replaceAtomHost(content) {
    if (content.includes('atom://file-icons/')) {
        content = content.replace('atom://file-icons/', '@{ICON_PATH}/');
    }

    return content;
}

function replaceUrlHost(ast) {
    ast.traverseByType('uri', (node) => {
        node.traverse(item => {
            if (item.is('string')) {
                item.content = replaceAtomHost(item.content)
            }
        });
    });

    return ast;
}

function replaceDeclaration(ast) {
    ast.traverseByType('declaration', (decl) => {
        let isVariable = false;

        decl.traverse((item) => {
            if (item.type === 'property') {
                item.traverse((childNode) => {
                    if (childNode.content === 'custom-font-path') {
                        isVariable = true;
                    }
                });
            }

            if (isVariable) {
                if (item.type === 'value') {
                    const node = item.content[0];

                    node.content = replaceAtomHost(node.content)
                }
            }
            return item;
        });
    });

    return ast;
}

function processFonts(lessFile) {
    const content = fs.readFileSync(lessFile).toString();

    if (content && content.length > 0) {

        let astTree;

        try {
            astTree = parse(content, {
                syntax: 'less'
            })
        } catch (e) {
            console.log(chalk.red(`parse error: ${e}`));
            return;
        }

        try {
            astTree = replaceUrlHost(astTree);
            astTree = replaceDeclaration(astTree);

            return astTree;
        } catch (e) {
            console.log(chalk.red(`transform error: ${e}`));
        }
    }
}

module.exports = function (file) {
    const ast = processFonts(file);

    if (ast) {
        fs.writeFileSync(file, ast.toString());
    }
}

文件處理

.
├── bin              
├── index.js
├── index.less              // 入口樣式
├── lib                     // 完成的樣式,字體
└── resource                // 待合併資源

file-icons/atom複製如下文件到lib:

  • fonts
  • styles
  • lib/icons
  • lib/utils.js

resource裏面內容複製到lib

index.less裏面內容以下:

@import "lib/styles/colours.less";
@import "lib/styles/fonts.less";
@import "lib/styles/octicons.less";

.file-icons-wrapper {
  @import "lib/styles/icons.less";
  @import "lib/styles/fix.less";
}

這裏經過添加父級file-icons-wrapper來控制樣式影響範圍。

至此,大體完成了針對file-icons/atom的定製工做。

總結

最終咱們經過npm run build命令完成拉取代碼,處理文件的。

對應的腳本在bin/update.js

固然最後能夠優化的是讓任務自動執行,這點能夠結合GitHub Actions的定時任務實現。本文就暫不花費篇幅介紹了,感興趣的能夠摸索下。

相關文章
相關標籤/搜索