mocha: Bin exported without extension, breaks node's native loader picker and ts-node/esm
Description
custom loaders like ts-node have a really hard time figuring out the mocha “binary”
The binary lacks.js or cjs extensions. Changing the node_modules/.bin/mocha
extension isn’t enough.
Steps to Reproduce
- Sandbox: https://codesandbox.io/s/mocha-ts-node-16-ctt5k?file=/package.json
- Open Terminal
- Run
npm run broken-test-npx
or runsource env.sh; mocha test/test.js
OR
npm install ts-node typescript @types/mocha mocha
on atype: "modules"
project.json- Set
export NODE_OPTIONS="--loader ts-node/esm/transpile-only"
- Run
npx mocha test/any-test-at-all.js
Expected behavior:
No errors, tests run.
Actual behavior:
Setting a loader prevents node from running the mocha binary, in any way
$ npm run test # Copies mocha to mocha.js as workaround
3 passing (3ms)
$ npm run test-cjs # Copies mocha to mocha.cjs as workaround
1 passing (2ms)
$ npm run broken-test-npx # Node cant tell what loader to use and errors out
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for /sandbox/node_modules/mocha/bin/mocha
$ npm run broken-test-direct # same behavior as before
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for /sandbox/node_modules/mocha/bin/mocha
Reproduces how often: 100% of the time
Versions
- The output of mocha: 8.4.0
- The output of
node --version
: 14 (Sandbox) and 16 as well - Your operating system
- name and version: yes
- architecture (32 or 64-bit): 64
- Your shell (e.g., bash, zsh, PowerShell, cmd):
- Your browser and version (if running browser tests):
- Any third-party Mocha-related modules (and their versions):
- Any code transpiler being used (and its version): ts-node loader
Additional Information
Transpile only mode does not make a difference. Extension of tests do not make a difference. As long as the loader boots up, when node proceeds to guess which loader to use, node errors out.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 1
- Comments: 32 (20 by maintainers)
https://github.com/mochajs/mocha/issues/4645#issuecomment-854989395
^^ This is a fully backwards-compatible fix and takes little effort, right? I feel like there’s some confusion with talk of this being a breaking change, but it’s not. Is there anything we can explain further?
@juergba why are you against this? (or at least two
bin
entry points: one without an extension and one with it)This is a confirmed bug in nodejs. Please remind them that they need to fix it! I have cited mocha as one of the libraries being broken by it, but it will help if mocha’s users and maintainers also remind them (politely) that they need to fix this! https://github.com/nodejs/node/issues/33226
To reproduce the bug, use a completely empty
--loader
. This will prove thatnode
is responsible for the error, notts-node
nor any other loader.EDIT Fixed a typo above; the
node --loader
invocation was missing the./extensionless-entrypoint
ts-node 10.6.0 implements a workaround that hopefully mimics the bugfix which will eventually be published in node core. This means that, for users of mocha and ts-node, upgrading to the latest ts-node should avoid this issue.
https://github.com/TypeStrong/ts-node/releases/tag/v10.6.0
Yeah some tools have hardcoded paths to the extensionless JS file, so just as easy to keep it there and add an extension-ed file that requires it. (Or vice versa, either works)
On Thu, Jan 27, 2022, 1:27 PM Juerg B. @.***> wrote:
This is not true. Take a look at e.g. nanoid after installation with npm, there is a
bin/nanoid.cjs
but nobin/nanoid
.If you mean:
bin/mocha.js
results in :.bin/mocha
then I agree. Otherwise …?I can live with adding an additional
bin/mocha.js
requiring the naked one. The second binarybin/_mocha
is on sneaky deprecation, we should leave it as is.@JakobJingleheimer please go ahead with your PR, if you are still on fire. Otherwise we wait till Mocha@10.
Technically the execute bit tells Linux it’s an executable, and the two-byte sequence
#!
is a magic number understood by the Linux kernel, used to differentiate different binary formats. That’s my understanding at least.Package managers use https://www.npmjs.com/package/@zkochan/cmd-shim to generate
.ps1
and.cmd
shims that achieve the same effect on Windows.Yes, I’m 99% sure the historic reason is days of yore (unix/linux).
Note that adding the
.js
file extension would NOT be a breaking change as npm and yarn will automatically handle the extension-less part for you.Also, I’m completely confident that making the two tiny changes I suggested will 100% be compatible now and in future, wherever loaders lands 😉
@lachrist cough I am on the node team 🙂
There is a more recent discussion, but I’m not linking to it at the moment because I need to port it from a PR (that I need to closed) to an actual discussion.
@lachrist There is no loader option in Mocha.
Just use
'experimental-loader' : './lib/loader.mjs'
. Or with the alias name:loader: './lib/loader.mjs'
Edit: Mocha recognizes Node’s option and forwards them to Node by spawning a child-process.
I think if mocha wants to implement a simple fix, they can add a new bin entrypoint file with a file extension (make sure to keep the old one, too, for backwards-compatibility) and then point
package.json
"bin"
field to the new entrypoint with the file extension.I believe that update can be published as a non-breaking change.