這篇文章帶大家了解一下工作中可以怎麼使用node,怎麼利用它來提升工作效率,希望對大家有幫助!
在工作項目中需要依賴外部文件,此文件由其他團隊維護,使用jenkins 構建,建構產物推送至[Amazon S3](aws.amazon .com/pm/serv-s3/…),我們需要從S3 手動下載檔案然後複製到工程中,整個過程可以考慮自動化完成。
另外還遇到了一個嚴重的問題:我們需要的構建產物在S3 中的路徑類似'a/b//c/',多餘的一個/ 實際上是一個名為'/' 的資料夾,此資料夾使用windows 的S3 Browser 可以正常識別,在mac 下大概是因為'/' 被看作文件分隔符,因此嘗試幾個GUI 工具均無法正常識別目錄,因此mac 開發者還需要在虛擬機器中使用windows 下載產物,這個過程是極其浪費且無意義的。 【推薦學習:《nodejs 教學》】
由於 Amazon 提供了 API 存取的方式,因此想到可以實作腳本來完成下載更新的工作。
未使用腳本:
#使用腳本:
jenkins → 產物名稱→ 執行腳本
這樣直接就可以完成了,可以省去手動流程,還不會出現'/' 的bug 問題。
這裡使用Amazon 提供的aws-sdk,使用S3 client,傳入accessKeyId 和secretAccessKey 就可以連接了:
import S3 from "aws-sdk/clients/s3"; const s3 = new S3({ credentials: { accessKeyId, secretAccessKey } });
aws-sdk 中提供了bucket 和檔案的增刪改查接口,這裡我們可以提前拿到jenkins 建構出的產物檔案名,這裡需要根據檔案名稱和位置下載檔案:
const rs = s3 .getObject({ Bucket: "your bucket name", Key: "file dir + path" }) .createReadStream();
Bucket 即儲存檔案的Bucket 位置,Key 是檔案在S3 中的路徑訊息,整個路徑相當於是目錄名稱檔案名稱。
這裡我們可以取得到一個ReadStream,之後使用node.js 可直接寫入本地:
const ws = fs.createWriteStream(path.join(__dirname, outputfilename)); rs.pipe(ws);
解壓縮使用node-tar 工具,直接安裝即可:
npm install tar
extract 別名x,這裡直接使用tar.x 方法,此方法可以直接處理ReadStream,將原始資料解壓縮後寫入檔案中,因此我們這裡直接把ReadStream 傳入tar.x 即可,不需要儲存原始的.tar 檔案:
- const ws = fs.createWriteStream(path.join(__dirname, outputfilename)); - rs.pipe(ws); + rs.pipe(tar.x({ C: path.join(__dirname, outputfilename) }));
這裡的pipe 操作會傳回stream 對象,我們可以監聽finish 方法來處理後續流程:
const s = rs.pipe(tar.x({ C: path.join(__dirname, outputfilename) })); s.on('finish', () => { // do something ... })
原始檔案有子資料夾,我們需要都移到最外層,因此需要做一個平鋪資料夾的操作。
這裡使用fs 相關API 進行讀取,fs API 分為同步和非同步兩種,同步API 函數名稱以Sync 結尾,非同步函數預設為callback error first 風格,在fs/promises 下提供了對應的promise 風格非同步API,這裡依需求使用即可。
由於我們的目錄只有一層,因此只做一層flatten,如果有多層可以使用遞歸來實現:
async function flatten(dir) { const fileAndDirs = await fsp.readdir(dir); const dirs = fileAndDirs.filter((i) => fs.lstatSync(path.join(dir, i)).isDirectory() ); for (const innerDir of dirs) { const innerFile = await fsp.readdir(path.join(dir, innerDir)); await Promise.all([ innerFile .filter((item) => fs.lstatSync(path.join(dir, innerDir, item)).isFile()) .map((item) => fsp.rename(path.join(dir, innerDir, item), path.join(dir, item)) ), ]); remove(path.join(dir, innerDir)); } }
#之後複製到我們的工程目錄即可,複製只需要呼叫copyFile API,對於不需要的檔案這裡使用正規表示式設定exclude 黑名單:
async function copy(from, to) { const files = await fsp.readdir(from); await Promise.all( files .filter((item) => !exclude.test(item)) .map((item) => fsp.copyFile(path.join(from, item), path.join(to, item))) ); }
在實際使用時,配置檔案要和程式碼分離,這裡的accessKeyId 和secretAccessKey 應該由每個用戶自己配置,因此放在單獨的配置檔案中,此檔案由用戶本地創建,在主程式中讀取相關配置內容:
// config.js module.exports = { s3: { accessKeyId: 'accessKeyId', secretAccessKey: 'secretAccessKey', } }; // main.js if (!fs.existsSync('config.js')) { console.error('please create a config file'); return; } const config = require(path.resolve(__dirname, 'config.js'));
每次下載的檔案名稱需要在呼叫時傳入,寫在檔案中會頻繁修改,這裡直接作為參數傳遞。
node.js 中可以透過process.argv 來讀取,argv 是一個數組,這個數組第一個元素是node 所在的安裝路徑,第二個元素是目前執行的腳本所在路徑,從第三個元素開始是自訂參數,因此需要從process.argv[2] 開始。如果有複雜的命令列參數需求可以使用命令列參數解析函式庫如 commander,由於本例只需要一個參數,這裡直接讀取即可:
const filename = process.argv[2]; if (!filename) { console.error('please run script with params'); return; }
至此,一个可用的命令行工具就完成了。
node.js 可以开发后端,但是 node.js 意义最大的地方绝不是使用 JS 开发后端。对前端开发者而言,node.js 真正的价值在于它是一个非常实用的工具,前端工具 Webpack、rollup、dev-server 等都是 node 创造的价值,由于 NPM 丰富的生态,使用 node 可以快速完成脚本的开发,处理开发中遇到的一些工具链与效率的问题很有效,在工作中遇到问题时可以考虑尝试。
更多编程相关知识,请访问:编程入门!!
以上是淺談怎麼利用node提升工作效率的詳細內容。更多資訊請關注PHP中文網其他相關文章!