從零開發一個健壯的npm包

御風天流發表於2019-02-16

最近寫 node 的時候遇到一個需求,需要清理某目錄下超過3天圖片,本來想在 npm 找個包直接用用,結果沒找到合適的,於是就自己擼一個了。

本文主要講述如何從零開始開發一個完善健壯的 npm 包,主要涉及到一些工具的使用配置,包的功能不是重點。

一、配置eslint

ESLint是一個程式碼風格檢測工具,比如使用空格還是tab,要不要加分號,使用駝峰命名還是下劃線等等。可以保證一個團隊的程式碼風格保持一致。

npm install eslint -geslint init複製程式碼

根據 eslint 提供的選項結合自己的需求,一路選擇好後,會在根目錄建立一個 .eslintrc.json 檔案,裡面一系列的規則配置,這個時候你再寫程式碼,如果不符合規範,編輯器就會報錯提示,如果某些目錄不想使用校驗,可以建立一個 .eslintignore,把不需要校驗的目錄放進入。為了方便執行校驗,我們在 package.json 裡配置一下 scripts:

"scripts": { 
"lint": "eslint --fix src"
}複製程式碼

可以配合githook強制每次提交的時候校驗程式碼:使用git鉤子做eslint校驗

二、編寫程式碼

我們在src目錄下編寫我們的程式碼,拆分成具體步驟為

  1. 讀取目錄下所有檔案
  2. 篩選出我們需要處理的檔案,比如建立或者修改時間超過3天的圖片或者日誌
  3. 刪除這些檔案

我們分成3個函式:

// readAllFileInfo.js// 使用fs.readdir讀取目錄下所有檔案fs.readdir(filePath, function(err, files) { 
if (err) {
reject(err);

} else {
Promise.all(files.map(file =>
{
return filterFile(file, options);

})) .then(deleteFiles =>
{
resolve(deleteFiles.filter(deleteFile =>
deleteFile));

});

}
});
// filterFile.js// 使用fs.stat讀取檔案資訊,然後篩選出需要刪除的檔案fs.stat(fileName, (err, stats) =>
{
if (err) {
reject(err);

} else {
const time = stats[expiredType];
const distanceTime = formatDate(date);
const extName = path.extname(fileName);
if (now - time >
distanceTime &
&
extName === `.${ext
}
`
) {
deleteFile(fileName) .then((res) =>
{
resolve(res);

});

} else {
resolve();

}
}
});
// deleteFile.js// 使用fs.unlink刪除檔案fs.unlink(fileName, err =>
{
if (err) {
reject(err);

} else {
resolve(fileName);

}
});
複製程式碼

這裡主要講一下解決問題的思路,首先整理一下解決這個問題需要哪些步驟,然後每一個步驟可以抽象成一個函式,想一下函式的傳參和返回值,最後可以設計一下更加相容易擴充套件的 API,具體程式碼可以檢視倉庫:https://github.com/wulv/del-expired-file。

三、使用babel

在低版本的 node 可能還不支援某些 es6 語法,比如物件解構等,所以需要使用 babel 編譯成低版本也能識別的語法。我們把 src 目錄裡的程式碼編譯到 lib 目錄,然後我們在 package.json 裡,把 "main" 改為 "lib/index.js",這樣對外暴露出去的程式碼就不會出現相容性問題。

下載 babel-cli 依賴:

npm install --save-dev babel-cli// 下載預設,預設就是別人配置好的一系列規則,編譯在規則內的語法npm install --save-dev babel-preset-es2015複製程式碼

配置好 .babelrc:

{ 
"presets": ["es2015"]
}複製程式碼

package.json 裡配置一下 scripts:

"scripts": { 
"build": "babel src -d lib", "build:watch": "npm run build -- --watch"
}複製程式碼

這樣執行 npm run build 就會編譯原始檔到 lib 目錄了。

四、編寫測試

為了保障程式的穩定性,我們一定要寫測試用例,特別是當你的程式依賴越來越多的時候,比如你改了A模組,你覺得你的改動都沒問題,但一發布出去就會出現意想不到的 bug 因為影響到了你不知道的某個模組。這個時候測試就尤為重要,可以幫你避免很多低階錯誤。我們使用 mochachai 做測試框架和斷言,下載依賴。

npm install mocha chai --save-dev複製程式碼

我們在專案根目錄建立一個 test 目錄。建立 index.formatDate.js,內容為:

'use strict';
const chai = require('chai');
const formatDate = require('../lib/formatDate');
const expect = chai.expect;
const S = 1000;
describe('format dete', () =>
{
it('test 2s', function() {
expect(formatDate('2s')).to.be.equal(2 * S);

});

});
複製程式碼

