大搜车内部两行代码,我自己测试没有成功。见图。
发布于 6 年前 作者 mrlong 4740 次浏览 来自 问答

屏幕快照 2016-08-15 10.10.33.png

15 回复

这两行代码的目的是以前我们写 var xxx = require("…/…/lib/aa.js"); 可以直接写 var xxx = require(“lib/js”);

1231<br/><br/><a class=“form” href=“https://github.com/shinygang/Vue-cnodejs”>I‘m webapp-cnodejs-vue</a>

这样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 源码在哪?? 能粘出主要代码吗??

@mrlong

_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的异常

会不会影响编辑器的代码跳转和路径联想功能?

回到顶部