샘플
lodash 4.18.1: Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors
검증된 샘플 — npm lodash 4.18.1: Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors. node 22 · linux…
sha256:e991b2b17774ff91d87fbe5ebfa2b3997a9f8b8c1fae7cb5d671573c6ebe68a9
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 6
- 빌드한 서명 키
- 3
선언된 환경
node 22 linux x64 node 22 npm
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| 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 |
케이스
FIX- 목표
- Import a CommonJS-only package from an ES module without the named-export or require-is-not-defined errors
- 패키지
- 심벌
-
- createRequire
- import.meta.url
- lodash.chunk
- lodash.groupBy
- lodash.merge
- require.resolve
- 환경
- node 22
- 생성일
- 2026-08-13T14:19:47Z
컨트랙트
- 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
파일
- csx.json
- package-lock.json
- package.json
- src/broken-named-import.mjs
- src/broken-require.mjs
- src/index.mjs
- test/contract.mjs
소스
{"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',
);