检查dynamic import是否是JavaScript/TypeScript中的模块



我正在为一个多年前创建的项目开发ScriptManager类。原始代码从数据库读取脚本,这些脚本根据客户和安装而不同(应用程序是使用Chrome嵌入式框架显示网页的桌面应用程序)。代码将读取自定义JavaScript代码并对其进行eval(),这当然是非常不可取的。

我用一个可以支持动态插入代码的ScriptManager类来替换这些代码,并且ScriptManager能够使用JavaScript的动态import()命令将代码加载为模块,或者通过在文档中动态创建脚本标记将代码加载为纯脚本。

我的问题是,有许多不同的可能的自定义代码块在数据库中,而不是所有的模块;有些将是纯脚本,直到它们可以在以后的时间转换为模块。我的代码可以如上所述处理此问题,但我需要一种方法来检测数据库中的脚本代码是否为模块,因此我可以使用import()命令或插入脚本标记(如果不是)。

我通过确保任何模块脚本代码具有&;export const isModule = true&;并在调用import()后检查此问题来临时解决此问题。这是可行的,但是任何纯脚本代码仍然会产生模块变量,但其中没有导出。如果可能的话,我不希望其他开发人员不得不记住在他们将来开发的任何模块中添加isModule = true。

是否有一种方法可以检查代码是一个模块,而不必对代码进行复杂的分析以检查其中是否有导出?由于import()仍然返回一个对象,并且如果没有导出也不会抛出错误,所以我不知道如何检测它。

更新:这里有一些例子说明这是如何工作的:

// Not real code, pretend that function gets the string of the script.
let code = getSomeCodeFromTheDatabase();
// Save the code for later loading.
let filename = 'some-filename.js';
saveCodeToFile(code, filename);
// Attempt to dynamically import the script as a module.
let module = await import(filename);
// If it is NOT a module, load it instead as a script tag.
// This is where I need to be able to detect if the code is
// a module or pure script.
if (!module.isModule) {
let scriptTag = document.createElement('script');
scriptTag.src = filename;

document.head.appendChild(script);
}

如果你看这里我怎么知道如果一个特定的模块是CommonJS模块或ES6模块?你会看到我回答了一个类似的问题。

问题是Sarah,模块是由它们解析的方式定义的。模块类型的不同解析不仅使它们彼此不兼容,而且也是我们以不同的方式命名它们的原因。最初像Babel这样的转译器,是由于ECMA-262规范的差异而被发明的,并且希望支持那些没有更新规范的人,以及为那些有新功能的人提供支持。

今天,转译器在概念上仍以大致相同的方式使用。它们仍然帮助我们维护一个单一的代码库,同时支持旧的规范和新规范中的特性,但它们还有一个额外的好处,即能够从一个代码库生成多个不同的构建。他们使用它来支持不同的模块类型。在node.js中,主要的模块类型是CJS,但未来是ESM模块,所以包维护者选择了双重构建项目。使用TypeScript Compiler(又名Transpiler)来生成CJS构建和ESM构建。

这就是事情变得复杂的地方,因为你不能仅仅通过查看模块来判断它是CJS还是ESM,在这种情况下,**你绝对必须检查它的代码,并检查它是否有多个tsconfig.json文件(因为它至少需要2个来维持一个双模块构建(每天都变得越来越普遍)

我给你的建议:

使用文档完备的软件包。好的包应该有良好的文档,这些包应该在它们的README.md文档中说明它们是什么类型的包/模块,以及包是否支持多个模块类型。如果您有疑问,您可以来这里询问,或者更好的是,您可以通过创建一个问题来询问维护者,要求他们将这些信息添加到他们的README.md文档中。

可以检查导入后是否没有导出。在铬import()添加空default非模块。

function isNotModule(module) {
return (!Object.keys(module).length) || (!!module.default && typeof module.default === 'object' && !Object.keys(module.default).length)
}
import('./test.js')
.then((module) => {
console.log('./test.js',isNotModule(module))
})

可能最好通过regex检查源代码是否包含export

像这样的

const reg = new RegExp('([^w]|^)export((s+)w|(s*{))')
reg.test(source)

最新更新