CodeSampleX

Beispiel

lodash 4.18.1: Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors

Verifiziertes Beispiel für npm lodash 4.18.1: Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors. Der…

sha256:e991b2b17774ff91d87fbe5ebfa2b3997a9f8b8c1fae7cb5d671573c6ebe68a9

Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen. Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen. MIT-0

Ausführungsbelege

Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.

Beleggrundlage
Signierter Vertrag bestanden
Verifizierungsbelege
6
Signaturschlüssel, die es gebaut haben
3
Deklarierte Umgebung node 22 linux x64 node 22 npm

Umgebungen der Verifizierungsläufe

Umgebung Contract Stufen Lauf
node 22 · linux alpine/x64 · docker ed25519:a2ec939a4c60e243 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-13
node 22 · linux alpine/x64 · docker ed25519:a2ec939a4c60e243 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-13
node 22 · linux alpine/x64 · docker ed25519:a2ec939a4c60e243 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-13
node 22 · linux alpine/x64 · docker ed25519:a2ec939a4c60e243 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-13
node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-17
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-09-08

Fall

FIX
Ziel
Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors
Pakete
Symbole
  • createRequire
  • import.meta.url
  • lodash.chunk
  • lodash.groupBy
  • lodash.merge
  • require.resolve
Umgebung
node 22
Erstellt
2026-08-13T14:19:47Z

Contract

  1. importing a named export from the CJS-only package throws SyntaxError: Named export 'chunk' not found ... is a CommonJS module
  2. calling require() in ES module scope throws ReferenceError: require is not defined in ES module scope
  3. the default-import interop pattern returns correct lodash results for chunk, groupBy and a deep merge that does not mutate its input
  4. createRequire(import.meta.url) supplies real require semantics: it requires a JSON subpath inside the dependency and resolves the package to a filesystem path
  5. import * as namespace leaves the CJS functions undefined on the namespace and reachable only through namespace.default

Dateien

  • csx.json
  • package-lock.json
  • package.json
  • src/broken-named-import.mjs
  • src/broken-require.mjs
  • src/index.mjs
  • test/contract.mjs

Quellartefakt herunterladen (tar.gz)

Quelltext

csx.json
{"case":{"caseId":"case:sha256:c534654c43aa4afbd6802ae13af996bed5e3b50231fa71b0cf2b01d163d77cbe","constraints":{"moduleSystem":"esm","runtime":"node"},"contract":["importing a named export from the CJS-only package throws SyntaxError: Named export 'chunk' not found ... is a CommonJS module","calling require() in ES module scope throws ReferenceError: require is not defined in ES module scope","the default-import interop pattern returns correct lodash results for chunk, groupBy and a deep merge that does not mutate its input","createRequire(import.meta.url) supplies real require semantics: it requires a JSON subpath inside the dependency and resolves the package to a filesystem path","import * as namespace leaves the CJS functions undefined on the namespace and reachable only through namespace.default"],"goal":"Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors","kind":"FIX","packages":["pkg:npm/lodash@4.18.1"],"schemaVersion":1,"symbols":["createRequire","import.meta.url","lodash.chunk","lodash.groupBy","lodash.merge","require.resolve"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","moduleSystem":"esm","os":"linux","packageManager":"npm","runtime":"node","runtimeVersion":"22","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/lodash@4.18.1"],"schemaVersion":1,"symbols":["createRequire","import.meta.url","lodash.chunk","lodash.groupBy","lodash.merge","require.resolve"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "csx-sample-esm-cjs-interop",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "csx-sample-esm-cjs-interop",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "lodash": "4.18.1"
      }
    },
    "node_modules/lodash": {
      "version": "4.18.1",
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
      "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
      "license": "MIT"
    }
  }
}
package.json
{
  "name": "csx-sample-esm-cjs-interop",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "license": "MIT-0",
  "dependencies": {
    "lodash": "4.18.1"
  }
}
src/broken-named-import.mjs
// FAILURE MODE 1 — DO NOT COPY THIS.
//
// lodash is CommonJS-only (no "type":"module", no "module" field, no "exports"
// field). Node can still `import` it, but the named exports you get are
// whatever Node's static CJS lexer can detect by reading the source. lodash
// assigns its exports from inside a UMD closure, so the lexer detects nothing
// and the only export available is `default`.
//
// Importing this file throws at LINK time, before a single line runs:
//
//   SyntaxError: Named export 'chunk' not found. The requested module 'lodash'
//   is a CommonJS module, which may not support all module.exports as named
//   exports.
//
// Note this is package-shape dependent, not a blanket rule about CJS: the lexer
// *does* detect `module.exports = { ... }` object literals, so named imports
// from some CJS packages work fine. You cannot tell by looking at the import.
import { chunk } from 'lodash';

export const nope = chunk;
src/broken-require.mjs
// FAILURE MODE 2 — DO NOT COPY THIS.
//
// The reflex after failure mode 1 is to reach for require(). But `require` is a
// CommonJS-module-scope variable, and this file is an ES module, so the
// identifier simply does not exist. Importing this file throws at RUN time:
//
//   ReferenceError: require is not defined in ES module scope, you can use
//   import instead
//
// The same applies to `module`, `exports`, `__dirname` and `__filename`.
// The fix is not to rename the file to .cjs — it is createRequire(), see
// src/index.mjs.
const _ = require('lodash');

