asciidoctor/asciidoctor.js

Refine package exports

ggrossetie opened this issue · 3 comments

We should refine exports as described in: https://nodejs.org/api/packages.html#packages_package_entry_points

Currently, we define the following:

{
  "type": "module"
  "main": "dist/node/asciidoctor.js",
  "browser": "dist/browser/asciidoctor.js",
  "module": "dist/browser/asciidoctor.js",
}

This is not good enough because web bundlers prioritize module when the target is node.
As a result, we need to

{
  "type": "module"
  "main": "dist/node/asciidoctor.cjs",
  "browser": "dist/browser/asciidoctor.umd.js",
  "module": "dist/browser/asciidoctor.module.js",
  "exports": {
    ".": {
      "node": {
        "import": "./dist/node/asciidoctor.js",
        "require": "./dist/node/asciidoctor.cjs",
        "default": "./dist/node/asciidoctor.cjs"
      },
      "browser": "./dist/browser/asciidoctor.umd.js",
      "umd": "./dist/browser/asciidoctor.umd.js",
      "import": "./dist/browser/asciidoctor.module.js",
      "default": "dist/browser/asciidoctor.umd.js"
    }
  }
}

Open questions:

As you can see, the above definition prioritize the browser. I think this is safer since exports is not broadly supported by web bundlers (which most of the time target the browser).

I'm still thinking about whether or not we should export an UMD. If we don't, it would greatly simplify things on our side and I believe that most (all?) web bundlers can now work with an ESM library.

Without UMD:

{
  "type": "module"
  "main": "dist/node/asciidoctor.cjs",
  "browser": "dist/browser/asciidoctor.js",
  "module": "dist/browser/asciidoctor.js",
  "exports": {
    ".": {
      "node": {
        "import": "./dist/node/asciidoctor.js",
        "require": "./dist/node/asciidoctor.cjs",
        "default": "./dist/node/asciidoctor.js"
      },
      "default": "dist/browser/asciidoctor.js"
    }
  }
}

"default" - the generic fallback that always matches. Can be a CommonJS or ES module file. This condition should always come last.

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

Since default is unspecified, it's probably better to use an ES module file (i.e., future proof).

It's arguably a bit misleading that main points to a CommonJS module file since type is module but it's the recommended by the Node.js documentation:

If both "exports" and "main" are defined, the "exports" field takes precedence over "main". "exports" are not specific to ES modules or CommonJS; "main" is overridden by "exports" if it exists. As such "main" cannot be used as a fallback for CommonJS but it can be used as a fallback for legacy versions of Node.js that do not support the "exports" field.

Newer version of Node.js (which support ES module) will use exports.node.import over main.

I think we did a relatively good job in 3.0.4, closing.