👆 點擊上方卡片關注html
在平常使用 Node 進行開發的時候,會使用到一些文件系統、路徑操做等基礎 API,這裏整理一下,方便你們理解和直接使用。
前端
這裏只介紹最經常使用的那些,不是全部哈,想要看更全的,直接看官方文檔[1]就 OK。vue
儘可能不廢話,多上代碼。node
Process 模塊
先介紹 process 模塊,它提供了當前 Node 進程相關的全局環境信息。在後面的 API 中被用到。linux
// 內置模塊,直接使用
const process = require('process');
process.cwd()
這是一個函數,返回當前 Node 進程執行的目錄,舉例一個常見的場景:webpack
一個 Node 模塊 A
經過 NPM 發佈,項目 B
中使用了模塊 A
。在 A
中須要操做 B
項目下的文件時,就能夠用 process.cwd()
來獲取 B
項目的路徑。web
const cwd = process.cwd(); // 輸出:/Users/xiaolian/Code/node-api-test
process.argv
在終端經過 Node 執行命令的時候,經過 process.argv
能夠獲取傳入的命令行參數,返回值是一個數組:面試
-
0: Node 路徑(通常用不到,直接忽略) -
1: 被執行的 JS 文件路徑(通常用不到,直接忽略) -
2~n: 真實傳入命令的參數**
因此,咱們只要從 process.argv[2]
開始獲取就行了。通常都是這樣用:vue-cli
const args = process.argv.slice(2);
直接獲取咱們想要的參數。json
process.env
返回一個對象,存儲當前環境相關的全部信息,通常不多直接用到。
通常咱們會在 process.env
上掛載一些變量標識當前的環境。好比最多見的用 process.env.NODE_ENV
區分 development
和 production
。在 vue-cli
的源碼中也常常會看到 process.env.VUE_CLI_DEBUG
標識當前是否是一 DEBUG
模式。
這裏提一個 webpack 的插件 DefinePlugin[2],在平常的構建流程中,咱們常常會經過這個插件來注入不一樣的全局變量,從而執行不一樣的構建流程,而且代碼中的 process.env.xxx
會被替換成具體的值,在 Terser 壓縮階段會將 deadCode 移除,優化代碼體積。
process.platform
這個用的很少,返回當前系統信息,枚舉值以下:
console.log(process.platform);
// 'aix'
// 'darwin' - macOS
// 'freebsd'
// 'linux' - linux
// 'openbsd'
// 'sunos'
// 'win32' - windows
Path 模塊
// 內置模塊,直接使用
const path = require('path');
Node 中幾乎路徑相關的操做都會使用這個模塊。
這裏就說 5 個最經常使用的:
path.join(...paths)
path.join
做用是將傳入的多個路徑拼成一個完整的路徑。
const dPath = path.join('template', 'aaa', 'bbb', 'ccc', 'd.js');
// 輸出: template/aaa/bbb/ccc/d.js
來看一個很是常見的場景,咱們須要獲取當前項目的 package.json 文件,就能夠這樣獲取它的路徑:
const pkgPath = path.join(process.cwd(), './package.json');
// 輸出: /Users/xiaolian/Code/node-api-test/package.json
path.join
能夠傳入任意個路徑,好比:
['package.json', 'README.md'].forEach(fileName => {
const templateFilePath = path.join(process.cwd(), 'template', fileName);
console.log(templateFilePath);
});
// 輸出: /Users/xiaolian/Code/node-api-test/template/package.json
// 輸出: /Users/xiaolian/Code/node-api-test/template/README.md
path.resolve(...paths)
path.resovle
和 path.join
的區別在於它的做用是將傳入的多個路徑和當前執行路徑拼接成一個完整的絕對路徑。
假設我如今 index.js
在 scripts
目錄下,而後我在根目錄下執行 node scripts/index.js
,它的代碼以下:
const dPath = path.resolve('aaa', 'bbb', 'ccc', 'd.js');
// 輸出: /Users/xiaolian/Code/node-api-test/aaa/bbb/ccc/d.js
通常狀況下,當 path.resolve
的第一個參數爲 ./
時,能夠直接理解和 path.join(processs.cwd(), '')
表現一致。
path.basename(path[, ext])
path.basename
返回指定 path
最後一個路徑名,其中第二個參數 ext
可選,表示文件擴展名。好比:
console.log(path.basename('scripts/index.js')); // index.js
console.log(path.basename('scripts/index.js', '.js')); // 匹配到 .js,返回 index
console.log(path.basename('scripts/index.js', '.json')); // 沒匹配到,返回 index.js
path.dirname(path)
和 path.basename
對應,返回指定 path
最後一個路徑名以前的路徑。好比:
console.log(path.basename('scripts/index.js')); // scripts
console.log(path.basename('scripts/hook/index.js')); // scripts/hook
path.extname(path)
和 path.basename
對應,返回指定 path
最後一個路徑名的文件擴展名(含小數點 .
)。好比:
console.log(path.basename('scripts/index.js')); // .js
console.log(path.basename('README.md')); // .md
對比
最後再來對比一下各個路徑相關的 API 的區別。
項目 A
的目錄結構以下:
├── scripts
│ └── index.js
├── src
│ └── index.js
├── package.json
├── README.md
scripts/index.js
的代碼以下:
const path = require('path');
console.log(path.join('package.json'));
console.log(path.resolve('package.json'));
console.log(path.join('src', 'index.js'));
console.log(path.resolve('src', 'index.js'));
console.log(path.join(process.cwd(), 'package.json'));
console.log(path.resolve('./', 'package.json'));
console.log(__filename);
console.log(__dirname);
而後,咱們在項目 A
的根目錄下執行 node scripts/index.js
,結果以下:
-> node scripts/index.js
package.json
/Users/xiaolian/Code/A/package.json
src/index.js
/Users/xiaolian/Code/A/src/index.js
/Users/xiaolian/Code/A/package.json
/Users/xiaolian/Code/A/package.json
/Users/xiaolian/Code/A/scripts/index.js
/Users/xiaolian/Code/A/scripts
品,仔細品,它們有什麼區別。
我的而言,通常仍是習慣用 path.join(process.cwd(), 'xxx')
。
File System 模塊
// 內置模塊,直接使用
const fs = require('fs');
文件系統相關操做的模塊,除了 fs
以外,咱們還常常用到 fs-extra
,後面會介紹。
這個模塊在平時的 Node 開發中會被大量使用,這裏簡單列幾個,其它的仍是看文檔哈:https://nodejs.org/dist/latest-v14.x/docs/api/fs.html[3]
fs
模塊的 API 默認都是異步回調的形式,若是你想使用同步的方法,有兩種解決方法:
-
使用 Node 提供的同步 API: xxxSync
,也就是在 API 的後面加一個Sync
後綴,它就是一個同步方法了(具體仍是須要查文檔哈,是否有提供同步 API) -
包裝成一個 Promise 使用
fs.stat(path[, options], callback)
fs.stat()
返回一個文件或者目錄的信息。
const fs = require('fs');
fs.stat('a.js', function(err, stats) {
console.log(stats);
});
其中包含的參數有不少,介紹幾個比較經常使用的:
export interface StatsBase<T> {
isFile(): boolean; // 判斷是不是一個文件
isDirectory(): boolean; // 判斷是否一個目錄
size: T; // 大小(字節數)
atime: Date; // 訪問時間
mtime: Date; // 上次文件內容修改時間
ctime: Date; // 上次文件狀態改變時間
birthtime: Date; // 建立時間
}
通常咱們會使用 fs.stat
來取文件的大小,作一些判斷邏輯,好比發佈的時候能夠檢測文件大小是否符合規範。在 CLI 中,常常須要獲取一個路徑下的全部文件,這時候也須要使用 fs.stat
來判斷是目錄仍是文件,若是是目錄則繼續遞歸。固然,如今也有更方便的 API 能夠完成這個工做。
同步方法
const fs = require('fs');
try {
const stats = fs.statSync('a.js');
} catch(e) {}
fs.readdir(path[, options], callback)
fs.readdir(path)
獲取 path
目錄下的文件和目錄,返回值爲一個包含 file
和 directory
的數組。
假設當前目錄爲:
.
├── a
│ ├── a.js
│ └── b
│ └── b.js
├── index.js
└── package.json
執行如下代碼:
const fs = require('fs');
fs.readdir(process.cwd(), function (error, files) {
if (!error) {
console.log(files);
}
});
返回值爲:
[ 'a',
'index.js',
'package.json' ]
能夠看到這裏只返回了根目錄下的文件和目錄,並無去深度遍歷。因此若是須要獲取全部文件名,就須要本身實現遞歸。
同步方法
const fs = require('fs');
try {
const dirs = fs.readdirSync(process.cwd());
} catch(e) {}
fs.readFile(path[, options], callback)
文件讀取的 API,經過 fs.readFile
能夠獲取指定 path
的文件內容。
入參以下:
-
第一個參數: 文件路徑 -
第二個參數: 配置對象,包括 encoding
和flag
,也能夠直接傳如encoding
字符串 -
第三個參數: 回調函數
使用方法以下:
const fs = require('fs');
const path = require('path');
fs.readFile(path.join(process.cwd(), 'package.json'), 'utf-8', function (
error,
content
) {
if (!error) {
console.log(content);
}
});
若是沒傳 encoding
,則其默認值爲 null
,此時返回的文件內容爲 Buffer
格式。
同步方法
const fs = require('fs');
try {
fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8');
} catch(e) {}
fs.writeFile(file, data[, options], callback)
對應着讀文件 readFile
,fs
也提供了寫文件的 API writeFile
,接收四個參數:
-
第一個參數: 待寫入的文件路徑 -
第二個參數: 待寫入的文件內容 -
第三個參數: 配置對象,包括 encoding
和flag
,也能夠直接傳如encoding
字符串 -
第三個參數: 回調函數
使用方法以下:
const fs = require('fs');
const path = require('path');
fs.writeFile(
path.join(process.cwd(), 'result.js'),
'console.log("Hello World")',
function (error, content) {
console.log(error);
}
);
同步方法
const fs = require('fs');
const path = require('path');
try {
fs.writeFileSync(
path.join(process.cwd(), 'result.js'),
'console.log("Hello World")',
'utf-8'
);
} catch (e) {}
本文主要是總結了一下在開發 Node 時經常使用的一些 API,後續的文章會帶來 Node 經常使用的一些三方包。
參考資料
官方文檔: https://nodejs.org/dist/latest-v14.x/docs/api/
[2]DefinePlugin: https://webpack.js.org/plugins/define-plugin
[3]https://nodejs.org/dist/latest-v14.x/docs/api/fs.html: https://nodejs.org/dist/latest-v14.x/docs/api/fs.html
交流討論
歡迎關注公衆號「前端試煉」,公衆號平時會分享一些實用或者有意思的東西,發現代碼之美。專一深度和最佳實踐,但願打造一個高質量的公衆號。
❤️
公衆號後臺回覆【小煉】
邀請你加入純淨技術交流羣(上班划水摸魚羣)
🙏
若是以爲這篇文章還不錯
來個【分享、點贊、在看】三連吧
讓更多的人也看到
本文分享自微信公衆號 - 前端試煉(code-photo)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。