Node's Perfect Mate

    TypeScript icon, indicating that this package has built-in type declarations

    0.1.1 • Public • Published

    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";

    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";
    $ node ./b.mjs
    TypeError: greet is not a function
        at ./b.mjs:3:1
        at (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.


    npm i node-cjs-interop

    DownloadsWeekly Downloads






    Unpacked Size

    9.66 kB

    Total Files


    Last publish


    • qnighy