Provide ES Module
- Use microbundle to build CJS and ESM outputs. This seems to be currently the easiest way to compile simple node packages.
- Add "exports" to package.json, so that modern Node.js and TypeScript know how about the entry points.
Some changes to the source code were required:
-
heandiconv-liteprovide just CJS, so they have to be imported via their default export. - Since
require()is not allowed in ESM, I made the change to always importsource-map-support. It doesn't seem to hurt the tests. To be honest, I also don't know what's it good for.npm run teststill passes…
I tested the ESM code by trying to run a simple script that imports the generated file:
import { unfurl } from './dist/index.esm.mjs'
const metadata = await unfurl("https://github.com")
console.log(metadata)
What's the benefit to providing an ES module rather than just plain old CJS? I'm not opposed to this change, just interested.
The benefit is being able to reliably import this package from a ES module.
When Node.js runs in ESM mode (eg. type:package or file has a .mjs extension) then the following code can fail with an error, since you can't import named exports from a CJS file. It currently works, as Node.js does best effort to attempt to determine the named exports. However any small change in the build system could break that compatibility.
import { unfurl } from "unfurl.js"
The more robust way is to use the default export (that's guaranteed to work), but that's not intuitive.
import defaultExport from "unfurl.js"
const unfurl = defaultExport.unfurl
By providing an explicitly guaranteed ESM-compatible entry point (for modern runtimes and bundlers), this issue can be avoided.
It currently works, as Node.js does best effort to attempt to determine the named exports.
I think this makes it not worth adding the bundler, since it works without. Also it looks like tsc already outputs a mjs file.