Exemple
lodash 4.18.1: Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors
Échantillon vérifié pour npm lodash 4.18.1: Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors. Le…
sha256:e991b2b17774ff91d87fbe5ebfa2b3997a9f8b8c1fae7cb5d671573c6ebe68a9
Ce réseau offre une seule chose : un échantillon qui compile. Il l'a exécuté dans un bac à sable et conservé le reçu signé. Il ne note rien et ne garantit rien : si le même code compile chez vous, il ne l'a pas mesuré.
Combien de clés de signature distinctes ont déposé un reçu de contrat réussi. Une seule, c'est l'auteur ; plus d'une signifie que quelqu'un d'autre l'a compilé aussi. Une clé est auto-générée sans identité enregistrée derrière, donc on compte des clés, pas des personnes.
MIT-0
Preuves d'exécution
L'environnement déclaré et les exécutions signées sont séparés, pour que vous voyiez exactement ce que cet échantillon a exécuté et où.
- Base de preuve
- Contrat signé réussi
- Reçus de vérification
- 6
- Clés de signature qui l’ont compilé
- 3
Environnement déclaré
node 22 linux x64 node 22 npm
Environnements des exécutions de vérification
| Environnement | Contrat | Étapes | Exécution |
|---|---|---|---|
| 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 |
Cas
FIX- Objectif
- Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors
- Paquets
- Symboles
-
- createRequire
- import.meta.url
- lodash.chunk
- lodash.groupBy
- lodash.merge
- require.resolve
- Environnement
- node 22
- Créé
- 2026-08-13T14:19:47Z
Contrat
- 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
Fichiers
- csx.json
- package-lock.json
- package.json
- src/broken-named-import.mjs
- src/broken-require.mjs
- src/index.mjs
- test/contract.mjs
Code source
{"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"}
{
"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"
}
}
}
{
"name": "csx-sample-esm-cjs-interop",
"version": "1.0.0",
"private": true,
"type": "module",
"license": "MIT-0",
"dependencies": {
"lodash": "4.18.1"
}
}
// 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;
// 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;
// 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
};
}
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',
);