跳到主要内容

Module._nodeModulePaths源码解析

获取当前目录下所有可能的 node_modules 路径

// 'node_modules' character codes reversed
const nmChars = [115, 101, 108, 117, 100, 111, 109, 95, 101, 100, 111, 110];
const nmLen = nmChars.length;

Module._nodeModulePaths = function (from) {
// Guarantee that 'from' is absolute.
from = path.resolve(from);
// Return early not only to avoid unnecessary work, but to *avoid* returning
// an array of two items for a root: [ '//node_modules', '/node_modules' ]
if (from === "/") return ["/node_modules"];

// note: this approach *only* works when the path is guaranteed
// to be absolute. Doing a fully-edge-case-correct path.split
// that works on both Windows and Posix is non-trivial.
const paths = [];
for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) {
const code = StringPrototypeCharCodeAt(from, i);
if (code === CHAR_FORWARD_SLASH) {
if (p !== nmLen)
ArrayPrototypePush(
paths,
StringPrototypeSlice(from, 0, last) + "/node_modules"
);
last = i;
p = 0;
} else if (p !== -1) {
if (nmChars[p] === code) {
++p;
} else {
p = -1;
}
}
}

// Append /node_modules to handle root paths.
ArrayPrototypePush(paths, "/node_modules");

return paths;
};

执行流程

1. 解析路径为绝对路径

from = path.resolve(from);

2. 根目录直接返回 /node_modules

if (from === "/") return ["/node_modules"];

如果当前传入目录为根路径的话,则直接返回 ['/node_modules'],否则执行遍历动作

3. 遍历添加 path

遍历各级目录,顺着目录依次向上查找,在每一级目录后面都添加 /node_modules 然后放入 paths 中进行返回

const paths = [];
// !!!p 用来判断当前字符串是否和 node_modules 相等
for (let i = from.length - 1, p = 0, last = from.length; i >= 0; --i) {
const code = from.charCodeAt(i);
if (code === CHAR_FORWARD_SLASH) {
if (p !== nmLen)
ArrayPrototypePush(
paths,
StringPrototypeSlice(from, 0, last) + "/node_modules"
); // 推入带有node_modules的路径
last = i;
p = 0;
} else if (p !== -1) {
if (nmChars[p] === code) {
++p;
} else {
p = -1;
}
}
}

// Append /node_modules to handle root paths.
ArrayPrototypePush(paths, "/node_modules");

return paths;

3.1 获取字符串 charcode 码

const code = StringPrototypeCharCodeAt(from, i);

const code = from.charCodeAt(i);

3.2 判断 charcode 值是否为 47

if (code === CHAR_FORWARD_SLASH) {
...
}
  • CHAR_FORWARD_SLASH === 47 === '/'
  • 判断当前字符串是否为文件夹

3.2.1 判断 p 和 node_modules 长度是否一致

if (p !== nmLen) paths.push(from.slice(0, last) + "/node_modules");
  • 如果当前字符串和 node_modules 不相同,则给当前路径拼接 /node_modules
  • 否则不做处理

3.3 判断字符串长度

else if (p !== -1) {
...
}
  • p 用来标识当前字符串长度
  • p 用来判断当前字符串是否和 node_modules 相等
  • 遇到为文件夹的字符串 p 重新归零计算

3.3.1 判断字符串

if (nmChars[p] === code) {
++p;
} else {
p = -1;
}

判断字符串是否和 node_modules 倒序排列 p 指针获取到的值相等,如果相等,p 指针++,否则为-1

这里为后续判断字符串是否为 node_modules 做准备(如果相等的话则跳过后续任务)