如何检测脚本在加载时是否导出某些内容?
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 模块时(即第一次 require
d),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
假设我在同一目录中有一个脚本 '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 模块时(即第一次 require
d),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