bs58check icon indicating copy to clipboard operation
bs58check copied to clipboard

cjs vs esm import compatibility issue

Open maerzhase opened this issue 11 months ago • 3 comments

There's an incompatibility between the cjs and esm versions of this package that causes issues for projects using named imports.

problem

The current esm version only provides a default export:

https://github.com/bitcoinjs/bs58check/blob/a128f033f48c08c6097edf610df661de4611f3ec/src/esm/index.js#L1-L8

But existing projects may be using named imports that work with the cjs version:

import { encode } from 'bs58check';
// or
import * as bs58check from 'bs58check';
bs58check.encode(...);

why It works in cjs but not esm?

In the cjs version, the package does essentially the same thing:

// index.cjs (CommonJS)
var sha256_1 = require("@noble/hashes/sha256");
var base_js_1 = __importDefault(require("./base.cjs"));

function sha256x2(buffer) {
    return (0, sha256_1.sha256)((0, sha256_1.sha256)(buffer));
}

exports.default = (0, base_js_1.default)(sha256x2);

however, cjs modules are consumed differently:

  1. when using require('bs58check'), you get the entire exports object
  2. many bundlers and node have special handling for cjs modules that allows property access forwarding
  3. typescript interoperability helpers (__importDefault and Object.defineProperty(exports, "__esModule", { value: true })) help bridge the gap

In the esm world, imports are strictly enforced. when you do import { encode } from 'bs58check', it's specifically looking for a named export called encode, which doesn't exist in the esm version.

proposed solution

To maintain compatibility with existing code, the esm version should export both the default object and its methods as named exports:

import { sha256 } from '@noble/hashes/sha256';
import bs58checkBase from './base.js';

function sha256x2(buffer) {
    return sha256(sha256(buffer));
}

const bs58check = bs58checkBase(sha256x2);
export const { encode, decode, decodeUnsafe } = bs58check;
export default bs58check;

This would ensure that both import styles work consistently across cjs and esm environments, avoiding breaking changes for users migrating to esm or using packages that have migrated to ESM.

maerzhase avatar Mar 17 '25 17:03 maerzhase