這裡只是演示一下基本的語法,程式碼太多,具體看倉庫。然後在 package.json 裡再新增一個 scripts:

"test": "npm run build &
&
mocha -t 5000"
複製程式碼

五、Travis-CI+Coveralls

Travis-CI 是一個持續整合構建專案,結合github 可以實現很強大的功能,比如你給一個倉庫提交 PR 後,可以自動幫你跑完測試用例,如果測試沒有通過,就不能 mergemasterCoveralls 是一個自動化測試覆蓋率的服務,用於收集測試覆蓋率報告,對於開源專案免費,配置好這個後,就可以生成一個顯示你程式碼測試覆蓋率的 badgeCoveralls 可以使用 GitHub 賬號登入,登入之後可以在 https://coveralls.io/repos/new 新增需要收集報告的 repo

首先安裝一下 istanbul 這個工具來檢測程式碼的測試覆蓋率:

npm install istanbul --save-dev複製程式碼

然後在 package.json 中的 scripts 裡新增:

"cover": "istanbul cover node_modules/mocha/bin/_mocha"複製程式碼

執行 npm run cover 就可以看到你的程式碼測試覆蓋率了

========= Coverage summary =========Statements   : 92.65% ( 63/68 )Branches     : 75% ( 15/20 )Functions    : 100% ( 14/14 )Lines        : 92.65% ( 63/68 )====================================複製程式碼

將測試覆蓋率報告提交給 Coveralls,首先安裝 coveralls:

npm install coveralls --save-dev複製程式碼

然後在 package.json 中的 scripts 裡新增

 "coveralls": "npm run cover -- --report lcovonly &
&
cat ./coverage/lcov.info | coveralls"
複製程式碼

然後建立 .travis.yml 檔案,

sudo: falselanguage: node_jsos:  - linux  - osxnode_js:  - 6  - 8  - 9  - 10branches:  only:  - masterinstall:- npm installscript:  - npm run lint  - npm run build  - npm run coverafter_success:- npm run coveralls複製程式碼

將程式碼推到 github 後,開啟 https://travis-ci.org/ ,點開右上角頭像 ->
profile,把自己倉庫的開關開啟:

從零開發一個健壯的npm包

README.md 裡新增程式碼測試覆蓋率的 badge,我們可以使用 http://shields.io 來新增 badge,比如還有下載量,star數等這些badge

[![Build Status](https://travis-ci.org/wulv/del-expired-file.png)](https://travis-ci.org/wulv/del-expired-file)[![Coverage Status](https://img.shields.io/coveralls/wulv/del-expired-file/master.svg?style=flat)](https://coveralls.io/github/wulv/del-expired-file?branch=master)複製程式碼

最終可以看到以下效果,當你看到一個 npm 如果顯示了測試覆蓋率,是不是頓時放心很多了呢?

從零開發一個健壯的npm包

六、釋出

至此我們基本已經寫好了一個相對比較健壯的倉庫了,現在釋出到 npm 上,如果沒有 npm 賬號的話,需要先註冊一下,然後執行

npm adduser複製程式碼

輸入使用者名稱和密碼,npm publish,這樣你的倉庫就釋出好了,如果要更新版本,要遵循 Semver(語義化版本號) 規範:

  1. 升級補丁版本號:npm version patch
  2. 升級小版本號:npm version minor
  3. 升級大版本號:npm version major

總結

總結一下上面使用到的工具和技術:

從零開發一個健壯的npm包

我們可以看到,如果只是實現功能,把目標定在僅僅實現需求上,寫這個 npm 包,用一個檔案三個函式就完成了,但是這樣的話,這個包估計也就只有你自己用了,以後的維護,修改都會比較麻煩,而使用這一套工具後,就健壯很多了。工作上也是這樣,我們需要追求卓越,不斷打磨自己的手藝,做出更完美的作品。

打個廣告,杭州有贊誠招前端開發工程師,我們在4月舉辦了一次前端技術開放日,詳情檢視連結:https://tech.youzan.com/fe-open-day-2018/。公司福利多多:

  • 標配:MacBook,報銷:螢幕、滑鼠、機械鍵盤
  • 五險一金、980元/月的餐補、加班叫車費報銷、年度outing和體檢、每人每年有機會參加外部大會/培訓等
  • 各種高大上的聚餐、千奇百怪的團建,長期投食的零食架…
  • 高配電視、遊戲機、桌球、乒乓球、檯球、健身器械,還有四驅賽道等,等你來戰~

有意向的話請傳送簡歷到wulv#youzan.com

參考連結

來源:https://juejin.im/post/5af7de01f265da0ba60fe37c#comment

相關文章