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的定时任务实现。本文就暂不花费篇幅介绍了,感兴趣的能够摸索下。

相关文章
相关标签/搜索