这两行代码的目的是以前我们写 var xxx = require("…/…/lib/aa.js"); 可以直接写 var xxx = require(“lib/js”);
这样hack代码,要将自己玩坏 自豪地采用 CNodeJS ionic
要消灭dot hell,可以搞一个process.cwd() + path
呀
不明白 好处在哪里
将
require("./lib/foo");
可以以
require("lib/foo");
的形式出现。
我的项目里面也有这种 hack,只不过方式不一样。
Module._resolveFilename = function(request, parent) {
if(!request.startsWith('./') && !request.startsWith('../')) {
if(cache[request]) {
request = cache[request];
} else if(undefined === cache[request]) {
// that is $PROJ_ROOT/src/
var testRequest = path.resolve(SRC_PATH, request);
var names = [
testRequest + '.js',
testRequest + '.json',
testRequest + '/index.js',
testRequest + '/index.json'
];
/**
* because
*
* > Stability: 0 - Deprecated: Use fs.statSync or fs.accessSync instead.
*
* so we use try...catch and statSync instead
*
* see https://nodejs.org/api/fs.html#fs_fs_existssync_path
*/
cache[request] = false;
for(var i = 0; i < names.length; i++) {
try {
if(fs.statSync(names[i]).isFile()) {
request = cache[request] = testRequest;
break;
}
} catch(e) {
// ignore...
}
}
}
}
return _resolveFilename(request, parent);
};
这个框架已经弃坑了,不推荐这样hack的方式。
挖坟啊,这什么时候的视频。。。
@xinyu198736 为啥不推荐,我翻了下lib/modules.js的源码,貌似逻辑没啥问题 对于require的路径,依旧是先匹配内建模块——不成功匹配各个node_modules目录——不成功匹配process.env.NODE_PATH——不成功throw error 我觉得逻辑上没啥问题啊
@xinyu198736 这个process.env.NODE_PATH应该是用来替换最早的require.paths方法的
我觉得完全没有必要这样hack,反而不利于寻找代码
@captainblue2013 在写代码时已规定了结构。不需要去找。
@hyj1991 源码在哪?? 能粘出主要代码吗??
_initPaths()主要向全局modulePaths数组变量中,添加了你设置的path,用来匹配,核心代码见下:
Module._initPaths = function () {
var paths = [path.resolve(process.execPath, '..', '..', 'lib', 'node')];
var nodePath = process.env['NODE_PATH'];
if (nodePath) {
paths = nodePath.split(path.delimiter).filter(function (path) {
return !!path;
}).concat(paths);
}
//如果process.env['NODE_PATH']有值,modulePaths里面添加用户设置的path,用作匹配
modulePaths = paths;
};
require的大致流程:
//最终require模块匹配是在_resolveFilename函数里面完成的,但是匹配的前缀path,是由_resolveLookupPaths提供的
Module.prototype.require—>Module._load—>Module._resolveFilename—>Module._resolveLookupPaths
当requrie的内容最前面两位不带’./‘或者’…'时,匹配的方式是使用modulePaths里面的内容concat上parent里面的path参数
Module._resolveLookupPaths = function (request, parent) {
var start = request.substring(0, 2);
if (start !== './' && start !== '..') {
//首先将paths赋值成为上述的modulePaths
var paths = modulePaths;
if (parent) {
if (!parent.paths) parent.paths = [];
//parent.paths里面包含的内容是[当前绝对路径/node_modules,当前上一级绝对路径/node_modules,...,/node_modules],这里讲parent.paths和paths做了一次concat
paths = parent.paths.concat(paths);
}
//返回参数形式为[原始require方法内填写的内容(比如'lib/js'),第二个参数是用来组装匹配的路径数组]
return [request, paths];
}
最后一步在_resolveFilename函数中调用Module._findPath(request, paths)进行最终的匹配,大致代码逻辑如下:
Module._findPath = function (request, paths) {
//此处request为用户require的内容,比如:'lib/js',
//此处paths为上述返回的数组,内容为:[当前路径/node_modules,当前路径上一级/node_modules,...,一直到根路径/node_modules,process.env.NODE_PATH]
for (var i = 0, PL = paths.length; i < PL; i++) {
if (paths[i] && internalModuleStat(path._makeLong(paths[i])) < 1) continue;
var basePath = path.resolve(paths[i], request);
//下面是对basePath进行验证处理的逻辑
}
//如果一直没匹配到,返回false
return false
};
可以看到,上述代码中的循环所操作的就是调用path.resolve方法,对paths数组里面的每一个内容和’lib/js’进行匹配,匹配到就返回成功 所以呢,如果你不添加process.env.NODE_PATH参数,则只会寻找各级目录下的node_modules文件夹,如果添加了process.env.NODE_PATH,则会在寻找完各级路径下的node_modules文件夹后,再去匹配下process.env.NODE_PATH的路径 这就是大搜车内部两行代码的作用,需要注意到是,这两行代码需要放到启动js文件的顶部,才会生效
结论
并且这不算什么hack方法,看懂源码,其实对原始require流程没有什么影响,因为requrie加载非相对路径和绝对路径modules的优先级依旧是: 1.从当前目录开始各级目录下的node_modules目录寻找 2.各级目录下的node_modules文件夹匹配不到寻找process.env.NODE_PATH目录下对应内容 3.以上都匹配不到返回false,throw 未找到module的异常
会不会影响编辑器的代码跳转和路径联想功能?