前言
vue 项目配置中经常能见到的 path.resolve() 、path.join()、__dirname,他们到底是个啥?官方的表述是:
__dirname
表示当前模块的目录名(即运行的js文件所在的目录)。
在 Node.js 模块系统中,每个文件都被视为一个独立的模块
path.resolve()
将路径或路径片段的序列解析为绝对路径。
path.join()
将所有给定的 path 片段连接到一起(使用平台特定的分隔符作为定界符),然后规范化生成的路径
嗯,有点抽象。为了更好的弄明白这些,我跑了以下代码 ——
前提条件
以下代码都是基于下面这个目录结构和执行路径的。请注意执行路径! 这是为了区分js文件的所在路径和执行路径,二者的区分有助于更好的理解 resolve 方法。
目录结构:
myTest
├─ test1
│ └─ test.js
└─ test2
执行路径:E:\myTest\test2
Part1 这几个是啥? 直接输出看看
const path = require('path');
console.log("__dirname ==> ", __dirname) //返回运行的js文件所在的目录 ==> E:\myTest\test1
console.log("resolve ==> ", path.resolve('')) //返回运行时的路径 ==> E:\myTest\test2
console.log("join ==> ", path.join('')) //返回.表示当前目录 ==> .
Part2 接下来再对比一下 resolve 和 join
const path = require('path');
console.log("resolve ==> ", path.resolve('a/b','c','d')) // E:\myTest\test2\a\b\c\d
console.log("join ==> ", path.join('a/b','c','d')) // a\b\c\d
//从二者的结果中可以看到, 路径被规范化了 (不同系统的路径符号不同,可能是 \ 也可能是 /)
Part3 再加点料
基于 Part2 的代码,给路径片段 d
分别加上 /
、./
、 ../
试试

