What is the difference between `main` and `module` vs `exports` in package.json?
Asked Answered
C

2

37

I'm trying to write a library that can be both required and imported.'ve found different approaches online, which are as follows:

{
  "main": "mylib-cjs.js",
  "module": "mylib-esm.js"
}

and

{
  "exports": {
    "import": "mylib-esm.js",
    "require": "mylib-cjs.js"
  }
}

What are the pros and the cons of both approaches, and how do they differ?

Comber answered 29/7, 2021 at 8:52 Comment(0)
L
29

Generally speaking, the "exports" field superseded the "module" field. "module" itself has never been an official standard but it became so widespread that at some point it was a de facto standard.

Note that the "module" field is still being used by TypeScript if tsconfig's moduleResolution is set to node; see microsoft/TypeScript#50794 for more info.

Of course, there's nothing wrong in having both of these defined at the same time if your aim is to be as backwards compatible as possible.

Regarding the difference between "main" and "exports", as per Node documentation:

In a package's package.json file, two fields can define entry points for a package: "main" and "exports". Both fields apply to both ES module and CommonJS module entry points.

The "main" field is supported in all versions of Node.js, but its capabilities are limited: it only defines the main entry point of the package.

The "exports" provides a modern alternative to "main" allowing multiple entry points to be defined, conditional entry resolution support between environments, and preventing any other entry points besides those defined in "exports". This encapsulation allows module authors to clearly define the public interface for their package.

For new packages targeting the currently supported versions of Node.js, the "exports" field is recommended. For packages supporting Node.js 10 and below, the "main" field is required. If both "exports" and "main" are defined, the "exports" field takes precedence over "main" in supported versions of Node.js.

Keep in mind that the "main" field may still be used by other online tools like jsDelivr: https://www.jsdelivr.com/documentation#id-publishing-packages

Lachrymator answered 12/1, 2023 at 14:26 Comment(0)
M
3

I think you should not use module anymore. It works in webpack and some other bundling tools, but it does not work in node.js. It's older way of defining an ESM entry point. So if you are writing purely an FE library, you are fine using module, but in node.js you need to use the exports. Only that one will work correctly when running in type: module mode.

Not sure about bundlers and their support for exports, but I would expect them to get in line with node's entry point.

Mulhouse answered 23/6, 2022 at 21:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.