👆 点击上方卡片关注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源创计划”,欢迎正在阅读的你也加入,一块儿分享。