Skip to content
文章目录

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__dirnamefile-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.definePropertyglobal添加loadJSONgetFileNamegetDirName三个函数,扩展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

在 ES 模块构建的 Nodejs 中如何使用 __dirname__filename

Node.js 中路径模块的 join 方法以及__dirname 和./的区别