Seeking advice on optimal npm package formats

Hey folks, I’m puzzled about which module format to use for my npm packages. I’ve been coding in JS for a bit, but this still confuses me.

There are so many options:

  • ESM: Great for writing and tree-shaking, works in most browsers. But older Node versions can’t use it with require.
  • CommonJS: Works everywhere in Node, but not great for browsers. It doesn’t tree-shake well.
  • UMD: Easy to use in any browser, but no tree-shaking at all.

We can ship both formats or just one. We can also include a UMD bundle for easy browser use via CDNs, but it won’t tree-shake.

So I’m wondering:

  1. Should we use dual packaging or just ESM for packages used in both client and server?
  2. Is there any point in using ESM for Node-only stuff like servers or CLIs?
  3. Is UMD still useful now that most browsers support ES modules?

Also, does anyone know a good site with tips for publishing open-source npm packages? Thanks!

hey alexlee, i also struggled w/ choice. i tend to use ESM mostly - it’s futureproof and works in modern envs, while sticking with CJS for node-only pkgs. umd’s nearly obsolete unless you need older browser support. docs - npm might help.

I’ve been through this dilemma too, and here’s what I’ve learned:

For packages used in both client and server environments, dual packaging (ESM + CJS) is indeed the most flexible approach. It covers all bases and caters to a diverse developer audience.

For Node-only applications, I prefer sticking with CommonJS. It’s robust in Node and sidesteps any additional overhead.

UMD has largely been phased out for me, owing to the rise of ES modules and modern bundlers. However, when absolute compatibility is necessary without a build process, UMD might still find its niche.

Always ensure your package is accompanied by a comprehensive README and solid CI/CD configuration to facilitate smoother adoption and maintenance.

In my experience, dual packaging (ESM + CJS) is the way to go for packages used across client and server. It offers the best compatibility and performance benefits. For Node-only packages, I still prefer CommonJS as it’s more straightforward and widely supported.

Regarding UMD, I’ve found its usefulness diminishing. Most modern projects use bundlers or CDNs that support ESM, making UMD less necessary. However, if you’re targeting a wide range of environments or creating a library for direct browser use, UMD can still be valuable.

For publishing open-source npm packages, I’ve found the npm documentation quite comprehensive. Additionally, GitHub’s guide on creating packages is an excellent resource. Remember to include clear documentation, examples, and maintain semantic versioning for your packages.