如何在 package.json 中选择“模块”而不是“主”文件

Posted

技术标签:

【中文标题】如何在 package.json 中选择“模块”而不是“主”文件【英文标题】:How to choose 'module' instead of 'main' file in package.json 【发布时间】:2019-03-01 18:32:38 【问题描述】:

我创建了一些 npm 模块并将它们编译为:

commonJS(使用exports.default =)和 esm(使用export default

我这样设置我的 package.json:

main: "index.cjs.js",
module: "index.esm.js"

当我 npm install 包并简单地导入它时:

import myPackage from 'my-package'

它会自动选择main文件,而不是模块。

我的问题:

javascript 文件中执行 import myPackage from 'my-package' 时,有没有办法导入 module 文件?

为什么我为“main”选择commonJS文件:

我注意到使用 Node,导入 esm 文件是不可能的,因为 export default,它必须是 commonJS。我有一些简单的辅助 JS 函数,例如 this 和 this,我希望它们能够用于最广泛的受众。这就是为什么我选择 cjs 作为 package.json 中的 "main" 路径的原因。

为什么我在 package.json 中定义一个单独的“模块”:

许多像 Vue.js 这样的著名库已经在这样做了。查看有关此 *** 线程的更多信息:

What is the "module" package.json field for?

为什么我希望能够导入“模块”文件而不是“主”文件:

目前有一个bug in Rollup 在导入cjs 文件后编码时无法正确显示JSDoc cmets,但在导入es 文件时它确实工作。 p>

我想避免的解决方法:

只需将“main”设置为 package.json 中的 esm 文件,对吗?但是,所有在 Node 应用程序中使用我的包的用户将无法再使用它......

→ 我对这一切也很困惑,但我认为我做了足够的研究来理解这一切。话虽如此,如果有人知道更好的方法或任何其他建议,请在下面的 cmets 中告诉我!

【问题讨论】:

我不认为 'module` 是 package.json 的有效键。您可能想使用此处解释的内容来解决问题:***.com/a/16631079/1971378。我已经在回答中详细说明了这一点。希望对您有所帮助。 ...重新考虑是否有理由不将main 直接指向index.es.js @82Tuskers 感谢您的链接,但您的回答有点“不妥”。首先,package.json 中的module 被许多著名的库和框架广泛使用。其次,您的链接指向如何导出不同函数的解释......我说的是编译为 CommonJS 和 ES5 的相同函数。最后,我将 main 指向 commonJS 的原因是为了确保它在本地也可以与 node 一起使用。如果我指向 index.es.js 文件 - 它使用 export default - 节点将不会运行它。 目标是什么?如果你在 Node 中使用这个模块,那么你应该配置 main 指向“模块”脚本。如果您在浏览器中使用它,则由您决定如何将其交付给客户端,而不是 package.json @JakeHolzinger 哦?根据我的经验,节点无法导入编译为 es5 的文件(使用 export default),而只能导入 commonJS 编译文件。这就是我设置main: "index.cjs.js" 的原因。 >“如果您在浏览器中使用它,那么您可以选择如何将其交付给客户端,而不是 package.json”我不确定您的意思。如果我写一个人们可以npm iimport x from 'my-pkg' 的小型JS 辅助函数,那么JavaScript 会自动选择设置在"main": 的文件,我认为你不能选择另一个inpoint。这正是我的问题! : D 【参考方案1】:

只是不要对主文件使用扩展名,并且将 es6 和 CommonJS 版本作为两个单独的文件,同名,在同一目录中,但扩展名不同,所以:

index.js // transpiled CommonJS code for old nodejs
index.mjs // es6 module syntax

package.json:


  "main": "index"

如果节点以--experimental-modules 标志启动,它将使用*.mjs 文件,否则*.js

【讨论】:

作者建议他们希望他们的辅助函数“可用于最广泛的受众”,而 .mjs 是 not associated,据我所知,可以使用任何脚本媒体类型。 有谁知道为什么在基于浏览器的应用程序(例如 React)中使用 require() 不会选择模块选项而不是 main? 您可以在基于浏览器的应用程序 b/c 中使用 require(),它与 webpack 之类的东西捆绑在一起。您的捆绑器配置将确定使用什么类型的模块。【参考方案2】:

Nodejs 不支持“模块”,但支持较新的“导出”规范。

https://nodejs.org/api/packages.html#exports

https://github.com/nodejs/node/blob/v16.14.0/lib/internal/modules/esm/resolve.js#L910

  "exports": 
    "import": "./main-module.js",
    "require": "./main-require.cjs"
  ,

【讨论】:

以上是关于如何在 package.json 中选择“模块”而不是“主”文件的主要内容,如果未能解决你的问题,请参考以下文章

在 Node.js 中,模块如何从应用程序的 package.json 中获取数据?

我今天如何在 package.json 中使用“exports”来嵌套子模块和打字稿

如何在 package.json 中动态选择包管理器

在 package.json 中使用 * 而不是版本号时如何始终获取最新版本? [复制]

如何将我的 node_module、模块添加到 package.json

如何将 package.json 导入 Typescript 文件而不将其包含在编译输出中?