Node cjs esm mismatch
Skill viditkbhatnagar/immunize/src/immunize/patterns/node-cjs-esm-mismatch
A curated pattern library that stops AI coding assistants from repeating common runtime errors. No API key. No LLM calls at runtime.
npx -y skills add viditkbhatnagar/immunize --skill node-cjs-esm-mismatchAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when writing Node.js modules to keep CommonJS (require) and ES Module (import/export) syntax consistent within a single file and aligned with the package's module type.
SKILL.md
2.4 KB, as published. Nobody here has run it
node-cjs-esm-mismatch
Pick one module system per file and stick with it. Mixing
require(...) and import in the same Node module crashes at load
time:
ReferenceError: require is not defined in ES module scope
SyntaxError: Cannot use import statement outside a module
Node decides the module system per file by these rules, in order:
- File extension wins:
.mjsis always ESM,.cjsis always CJS. - Otherwise, the closest enclosing
package.jsondecides via"type": "module"(ESM) or"type": "commonjs"(CJS, the default).
Once a file is loaded as ESM, require does not exist. Once a file is
loaded as CJS, top-level import is a syntax error.
Example
Wrong — mixed syntax in a .mjs file:
// readers.mjs
const fs = require("fs");
import path from "path";
export function readFirstLine(filename) {
return fs.readFileSync(filename, "utf8").split(path.sep)[0];
}
Right — consistent ESM:
// readers.mjs
import fs from "fs";
import path from "path";
export function readFirstLine(filename) {
return fs.readFileSync(filename, "utf8").split(path.sep)[0];
}
Or consistent CJS:
// readers.cjs
const fs = require("fs");
const path = require("path");
function readFirstLine(filename) {
return fs.readFileSync(filename, "utf8").split(path.sep)[0];
}
module.exports = { readFirstLine };
When you actually need both
Inside an ESM file, import("...") (the dynamic-import expression) is
the only way to load a CJS module — never call require. Inside a CJS
file, you cannot synchronously load ESM at all; either rewrite the
caller as ESM or use top-level await with dynamic import() in a small
ESM bridge file.
Don't reach for createRequire
createRequire(import.meta.url) papers over the bug instead of fixing
it: it gives you a working require inside an ESM file, but downstream
tooling (bundlers, type checkers, the Node loader hooks) treats the
file inconsistently. Pick one module system and convert the rest of the
file to match.
Immunity note
The verification scans the fixture for require(...) calls in an .mjs
file. The repro mixes require with import and fails the assertion;
the fix uses import consistently and passes.