nodejs路径相关
获取路径分隔符
js
import { sep } from 'path'
console.log(sep)
join 方法
path.join() 方法使用特定于平台的分隔符作为定界符将所有给定的 path 片段连接在一起,然后规范化生成的路径。
零长度的 path 片段被忽略。 如果连接的路径字符串是零长度字符串,则将返回 ‘.’,表示当前工作目录
js
import { join } from 'path'
join('/foo', 'bar', 'baz/asdf', 'quux', '..')
// 返回: '/foo/bar/baz/asdf'
join('foo', {}, 'bar')
// 抛出 'TypeError: Path must be a string. Received {}'
如果任何路径片段不是字符串,则抛出 TypeError
获取当前路径的上级目录
js
import { join } from 'path'
const parentFullPath = join(__dirname, '../')
__dirname 和 ./ 的区别
__dirname总是指向被执行 js 文件的绝对路径
当在/react-admin-server/routers/file-upload.js 文件中写了 __dirname, 它的值就是/react-admin-server/routers
相反./会返回你执行 node 命令的路径,例如你的工作路径
假设有如下目录结构
/react-admin-server
/routers
file-upload.js
js
// file-upload.js
var path = require('path')
console.log(path.resolve('.'))
console.log(path.resolve(__dirname))
然后在file-upload.js 中,有如下代码,然后在终端执行了下面命令
cd /react-admin-server/routers
node file-upload.js
. 是你的当前工作目录,在这个例子中就是/react-admin-server/routers ,__dirname 是 file-upload.js 的文件路径,在这个例子中就是 /react-admin-server/routers
然而,如果我们的工作目录是/react-admin-server
cd /react-admin-server
node routers/file-upload.js
将会得到
/react-admin-server
/react-admin-server/routers
此时,.指向我们的工作目录,即/react-admin-server,__dirname 还是指向 /react-admin-server/routers 。
js
//__dirname表示当前文件所在的根路径,也就是/routers,然后..表示向上退一级,也就是到了项目根目录,然后public/upload表示到了这个目录
const dirPath = path.join(__dirname, '..', 'public/upload')
ES Modules 下使用__filename 和__dirname
在 ESM 中没有了
__filename和__direname这两个变量, 如果程序中用到了__filename和__direname,则会遇到这样的错误ReferenceError: __dirname is not defined in ES module scope 和 ReferenceError: __filename is not defined in ES module scope
解决方法
js
// import.meta.url 返回模块的绝对的 `file:` URL。
// url模块中fileURLToPath()函数,返回完全解析的特定于平台的 Node.js 文件路径
// path模块中dirname()函数,返回路径的目录路径
import { fileURLToPath } from 'url'
import { dirname } from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
ES Modules 下无法使用import packageConfig from "../package.json"形式导入 json
会出现这样的错误 TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "file:///.../package.json" needs an import assertion of type "json"
解决方法
通过Object.defineProperty给global添加loadJSON、getFileName和getDirName三个函数,扩展esm模式下的 global 属性。代码如下
js
// expandGlobal.js
import url from 'node:url'
import path from 'node:path'
import { createRequire } from 'node:module'
Object.defineProperty(global, 'loadJSON', {
get() {
return (filepath, importMetaUrl) => {
const reg = /\S+.json$/g
if (reg.test(filepath)) {
const require = createRequire(importMetaUrl)
return require(filepath)
} else {
throw new Error('loadJSON 的参数必须是一个json文件')
}
}
},
enumerable: true,
configurable: false,
// writable: false,
})
Object.defineProperty(global, 'getFileName', {
get() {
return importMetaUrl => {
return url.fileURLToPath(importMetaUrl)
}
},
enumerable: true,
configurable: false,
// writable: false,
})
Object.defineProperty(global, 'getDirName', {
get() {
return importMetaUrl => {
return path.dirname(url.fileURLToPath(importMetaUrl))
}
},
enumerable: true,
configurable: false,
// writable: false,
})
使用
js
import './expandGlobal.js'
console.log(global.getFileName(import.meta.url))
console.log(global.getDirName(import.meta.url))
console.log(global.loadJSON('../package.json', import.meta.url))
参考资料
nodejs 你不知道的__dirname 和__filename