如何编写有条件导入的在浏览器和Node中均可使用的ESM模块

问题描述

我有一个应该在浏览器和节点中运行的代码库。它需要根据是否在节点或浏览器中运行来切换某些功能

以前,我以Commonjs格式编写模块。我有一个“填充程序”模块,可以在其中测试功能部件的环境,然后基于该模块导出内容。因此,所有条件行为都包含在此shim文件中。

现在,我尝试创建“ Shim” ESM模块。我不知道怎么办。某些切换行为取决于检查其他ESM模块是否存在。但是,您只能在异步的动态ESM导入中进行此类测试。而且由于export语句必须在顶层,所以除非有顶层等待可用,否则我无法导出结果。但这在浏览器中不可用。

在我当前的黑客中,我导出了类似延迟的对象,并在需要时await导出它。但这使我不必要地包裹在(async()=>{...})中。

那我该怎么做?

我宁愿不使用捆绑程序,我的浏览器目标肯定是最新的。

解决方法

使用 performance.now() 使模块在节点和浏览器中都能工作时遇到了类似的问题。

这有效:

const P = typeof performance !== 'undefined' ? performance
  : (await import('perf_hooks')).performance

顶级等待挽救了这一天,但是:

  • 截至目前,仅适用于 chrome、node 和 firefox canary
  • 正式来说,仍然只是第 3 阶段的提案
,

另一个更惯用的答案是在 package.json 中设置 main:main.jsbrowser:browser.js 字段,用于设置任何内容在导入和重新导出主模块之前特定于环境的元素。

//main.js fix for nodejs
import {something} from 'nodejsSpecificModule'
global.something = something //or whatever else needed
export {...} from './index.js'
//browser.js fix for browser
import {something} from 'browserSpecificModule'
window.something = something //or whatever else needed
export {...} from './index.js'

这避免了使用顶级等待的动态导入

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...