匹配字符相等算法
// node_modules reverse
var nmChars = [ 115, 101, 108, 117, 100, 111, 109, 95, 101, 100, 111, 110 ];
let from = "F:\node-test\lerna-3.22.1\lerna-3.22.1";// 绝对路径
// 末尾开始找
const CHAR_BACKWARD_SLASH = 92; // \
const CHAR_BACKWARD_SLASH = 47;// /
const CHAR_COLON = 58;// :
for (var i = from.length - 1; i >= 0; --i) {
const code = from.charCodeAt(i);
if (code === CHAR_BACKWARD_SLASH ||
code === CHAR_FORWARD_SLASH ||
code === CHAR_COLON) {
if (p !== nmLen) // /.../之间不能与node_modules匹配,加上node_modules
paths.push(from.slice(0, last) + '\\node_modules');
last = i;
p = 0;
} else if (p !== -1) {
if (nmChars[p] === code) { //匹配 ++
++p;
} else {//新的目录,重新开始计数
p = -1;
}
}
}
yargs
脚手架构成
bin:package.js中配置bin属性,npm link本地安装
command:命令
options:参数(boolean、string、number)
文件顶部增加
#!usr/bin/env node
脚手架初始化流程
构造函数:Yargs()
常用方法:
Yargs.options Yargs.option Yargs.group Yargs.demandCommand Yargs.recommendCommands Yargs.strict Yargs.fail Yargs.alias Yargs.wrap Yargs.epilogue
脚手架参数解析方法
hideBin(process.args)/Yargs.argv Yargs.parse(argv,options)
命令注册方法
Yargs.command(command,describe,builder,handler) Yargs.command({command,describe,builder,handler})
Lerna实现原理
- Lerna是基于git+npm的多package项目管理工具
- 实现原理
- 通过import-local优先调用本地lerna命令
- 通过Yargs生成脚手架,先注册全局属性,再注册命令,最后通过parse方法解析参数
- lerna命令注册时需要传入builder和handler两个方法,builder方法用于注册命令专属的options,handler用来处理命令的业务逻辑
- lerna通过配置npm本地依赖的方式来进行本地开发,具体方法是在package.json的依赖中写入:file:your-local-module-path,在lerna publish时会自动将该路径替换
Node.js模块路径解析流程
Node.js项目模块路径解析是通过require.resolve方法来实现的
require.resolve就是通过Module._resolveFileName方法实现的
require.resolve实现原理:
Module._resolveFileName方法核心流程有3点:
- 判断是否为内置模块
- 通过Module._resolveLookupPaths方法生成node_modules可能存在的路径
- 通过Module._findPath查询模块的真实路径
Module._findPath核心流程有4点:
- 查询缓存(将request和paths通过\x00合并成cacheKey)
- 遍历paths,将path与request组成文件路径basePath
- 如果basePath存在则调用fs.realPathSync获取文件真实路径
- 将文件真实路径缓存到Module._pathCache(key就是前面生成的cacheKey)
fs.realPathSync核心流程有3点:
- 查询缓存(缓存的key为p,即Module._findPath中生成的文件路径)
- 从左往右遍历路径字符串,查询到/时,拆分路径,判断该路径是否为软链接,如果是软连接则查询真实链接,并生成新路径p,然后继续往后遍历,这里有1个细节需要特别注意:
- 遍历过程中生成的子路径base会缓存在knownHard和cache中,避免重复查询
- 遍历完成得到模块对应的真实路径,此时会将原始路径original作为key,真实路径作为value,保存到缓存中
require.resolve.paths等价于Module._resolveLookupPaths,该方法用于获取所有node_modules可能存在的路径
require.resolve.path实现原理:
如果路径为/(根目录),直接返回['/node_modules']
否则,将路径字符串从后往前遍历,查询到/时,拆分路径,在后面加上node_modules,并传入一个paths数组,直到查询不到/后返回paths数组