export const nope = _.chunk;
src/index.mjs
// Importing a CommonJS-only package (lodash) from an ES module.
//
// See src/broken-named-import.mjs and src/broken-require.mjs for the two ways
// this normally blows up. This file is the pattern that works.

// PATTERN 1 — default-import interop.
// A CJS module's `module.exports` always arrives as the ESM default export, so
// take the default and destructure from it. This is exactly what Node's own
// error message tells you to do. It costs nothing at runtime: `_` is the same
// object `require('lodash')` would have returned.
import _ from 'lodash';
// Same package, namespace form — kept only to demonstrate the difference below.
import * as lodashNamespace from 'lodash';

const { chunk, groupBy, merge } = _;

// PATTERN 2 — createRequire, for when you truly need require() semantics.
// `require` does not exist in ESM scope, but you can build a real one bound to
// this file's URL. Use it for things `import` cannot do: requiring a JSON file
// from inside a dependency, or resolving a package to a filesystem path.
// import.meta.url is the ESM stand-in for __filename.
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);

export function pageItems(items, size) {
  return chunk(items, size);
}

export function bucketByParity(nums) {
  return groupBy(nums, (n) => (n % 2 ? 'odd' : 'even'));
}

export function deepMergeConfig(base, override) {
  // merge() mutates its first argument, so start from a fresh object to avoid
  // clobbering the caller's config.
  return merge({}, base, override);
}

export function lodashVersion() {
  // `import pkg from 'lodash/package.json'` needs an import attribute and is
  // still awkward across runtimes; require() of a JSON subpath just works.
  return require('lodash/package.json').version;
}

export function resolvedFromESM() {
  // No ESM equivalent of require.resolve() that returns a plain path.
  return require.resolve('lodash');
}

export function namespaceShape() {
  // `import * as ns from 'lodash'` does NOT spread the CJS exports onto the
  // namespace — every function hangs off ns.default instead. Reported as
  // typeof strings so the contract can assert the shape.
  return {
    directChunk: typeof lodashNamespace.chunk, // undefined — the trap
    viaDefault: typeof lodashNamespace.default.chunk, // function — the payload
  };
}
test/contract.mjs
import { strict as assert } from 'node:assert';
import {
  pageItems,
  bucketByParity,
  deepMergeConfig,
  lodashVersion,
  resolvedFromESM,
  namespaceShape,
} from '../src/index.mjs';

// Helper: import a module that is expected to fail, and hand back the error.
async function importExpectingFailure(spec) {
  try {
    await import(spec);
  } catch (err) {
    return err;
  }
  throw new Error(`expected ${spec} to throw, but it imported cleanly`);
}

// --- 1. Named imports from a CJS-only package fail at link time -------------
const namedErr = await importExpectingFailure('../src/broken-named-import.mjs');
assert.ok(
  namedErr instanceof SyntaxError,
  `expected SyntaxError, got ${namedErr.constructor.name}`,
);
assert.match(namedErr.message, /Named export 'chunk' not found/);
assert.match(namedErr.message, /is a CommonJS module/);

// --- 2. require() does not exist in ES module scope -------------------------
const requireErr = await importExpectingFailure('../src/broken-require.mjs');
assert.ok(
  requireErr instanceof ReferenceError,
  `expected ReferenceError, got ${requireErr.constructor.name}`,
);
assert.match(requireErr.message, /require is not defined in ES module scope/);

// --- 3. The default-import interop pattern returns correct values -----------
assert.deepEqual(pageItems([1, 2, 3, 4, 5], 2), [[1, 2], [3, 4], [5]]);
assert.deepEqual(bucketByParity([1, 2, 3, 4]), { odd: [1, 3], even: [2, 4] });

// merge is a *deep* merge; a spread would drop base.retry.max entirely.
const base = { retry: { max: 3, backoffMs: 250 }, tags: ['a'] };
const merged = deepMergeConfig(base, { retry: { backoffMs: 1000 } });
assert.deepEqual(merged, { retry: { max: 3, backoffMs: 1000 }, tags: ['a'] });
// ...and the helper must not have mutated the caller's object.
assert.equal(base.retry.backoffMs, 250);

// --- 4. createRequire gives genuine require semantics -----------------------
// A version string proves a subpath JSON file was really required.
assert.match(lodashVersion(), /^4\.\d+\.\d+$/);
// require.resolve returns a real filesystem path to the CJS entry point.
assert.match(resolvedFromESM(), /lodash[\\/]lodash\.js$/);

// --- 5. The namespace object is not the module ------------------------------
// `import * as ns` on a CJS-only package yields a namespace whose only useful
// key is `default`; ns.chunk is undefined. This trips people right after they
// give up on named imports.
const shape = namespaceShape();
assert.equal(shape.directChunk, 'undefined');
assert.equal(shape.viaDefault, 'function');

console.log(
  'CONTRACT PASS: named import throws SyntaxError, require throws ReferenceError, ' +
    'default-import + createRequire produce correct lodash results',
);

Ursprungs-Seeder

anonymous