如何检测脚本在加载时是否导出某些内容?

How to detect if a script exports something when loaded?

假设我在同一目录中有一个脚本 'helpers.js' 作为'main.js',并在后者加载第一个,'helpers.js' 将 return 一个空对象 {} 当不导出任何东西时, 不管内容是什么,这是一个默认值 module.exports 变量,我猜。

有没有办法检查空对象是否是故意的 由 'helpers.js'?

导出

示例 1,无导出:

// helpers.js

// Any valid Javascript here, just no exports.



// main.js

const help = require('./helpers')

console.log(help)

>>> {}

示例 2,导出:

// helpers.js

let exportMe = require('./you').getNewestMe

module.exports = exportMe()



// main.js

const help = require('./helpers')

console.log(help)

>>> {}

我有一些不同的想法,但我意识到我原来的解决方案行不通,所以让我们看看...

加载 CommonJS 模块时(即第一次 required),Node.js 运行一个特殊函数 - 加载程序。 loader 函数可以在模块实际加载之前访问模块的状态,因此它可以检查和修改模块的某些属性的原始值,例如 module.exports。这个想法是,如果我们能以某种方式标记原始值,我们就可以将它与稍后在加载模块时分配的空对象区分开来。

可以使用 Module._extensions['.js'] 检索和更改加载程序函数,其中 Module 是模块构造函数,即 require('module')module.constructor。(Module._extensions与已弃用的 require.extensions 不同,但那是另一回事...)。

加载器函数使用两个参数调用:module 对象和 filename。那么原来的exports对象不出所料,module.exports。 在下面的代码中,我将使用一个符号来标记原始的空 exports 对象:

const noExports = Symbol('no exports');
const extensions = module.constructor._extensions;
const jsLoader = extensions['.js'];
extensions['.js'] = (module, filename) => {
    module.exports[noExports] = filename;
    jsLoader(module, filename);
};

const help1 = require('./helpers-without-exports.js');
const help2 = require('./helpers-with-empty-exports.js');

console.log(noExports in help1); // true
console.log(noExports in help2); // false

该方法只对loader函数打补丁后加载的模块有效,并且只判断模块创建后module.exports是否改变,所以不检测[=26导出的值=](在这种情况下,导出的对象无论如何都是 non-empty)。

另一个特殊情况是 re-exports 另一个不导出任何内容的模块(例如 module.exports = require('./foo'); 其中 foo.js 是一个空文件)。为了检测这些情况,如有必要,可以将符号 属性 的值与分配给该符号的模块文件名进行比较,看看它们是否匹配:

console.log(help1[noExports] === require.resolve('./helpers-without-exports.js')); // true
console.log(help2[noExports] === require.resolve('./helpers-with-empty-exports.js')); // false