is-promise 只做一件事,判断 JavaScript 对象是否为 Promise,但这个包被近百万个项目所依赖。作者在 4月25日发布的新版本并未遵循正确的 ES 模块标准,从而导致更新完成后,所有在构建时使用 is-promise 库的项目几乎全部报错。

这里犯了几个个错误 https://github.com/then/is-promise/blob/8e51d62bf158eb0685cd6109f0137472e8c3cb91/package.json#L7-L10

  • 以为 exports 和 main 一样,但实际上需要 ./ 前缀。
  • exports 不仅限制你能导入什么,还得限制你怎么导入

exports 字段

我们都知道 node 模块导出有 main ,所有版本的Node.js都支持,但是能力有限:它仅定义包的主要入口点。

"exports"扩展了 main,而且二者同时存在时,优先使用 exports。

Node.js支持以下条件:

  • "import" 通过import或 加载包时匹配import()。可以同时引用ES模块或CommonJS文件, import并且import()可以加载ES模块或CommonJS源。
  • "require"通过加载包时匹配require()。由于require()仅支持CommonJS,因此引用的文件必须为CommonJS。
  • "node"适用于任何Node.js环境。可以是CommonJS或ES模块文件。这种情况应该总是在"import"或 之后出现"require"。
  • "default"是CommonJS或ES模块文件,应始终排在最后。

条件导出

一个package.json文件可以直接定义单独的CommonJS和ES模块入口点:
条件匹配的规则是从上至下,所以应按对象顺序使用从最具体到最不具体的条件。

 "exports": {
    ".": [
      {
        "import": "./index.mjs",
        "require": "./index.js",
        "default": "./index.js"
      },
      "./index.js"
    ]
  },

嵌套条件

"exports": {
    "browser": "./feature-browser.mjs",
    "node": {
      "import": "./feature-node.mjs",
      "require": "./feature-node.cjs"
    }
  }

参考文章:
https://github.com/then/is-promise/issues/13
https://medium.com/javascript-in-plain-english/is-promise-post-mortem-cab807f18dcc