技術(shù)的學(xué)習(xí)一定要輔以代碼的實(shí)踐乐纸,菜鳥程序員撲在輪子上要像饑餓的人撲在面包上衬廷。
——沃茲基碩德
受到掘金上看到的 yddict:一個命令行查單詞的工具 的啟發(fā),原來摸一個 Node.js 的 demo 不一定非要寫一個服務(wù)器汽绢。恰逢最近開始看《算法(第4版)》吗跋,把練習(xí)代碼和筆記傳到 github 上時需要在 README.md 里放一份帶鏈接的目錄,方便在線跳轉(zhuǎn)查閱。兩者綜合跌宛,就有了開發(fā)一個能夠?qū)㈨?xiàng)目內(nèi)文件結(jié)構(gòu)自動映射并生成為 README.md 的項(xiàng)目目錄管理工具的靈感酗宋。
看上去是一個簡單的小工具,實(shí)際上花了 3 天才基本成型(當(dāng)然不是整的)疆拘。隨著思路從項(xiàng)目目錄管理到圖書管理再到書籍再到文藝社蜕猫,我決定將這個小工具命名為 yuki,蘊(yùn)含了我個人滿滿的宅趣味哎迄。
幸運(yùn)的是回右,這個日語里常見的詞竟然在 NPM 里還沒被搶用。我也因此不用為其加個后綴漱挚,直接就可以用這個名字傳上 NPM翔烁,以供使用。
這篇文章剩下來的篇幅一是介紹這個小工具的使用場景旨涝、實(shí)際用法等租漂,二是大概談一談開發(fā)過程中稍微值得一記的經(jīng)驗(yàn)。
關(guān)于 yuki
使用 Node.js 開發(fā)的項(xiàng)目目錄管理工具颊糜,能夠?qū)㈨?xiàng)目內(nèi)文件結(jié)構(gòu)自動映射并生成為 README.md
項(xiàng)目地址
適用場合
當(dāng)一份 README.md 的主體內(nèi)容是項(xiàng)目目錄哩治,而你又厭倦了每次增加、修改衬鱼、刪除項(xiàng)目中文件時都要對 README 進(jìn)行維護(hù)业筏,那么不妨試試 yuki!
它可以在極短時間內(nèi)幫你生成符合要求的 README.md 文檔鸟赫。你更可以通過配置一份 yuki.config.json 來滿足你的以下需求:
- 固定文檔標(biāo)題
- 目錄前后增加固定內(nèi)容
- 映射時忽略指定文件夾蒜胖、文件、擴(kuò)展名
- 根據(jù)指定擴(kuò)展名選擇是否去掉文件名的擴(kuò)展名或加上書名號
- 讓每個文件都帶上 Github 的鏈接以方便在線跳轉(zhuǎn)查看
你可以用 yuki 幫助你輕松維護(hù) github 上類似博客抛蚤、筆記台谢、代碼匯總等項(xiàng)目!
效果示例
我的《算法》筆記及代碼項(xiàng)目的 README.md 完全通過 yuki 生成岁经。你可以點(diǎn)擊以查看效果朋沮。
使用方法
請確認(rèn)你使用的電腦有 Node 環(huán)境,越新越好缀壤。
安裝 yuki
npm install -g yuki
進(jìn)入需要生成 README.md 的文件夾
# 請將 <dirname> 換為文件夾路徑
cd <dirname>
創(chuàng)建 yuki.config.json(可選)
touch yuki.config.json
配置 yuki.config.json(可選)
{
// README.md的大標(biāo)題(h1)樊拓,默認(rèn)為所在文件夾名
"title": "《算法(第4版)》筆記及代碼",
// github庫地址,如果配置了這項(xiàng)會給每個文件加上超鏈接
// 如果配置塘慕,請保證index填寫無誤筋夏,且所有文件名不含空格(否則鏈接無法正確表示)
// branch默認(rèn)為master
"repository": {
"index": "https://github.com/bighuang624/Algorithms-notes",
"branch": "master"
},
// 目錄開始的標(biāo)題等級
// 默認(rèn)為2,即該目錄下的文件夾名等級從3開始图呢,隨層級深入遞減
"startLevel": 2,
// 需要忽略的目錄条篷、擴(kuò)展名和文件骗随,都以數(shù)組表示
"ignore": {
"dir": [".git"],
"extname": [".json"],
"file": [
"yuki.config.json",
".gitignore",
"README.md",
".DS_Store"
]
},
// 根據(jù)擴(kuò)展名選擇對展示的文件名做一些處理
// 每個擴(kuò)展名的配置需要單獨(dú)一個對象
// 目前支持省略擴(kuò)展名"withoutExt": true
// 和加上書名號"withBookmark": true
"format": [
{
"extname": ".md",
"withoutExt": true,
"withBookmark": true
}
],
// 在大標(biāo)題之后,目錄之前添加的內(nèi)容
// 每個對象可選擇包含標(biāo)題赴叹、標(biāo)題等級和內(nèi)容
// 其中蚊锹,標(biāo)題和標(biāo)題等級需在一個對象中一同填寫
"prefix": [
{
"content": "[![](https:\//img.shields.io\/badge/%E4%BD%9C%E8%80%85-KyonHuang-7AD6FD.svg)](http:\//kyonhuang.top)"
}, {
"title": "目錄",
"level": "2"
}
],
// 在README.md末尾添加的內(nèi)容
// 和prefix相同,每個對象可選擇包含標(biāo)題稚瘾、標(biāo)題等級和內(nèi)容
"append": [
{
"title": "維護(hù)",
"level": "2",
"content": "本文檔由 [yuki](https://github.com/bighuang624/yuki) 維護(hù)"
}
]
}
因?yàn)?JSON 標(biāo)準(zhǔn)中不含注釋,請?jiān)谑褂脮r將注釋去掉姚炕。項(xiàng)目中也提供一份不帶注釋摊欠、可供修改使用的 yuki.config.json 模版。
不需要的配置選項(xiàng)請全部刪除柱宦。
創(chuàng)建 README.md
yuki
LICENSE
開發(fā)中的那些事
Cli 命令工具開發(fā)的準(zhǔn)備工作
我們來了解一下圍繞 NPM 開發(fā)的準(zhǔn)備工作些椒。第一步自然是在文件夾下使用命令npm init
生成 package.json 文件。
注冊
可以通過以下命令在 NPM 資源庫中注冊用戶:
npm adduser
之后跟著要求填寫 Username掸刊、Password免糕、Email 就 ok 了。項(xiàng)目發(fā)布前可能需要npm login
一下忧侧。
版本號
NPM 使用語義版本號來管理代碼石窑。語義版本號分為 X.Y.Z 三位,分別代表主版本號蚓炬、次版本號和補(bǔ)丁版本號松逊。當(dāng)代碼變更時,版本號按以下原則更新:
- 如果只是修復(fù) bug肯夏,需要更新 Z 位经宏。
- 如果是新增了功能,但是向下兼容驯击,需要更新 Y 位烁兰。
- 如果有大變動,向下不兼容徊都,需要更新 X 位沪斟。
當(dāng)然我這個小項(xiàng)目比較隨便,bug 修的多了次版本號看心情也往上升一次暇矫。
你可以用npm view <pkg> version
來查看你發(fā)布到 NPM 項(xiàng)目的現(xiàn)在版本號币喧。
測試小竅門
這兩個小竅門可以節(jié)省你在一邊開發(fā)一邊測試的時間(沒發(fā)現(xiàn)之前,3 天的開發(fā)時間花在這上面的不少...)袱耽。
在 package.json 所在目錄下使用
npm install . -g
可先在本地安裝當(dāng)前命令行程序杀餐,可用于發(fā)布前的本地測試。使用
npm update <pkg> -g
可以把全局安裝的對應(yīng)命令行程序更新至最新版朱巨。
編寫
想要在全局使用你編寫的 cli 工具史翘,你需要在 package.json 加一個 bin 屬性:
"bin": {
"yuki": "./index.js"
},
yuki 換做你啟動這個程序所要在命令行輸入的命令。屬性的值是項(xiàng)目的入口文件。添加這個屬性后琼讽,在命令行執(zhí)行yuki
就等同于執(zhí)行node ./index.js
必峰。
發(fā)布項(xiàng)目
項(xiàng)目寫了一個版本準(zhǔn)備發(fā)布,先在 package.json 所在目錄下用npm version
看一下版本號钻蹬,然后就可以 publish 了吼蚁。
cd yuki
npm version
npm publish
之后就可以通過全局安裝來使用:
npm i -g yuki
獲得程序運(yùn)行的路徑
說實(shí)話,一個我很不擅長的東西就是 API问欠,哪怕是那些非常常用的肝匆。這次我一開始就遇到了麻煩:如何獲得程序開始遍歷的“根目錄”路徑?
在查找的同時順便了解了一下獲得各種路徑的方法顺献,有以下幾種:
process.cwd()
獲得 Node.js 進(jìn)程當(dāng)前工作的路徑(即執(zhí)行命令行時候的路徑旗国,而非代碼路徑。例如在根目錄下執(zhí)行node ./xxx/xxx/example.js
注整,則process.cwd()
返回的是根目錄地址)能曾;__dirname
: 獲得代碼存放的位置(例如運(yùn)行位于/usr/a
目錄下的example.js
文件:node example.js
,則__dirname
返回/usr/a
)肿轨;process.execPath
: 返回返回啟動 Node.js 進(jìn)程的可執(zhí)行文件所在的絕對路徑(也就是當(dāng)前執(zhí)行的 Node 自身的路徑寿冕,例如:/usr/local/bin/node
)。
根據(jù)查詢結(jié)果和實(shí)際需求椒袍,應(yīng)該使用process.cwd()
(我們要求在 package.json 所在目錄下使用 yuki)蚂斤。不過實(shí)際上使用的是path.resolve()
。path.resolve()
不含參數(shù)時槐沼,返回返回當(dāng)前工作目錄的絕對路徑曙蒸,也符合要求。
yuki 的編寫也幫助我熟悉了 Node 里的很多 API岗钩,尤其是和 path 和 fs 相關(guān)的纽窟。
先遍歷文件再深度遍歷文件夾
開發(fā)的過程中發(fā)現(xiàn)一個問題:遍歷文件夾 a 下的所有文件時,經(jīng)常先深度遍歷了其中的文件夾兼吓,導(dǎo)致文件排在這些文件夾深度遍歷的結(jié)果之后臂港,在生成的 README 中無法看出其準(zhǔn)確位置。
解決方法還比較簡單视搏,就是在每一次遞歸的遍歷方法中都建立一個隊(duì)列审孽,遍歷到文件夾先推入隊(duì)列,遍歷到文件則展示浑娜。所有文件遍歷結(jié)束后佑力,將隊(duì)列中的文件夾依次取出并遍歷。這樣既滿足了要求筋遭,也沒有對深度優(yōu)先遍歷造成影響打颤。
更好的是暴拄,JS 的數(shù)組原生支持了push
方法,使得我不用再寫一個隊(duì)列的實(shí)現(xiàn)编饺。
結(jié)語
盡管只是一個微不足道的小工具乖篷,我還是很開心能夠根據(jù)自己的實(shí)際需求開發(fā)了 yuki,更開心有機(jī)會開發(fā)一個能在名字中夾私貨的項(xiàng)目(早在看到 vue 的版本名時我就一直心心念念了)透且。
如果你覺得這個小工具還不錯撕蔼,或者使用時覺得很方便、減輕了重復(fù)的工作負(fù)擔(dān)秽誊,那么不妨為 yuki 點(diǎn)一個 star鲸沮,因?yàn)槲毅裤街茉诋厴I(yè)前擁有一個自己的 100+ star 項(xiàng)目。
當(dāng)然养距,我更希望這些 star 是憑借我自己的開發(fā)創(chuàng)意和技術(shù)所得到的認(rèn)可的。而我的開發(fā)經(jīng)驗(yàn)確實(shí)不太足日熬,所以如果你覺得這個工具不太好使棍厌、代碼糟糕、發(fā)現(xiàn)了 bug竖席,或是有可以增加的功能耘纱,也歡迎你開 issue 或者提交 PR 來告知我。