console.log("使用 /")
console.log("resolve ==> ", path.resolve('a/b','c','/d')) // E:\d
console.log("join ==> ", path.join('a/b','c','/d')) // a\b\c\d
console.log("使用 ./")
console.log("resolve ==> ", path.resolve('a/b','c','./d')) // E:\myTest\test2\a\b\c\d
console.log("join ==> ", path.join('a/b','c','./d')) // a\b\c\d
console.log("使用 ../")
console.log("resolve ==> ", path.resolve('a/b','c','../d')) // E:\myTest\test2\a\b\d
console.log("join ==> ", path.join('a/b','c','../d')) // a\b\d
包含以
/
、./
、../
开头的路径片段,分别代表:根目录(/), 当前目录(./), 上级目录(…/)。用法同命令行中使用 cd 啥啥啥
Part4 搭配 __dirname
食用
再基于 Part3 ,加上 __dirname
作为第一个参数(这个有点意思,注意看看与上例的区别)
console.log("使用 /")
console.log("resolve ==> ", path.resolve(__dirname, 'a/b','c','/d')) // E:\d
console.log("join ==> ", path.join(__dirname, 'a/b','c','/d')) // E:\myTest\test1\a\b\c\d
console.log("使用 ./")
console.log("resolve ==> ", path.resolve(__dirname, 'a/b','c','./d')) // E:\myTest\test1\a\b\c\d
console.log("join ==> ", path.join(__dirname, 'a/b','c','./d')) // E:\myTest\test1\a\b\c\d
console.log("使用 ../")
console.log("resolve ==> ", path.resolve(__dirname, 'a/b','c','../d')) // E:\myTest\test1\a\b\d
console.log("join ==> ", path.join(__dirname, 'a/b','c','../d')) // E:\myTest\test1\a\b\d
Part 5 加个带盘符的路径片段试试
同样基于 Part3 ,这次不加 __dirname
, 加个带盘符的路径片段(效果似乎跟加__dirname
一样)
console.log("使用 /")
console.log("resolve ==> ", path.resolve('F:/', 'a/b','c','/d')) // F:\d
console.log("join ==> ", path.join('F:/', 'a/b','c','/d')) // F:\a\b\c\d
console.log("使用 ./")
console.log("resolve ==> ", path.resolve('F:/', 'a/b','c','./d')) // F:\a\b\c\d
console.log("join ==> ", path.join('F:/', 'a/b','c','./d')) // F:\a\b\c\d
console.log("使用 ../")
console.log("resolve ==> ", path.resolve('F:/', 'a/b','c','../d')) // F:\a\b\d
console.log("join ==> ", path.join('F:/', 'a/b','c','../d')) // F:\a\b\d
OK,从以上的运行结果,可以看出点端倪来了:
path.resolve 基于运行时的路径,返回拼接后的绝对路径。但如果路径片段中包含带盘符,则以该盘符为准。
emm… 好像有点毛病,如果同时使用了
__dirname
和带盘符的路径片段呢?或者不是作为首位参数?
我再跑一个试试……
Part6 同时使用__dirname
和带盘符的路径片段 & 不是作为首位参数的情况
console.log("resolve ==> ", path.resolve(__dirname, 'F:/', 'a/b','c')) // F:\a\b\c
console.log("resolve ==> ", path.resolve('F:/', __dirname, 'a/b','c')) // E:\myTest\test1\a\b\c
console.log("resolve ==> ", path.resolve('x/y', 'F:/', __dirname, 'a/b','c')) // E:\myTest\test1\a\b\c
好的,我知道了。换个更准确的表述:
path.resolve
路径片段从右到左依次拼接,直至返回完整的绝对路径。如果传入的路径片段中没有带盘符的,就拿运行时的路径来用啦~
path.join
路径片段从右到左依次拼接,返回拼接好的路径片段
总结
二者的共同点:
- 路径都会被规范化
- 都是从右到左拼接路径片段
二者的不同点:
- resolve 返回绝对路径,join 只把路径片段拼接
/
符号在 resolve 中表示根目录,在 join 中没有这个效果
附上完整的测试代码,可以跑一下看看~
const path = require('path');
// 这几个是啥? 直接输出看看
console.log("----------------------------------")
console.log("__dirname ==> ", __dirname) //返回运行的js文件所在的目录 ==> E:\myTest\test1
console.log("resolve ==> ", path.resolve('')) //返回运行时的路径 ==> E:\myTest\test2
console.log("join ==> ", path.join('')) //返回.表示当前目录 ==> .
console.log("----------------------------------")
// 接下来再对比一下 resolve 和 join
console.log("resolve ==> ", path.resolve('a/b','c','d')) // E:\myTest\test2\a\b\c\d
console.log("join ==> ", path.join('a/b','c','d')) // a\b\c\d
// 从二者的结果中都可以看到, 路径被规范化了 (不同系统的路径符号不同,可能是 \ 也可能是 /)
console.log("----------------------------------")
// 再加点料 ----
// 路径片段以 / ./ ../ 开头,分别代表:根目录(/), 当前目录(./), 上级目录(../)
// 用法同命令行中使用 cd **
console.log("============ 基础使用 ============")
console.log("使用 /:")
console.log("resolve ==> ", path.resolve('a/b','c','/d')) // E:\d
console.log("join ==> ", path.join('a/b','c','/d')) // a\b\c\d
console.log("----------------------------------")
console.log("使用 ./:")
console.log("resolve ==> ", path.resolve('a/b','c','./d')) // E:\myTest\test2\a\b\c\d
console.log("join ==> ", path.join('a/b','c','./d')) // a\b\c\d
console.log("----------------------------------")
console.log("使用 ../:")
console.log("resolve ==> ", path.resolve('a/b','c','../d')) // E:\myTest\test2\a\b\d
console.log("join ==> ", path.join('a/b','c','../d')) // a\b\d
console.log("==================================")
// 加上 __dirname 的使用
console.log("========= 加上 __dirname =========")
console.log("使用 /:")
console.log("resolve ==> ", path.resolve(__dirname, 'a/b','c','/d')) // E:\d
console.log("join ==> ", path.join(__dirname, 'a/b','c','/d')) // E:\myTest\test1\a\b\c\d
console.log("----------------------------------")
console.log("使用 ./:")
console.log("resolve ==> ", path.resolve(__dirname, 'a/b','c','./d')) // E:\myTest\test1\a\b\c\d
console.log("join ==> ", path.join(__dirname, 'a/b','c','./d')) // E:\myTest\test1\a\b\c\d
console.log("----------------------------------")
console.log("使用 ../:")
console.log("resolve ==> ", path.resolve(__dirname, 'a/b','c','../d')) // E:\myTest\test1\a\b\d
console.log("join ==> ", path.join(__dirname, 'a/b','c','../d')) // E:\myTest\test1\a\b\d
console.log("----------------------------------")
// 不要 __dirname , 但是加个带盘符的路径片段 ==> 效果跟加是 __dirname 一样
console.log("========== 加个带盘符的 ==========")
console.log("使用 /:")
console.log("resolve ==> ", path.resolve('F:/', 'a/b','c','/d')) // F:\d
console.log("join ==> ", path.join('F:/', 'a/b','c','/d')) // F:\a\b\c\d
console.log("----------------------------------")
console.log("使用 ./:")
console.log("resolve ==> ", path.resolve('F:/', 'a/b','c','./d')) // F:\a\b\c\d
console.log("join ==> ", path.join('F:/', 'a/b','c','./d')) // F:\a\b\c\d
console.log("----------------------------------")
console.log("使用 ../:")
console.log("resolve ==> ", path.resolve('F:/', 'a/b','c','../d')) // F:\a\b\d
console.log("join ==> ", path.join('F:/', 'a/b','c','../d')) // F:\a\b\d
console.log("----------------------------------")
// 同时使用了 __dirname和盘符,或者穿插在其他路径片段里面
console.log("========== 这是要搞事情啊 ==========")
console.log("resolve ==> ", path.resolve(__dirname, 'F:/', 'a/b','c')) //F:\a\b\c
console.log("resolve ==> ", path.resolve('F:/', __dirname, 'a/b','c')) //E:\myTest\test1\a\b\c
console.log("resolve ==> ", path.resolve('x/y', 'F:/', __dirname, 'a/b','c')) //E:\myTest\test1\a\b\c