JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 768
  • Score
    100M100P100Q111645F
  • License MIT

A library to fix the default import interoperability issue in Node.js

Package Exports

  • node-cjs-interop

Readme

node-cjs-interop: Import helpers for Babel ESM from Node.js native ESM

The problem to solve

Consider the following modules:

// a.js

export default function greet() {
  console.log("Hello, world!");
}
// b.js

import greet from "a.js";

greet();

They usually work, unless the following conditions are met:

  • a.js (the module being imported) is a simulated ESM. That is, the module is transpiled as a CommonJS module (by Babel or TypeScript) before execution. And,
  • b.js (the importing module) is a native ESM, That is, the module is run on Node.js' native ES Module support.

You can reproduce the above condition by placing the following files:

// a.cjs

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true,
});
exports.default = greet;

function greet() {
  console.log("Hello, world!");
}
// b.mjs

import greet from "./a.cjs";

greet();
$ node ./b.mjs
./b.mjs:3
greet();
^

TypeError: greet is not a function
    at ./b.mjs:3:1
    at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:65:12)

The following packages solve the problem:

Getting started

Install the package:

npm install node-cjs-interop
# or:
yarn add node-cjs-interop

Wrap a default import:

import { interopImportCJSDefault } from "node-cjs-interop";
import styledOrig from "styled-components";

const styled = interopImportCJSDefault(styledOrig);

const CustomDiv = styled.div`
  ...
`;

Wrap a namespace import:

import { interopImportCJSNamespace } from "node-cjs-interop";
import * as nsOrig from "your-package";
const ns = interopImportCJSNamespace(nsOrig);

Difference between interopImportCJSNamespace and interopCJSDefault

interopImportCJSNamespace allows more accurate simulation of ESM semantics:

import { interopImportCJSNamespace } from "node-cjs-interop";
// import styled from "styled-components";
import * as nsOrig from "styled-components";

const ns = interopImportCJSNamespace(nsOrig);

// const CustomDiv = styled.div`...`;
const CustomDiv = ns.default.div`...`;

However, using babel-plugin-node-cjs-interop is recommend over manual wrapping.