GitMaster
裏面展現項目結構時,同時也顯示了對應的icon
。javascript
看起來和Octotree
是沒什麼區別,但其實在維護和更新上是有顯著區別的。css
Octotree
是直接從file-icons/atom
複製相關樣式和字體文件到項目裏,這樣耦合的方式很不利於維護,因此我在處理文件圖標時進行了額外的處理,把全部文件圖標經過npm
包的形式引入。前端
你們可能好奇爲何不直接用file-icons/atom
,沒有采用的緣由有幾個:java
css
樣式通過Content Script
方式注入會污染全局樣式Octicons
圖標woff2
文件指向不對通過考量,最終採用經過腳本處理文件,而後發佈npm
包: ineo6/file-icons。node
file-icons/atom
使用download-git-repo
從GitHub
下載代碼。webpack
還使用npm
開發過程當中經常使用的chalk
和ora
。git
ora
是一個終端加載動畫的庫,有了它,你的終端不會再蒼白。github
chalk
的做用是豐富終端文字樣式。web
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); } } })
文件 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__' }, }, },
推薦使用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
的定時任務實現。本文就暫不花費篇幅介紹了,感興趣的能夠摸索下。