总结
知识点
- __filename:当前模块(js)的文件名。 这是当前的模块文件的绝对路径(符号链接会被解析)
- 运行 node代码时,默认会注入modulerequire__filename__dirnameexports五个变量
- node.js中使用 require(".")相当于require("./"),相当于require("./index.js"),也就是查找本地目录的index.js
优秀的文件操作库
pkg-dir 
找到 npm 或者 node.js 项目的根目录
findup 
通过遍历父级目录查账文件或文件夹
locate-path 
从多个文件中获取第一个存在的路径
path-exists
检查路径是否存在
resolve-cwd 
从当前工作目录,像 require.resolve 一样解析模块路径
resolve-from 
从给定路径,像 require.resolve 一样解析模块路径
涉及到的 node.js 方法
- process.cwd()- 返回 Node.js 进程的当前工作目录(working directory)。 
- path.dirname() 
- path.resolve()相对路径转换成真实路径
- path.parse() 
- fs.accessSync(filepath)- 判断文件是否存在(能访问到),不存在会抛出异常 
- path.relative() 
- path.join() 
Node.js 模块路径解析流程
- Node.js项目模块路径解析是通过- require.resolve方法来实现的
- require.resolve就是通过- Module._resolveFileName方法实现的- Module._resolveFileName方法核心流程有 3 点:- 判断是否为内置模块 - NativeModule.canBeRequireByUsers()判断是否是可以被加载的内置模块
- 通过 - Module._resolveLookupPaths方法生成- node_modules可能存在的路径- 如果路径为 /(根目录),直接返回['/node_modules']
- 否则,将路径字符串从后往前遍历,查询到 /时,拆分路径,在后面加上node_modules,并传入一个paths数组,直至查询不到
 
- 如果路径为 
- 通过 - zModule._findPath查询模块的真实路径
 
- Module._findPath核心流程有 4 点:- 查询缓存(将 request和paths通过\x00合并成cacheKey)
- 遍历 paths,将path与request组成文件路径basePath
- 如果 basePath 存在则调用 <code>fs.realPathSync</code>获取文件真实路径
- 将文件真实路径缓存到 <code>Module._pathCache</code>(key 就是前面生成的 cacheKey)
 
- 查询缓存(将 
- fs.realPathSync核心流程有 3 点:- 查询缓存(缓存的 key 为 p,即 Module._findPath中生成的文件路径)
- 从左往右遍历路径字符串,查询到 /时,拆分路径,判断该路径是否为软链接,如果是软链接则查询真实链接,并生成新路_径 p,然后继续往后遍历,这里有 1 个细节需要特别注意:
- 遍历过程中生成的子路径 base 会缓存在 knownHard 和 cache 中,避免重复查询
- 遍历完成得到模块对应的真实路径,此时会将原始路径 original 作为 key,真实路径作为 value,保存到缓存中
 
- 查询缓存(缓存的 key 为 p,即 
 
- require.resolve.paths等价于- Module._resolveLookupPaths,该方法用于获取所有- node_modules可能存在的路径

图中知识点列表:
- 通过 require加载模块以后,会向Module._pathCache对象中添加该模块的路径,key:模块名称加\x00路径,value:实际路径
- stat(path):查看文件状态。-2 不存在, 0 文件,1 文件夹
- realPathCache是一个- Map对象
- linux- stat命令打印文件相关信息- dev_t设备编号、- ino_t文件的唯一标识
- fs.realPathSync在拿到软连接指向的真实路径后,还会在遍历,查看指向的路径是否还是一个软连接
正则表达式
Modules._findPath() 中的正则 /(?:^|\/)\.?\$/ 匹配 ..、/..。包含知识点
- ?匹配0到1个
- (?:)表示非匹配分组,作用是不保存括号中匹配的内容
- /^/匹配的是个空字符串'',任意字符都能匹配成功,任意字符中都有空字符串
- /[^]/表示非
为什么选择commander, 而不是yrags
- 两者差不多,都是Nodejs命令行工具,lerna选择的是yargs, 
- 但是commander比yargs的热度高 
https://www.npmtrends.com/commander-vs-yargs
