Describe the bug
When the package is required from a CommonJS application (e.g. NestJS, or any Node app that uses require() or compiles to CommonJS), Node throws:
ReferenceError: exports is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '.../node_modules/fish-audio/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
at file:///.../node_modules/fish-audio/dist/cjs/index.js:16:23
So the CJS build (dist/cjs/index.js) is being executed as an ES module, and its CommonJS-style exports usage is invalid in ESM scope.
Root cause
- In
package.json you have "type": "module", so Node treats all .js files in the package as ES modules.
- The
exports field maps "require" to ./dist/cjs/index.js.
- When a CJS app does
require('fish-audio'), Node loads that file. Because of "type": "module", that .js file is interpreted as ESM, not CommonJS. The file content is CommonJS (exports.FishAudioClient = ..., etc.), so you get ReferenceError: exports is not defined.
So the CJS entry is shipped as .js inside a package that is fully ESM — that combination is invalid for CJS consumers.
Environment
- Package version: 0.1.0 (and any version with the same
package.json + CJS build layout).
- Node: 18+ (tested on current LTS).
- Consumer: Any project that uses CommonJS (e.g. TypeScript with
"module": "commonjs", or plain Node with require()).
Expected behavior
- CJS consumers:
require('fish-audio') should load the CJS build and run without errors.
- ESM consumers:
import 'fish-audio' / import('fish-audio') should continue to load the ESM build.
Suggested fix
Keep "type": "module" for the ESM build, but make the CJS build explicitly CommonJS so Node does not treat it as ESM:
- Output the CJS build with the
.cjs extension (e.g. dist/cjs/index.cjs), so Node always runs it as CommonJS regardless of "type": "module". Internal require() calls within the CJS build must reference the same .cjs files, or the build tool must emit/rename them accordingly.
- Point the
require condition in package.json to that file:
"exports": {
".": {
"require": "./dist/cjs/index.cjs",
"import": "./dist/esm/index.js"
}
}
Reference: Node.js — Determining module system: in a package with "type": "module", .js is treated as ESM; .cjs is always CommonJS.
Describe the bug
When the package is required from a CommonJS application (e.g. NestJS, or any Node app that uses
require()or compiles to CommonJS), Node throws:So the CJS build (
dist/cjs/index.js) is being executed as an ES module, and its CommonJS-styleexportsusage is invalid in ESM scope.Root cause
package.jsonyou have"type": "module", so Node treats all.jsfiles in the package as ES modules.exportsfield maps"require"to./dist/cjs/index.js.require('fish-audio'), Node loads that file. Because of"type": "module", that.jsfile is interpreted as ESM, not CommonJS. The file content is CommonJS (exports.FishAudioClient = ..., etc.), so you getReferenceError: exports is not defined.So the CJS entry is shipped as
.jsinside a package that is fully ESM — that combination is invalid for CJS consumers.Environment
package.json+ CJS build layout)."module": "commonjs", or plain Node withrequire()).Expected behavior
require('fish-audio')should load the CJS build and run without errors.import 'fish-audio'/import('fish-audio')should continue to load the ESM build.Suggested fix
Keep
"type": "module"for the ESM build, but make the CJS build explicitly CommonJS so Node does not treat it as ESM:.cjsextension (e.g.dist/cjs/index.cjs), so Node always runs it as CommonJS regardless of"type": "module". Internalrequire()calls within the CJS build must reference the same.cjsfiles, or the build tool must emit/rename them accordingly.requirecondition inpackage.jsonto that file:Reference: Node.js — Determining module system: in a package with
"type": "module",.jsis treated as ESM;.cjsis always CommonJS.