如何检测浏览器是否支持动态ES6模块加载?

问题描述 投票:1回答:2

背景

JavaScript ES6规范支持module importsES6 modules

静态导入非常易于使用,并且已经具有quite a good browser support,但是动态导入为still lacking behind。因此,您的代码有可能使用静态模块(当不支持这些模块时,代码甚至不会执行),但浏览器可能会错过对dynamic导入的支持。因此,检测动态加载是否有效(在尝试实际加载代码之前)可能很有用。还有as browser detection is frowned upon,我当然想使用特征检测。

用例可能会显示错误,回退到其他一些数据/默认/加载算法,为开发人员提供了在模块中动态加载(例如,以延迟模式样式的数据)优势,同时允许回退到直接传递数据等。基本上,可以使用特征检测的所有常用情况。

问题

现在,由于动态模块是通过import('/modules/my-module.js')导入的,因此显然会试图仅检测该函数是否存在,例如:

// this code does NOT work
if (import) {
    console.log("dynamic import supported")
}

我猜想,对于每个其他函数?都可以,但是问题似乎是:import分别是a reserved keyword in ECMAScript,现在显然也用于指示静态导入,这不是真正的功能。正如MDN所说,它就像“功能类”。

重试

import()导致语法错误,因此这实际上不是可用的,并且import("")导致拒绝的Promise,这可能是有用的,但看起来确实有点黑/像变通办法。此外,它仅需要异步上下文(await等)用于特征检测,这并不是很好。typeeof import也直接失败,由于关键字(“意外令牌:关键字'import'”)而导致语法错误。

那么,可靠地检测浏览器是否支持dynamic ES6模块的最佳方法是什么?

编辑:正如我看到的一些答案一样,请注意,该解决方案当然应该尽可能地普遍可用,例如CSPs可能会阻止the use of eval,在PWA中,您不应假定自己一直在线,因此仅尝试请求某个任意文件可能会导致错误的结果。

javascript ecmascript-6 module es6-modules feature-detection
2个回答
0
投票

在更多研究中,我发现了eval,并带有用于动态特征检测的JS必不可少的部分:

为此,所有功劳都来自GitHub function supportsDynamicImport() { try { new Function('import("")'); return true; } catch (err) { return false; } } document.body.textContent = `supports dynamic loading: ${supportsDynamicImport()}`;

无论如何,这有两个问题:

  • 使用评估@ebidel,尤其是对于which is evil
  • 根据要点中的评论,它在Chrome和Edge(某些版本)中确实具有false-positives。 (即,尽管这些浏览器实际上不支持它,但它始终返回websites that use a CSP

0
投票

唯一想到的是true或类似eval的解决方案,例如使用eval插入script标签。您有import()使用import()或类似的名称。除非它在您的模块映射中,否则它是无效的模块说明符,因此不应引起网络请求。

foo更方便,但会与某些CSP冲突:

eval

避免let supported = false; try { eval("try { import('foo').catch(() => {}); } catch (e) { }"); supported = true; } catch (e) { } document.body.insertAdjacentHTML("beforeend", `Supported: ${supported}`);

eval

[它们都在Chrome,Chromium Edge,Firefox等上默默报告let supported = false; const script = document.createElement("script"); script.textContent = "try { import('foo').catch(() => { }); } catch (e) { } supported = true;"; document.body.appendChild(script); document.body.insertAdjacentHTML("beforeend", `Supported: ${supported}`); ;和true在Legacy Edge上(存在语法错误)。

请注意,false“调用”周围的try / catch只是为了捕获有关模块说明符的所有同步错误,以避免使错误控制台混乱。

实际上,现在我考虑了,您不必动态生成该脚本:

import()
© www.soinside.com 2019 - 2024. All rights reserved.