-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
esm entrypoint with named exports #4298
Conversation
ty @giltayar. I started fiddling with smoke-test even before I saw this PR... should probably get it done. there are other efforts in the works too by various individuals in the community |
We do have |
064b1c2
to
71e262d
Compare
@giltayar in the future, you can create branches in the |
@giltayar I've added the missing rewrote the smoke tests to install mocha from the output of |
71e262d
to
487e8ab
Compare
and rebased onto |
c655c1e
to
c905ec7
Compare
@giltayar does |
What you call "smoke test", I call E2E tests. Oh, well: testing terminology has always been a bit vague. In any case, my personal preference is for all tests to be part of the But anyway, thanks for adding the ESM smoke test and the missing |
Yes. I just checked it locally on a dummy module, and it works (it allows |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use npx ls-exports package mocha@latest
and compare to npx ls-exports path .
run inside this PR's working directory, and make sure you're not accidentally creating a breaking change.
I tried @ljharb's utility and got some strange results. So I played around with When running under Mocha, you get additional properties ( What should be done is to add both of them to the |
yeah running npm-pack-style tests locally would be good. was easier to hack it out in a shell script for now |
@giltayar if you find anything broken, please do file an issue :-) |
@giltayar errrr... hmm. upon further consideration, there are problems here:
I think we should carefully consider how we want to export APIs for ESM instead of trying to mimic what happens in CJS. Keep in mind, this is new code, so we're not going to break anyone. But, IMO, Alternative A// mytest.spec.mjs
import {describe, beforeEach, it} from 'mocha/bdd';
import {suite, suiteSetup, test} from 'mocha/tdd';
// etc with the documented caveat that you must run your code via Alternative BMake tests work via Alternative CDon't export anything other than what Thoughts? @nicojs @Munter @craigtaub @outsideris |
Thanks @coreyfarrell and @ljharb for looking at this |
Mocha is a great example of both the advanced flexibility and wanton abuse of Node.js' CJS module system. |
There is Option D: export all interfaces, and let the user choose whichever one they want, which is basically what they do today. I'm not sure how Mocha decides which ones to really export (I always used Moreover, it'll probably be the least surprising to users, who got used to doing |
I agree D will be the least surprising to users. But my preference is A as it introduces more clarity between the interfaces (both require the mocha executable). Also agree regarding B, having interface as point-of-entry bootstrapping the parsing + runner execution phases sounds like introducing more complexity, I feel we should only do this route if we see real value. |
I feel like there's either A or D. I personally would prefer D, because I like simple and unsurprising, but of course, whatever will be chosen, I will implement. My preference for D is also thinking about the future, where we'll be getting questions (StackOverflow and such) about why isn't |
Think thats a fair point. To counter my own argument, there aren't that many interfaces to muddle up, so do not think any added clarity is worth future confusion. Im happy with either A or D. |
To be very clear, if you want D:
I thought of another way. It would not require us to export things that are broken, however. Alternative E// or some other name
import {currentInterface} from 'mocha';
// in bdd mode
const {describe, it} = currentInterface();
// in tdd mode
const {suite, test} = currentInterface(); Functions can be dynamic. ESM exports can't. |
@giltayar yes, you can use the deprecated slash patterns to make it not be semver-major - i was assuming the preference would be to avoid deprecated features. |
subpath_folder_mappings is the one being deprecated. also available in V14: subpath_patterns |
7204d4b
to
22e5af8
Compare
I finally had the time to look at this. This is a real bug, but not necessarily in this PR. It uncovered a bug in ESM combined with On a machine with more than one CPU, run Now, run the same, but with an additional It's something around the connection between parallel and "lazyLoadFiles", but I haven't tracked it yet. My guess is that fixing this bug will also fix this branch's bug. Looking into it... |
The tests here fail due to a real bug: #4559 |
699bf85
to
9499f28
Compare
Finally! All tests have passed, and this PR also fixes #4559. |
Co-authored-by: Jordan Harband <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@giltayar I'm trying to understand this PR, but haven't got it yet.
Why do you insert package-lock.json into this PR?
@juergba From what I see in the commit, I just modified the file that was already there, which I'm assuming my |
I just added We have had quite a few dependencies updates in recent weeks. It helps to delete your |
When no dep changes are intended, any lockfile changes that appear should be discarded. |
@juergba It's because I used npm v7 (we switched to it at work about a month ago). Sp I reverted to the upstream This made Nice catch! And sorry for the confusion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@giltayar I haven't digested the complete matter, but my first impressions is, I don't really like it.
The starting point was, that below code is awkward:
import mocha from 'mocha'
const {it, before} = mocha
and we want (?) this: import {it, before} from 'mocha'
This PR goes too far and at the same time stops on half way.
Too far:
- IMO big effort/risk for small added value. I know you are an ESM maniac, but ... 😎
- do we really need parity between CJS and ESM, and then - even more complex - backwards compability for CJS?
- the fallback
"./": "./"
has gone - I haven't understood the proxy part. Does it belong into this PR?
stop on half way:
- we have more interfaces
- what are the consequences for third party interfaces?
- you export
unloadFile
(which makes no sense for ESM)- what about the rest of our public functions?
- what about private functions which are used by other packages (eg. collectFiles (?))
@juergba thanks for the input. Here are my responses:
I am! Hopefully, it's a compliment 😉. What I'm seeing in the ecosystem is more and more packages adding ESM wrappers (or, like SIndre Sorhus' packages, migrating all in into ESM). So is it a small value? Last year, maybe. This year, I don't think so. It's slowly becoming a baseline requirement.
Not sure I understand what you mean.
That's easy. I can easily put it back. There was input here that maybe we should go all in, and do it as a semver major that abolishes all "illegal" entrypoints into mocha. But if the sentiment is not to do it, I can very easily restore it.
Unfortunately, yes. When using parallel execution, and the number of workers is less than the number of test files, a worker can be reused for two test files. This exposes the fact that the
Ouch. I must have missed those. If you tell me what those are, I can easily add them.
I have no idea. I didn't know Mocha has this capability. Where can I find documentation (or an example of such an interface) so that I can try and figure out the implications?
Good catch. I'll remove it from the ESM exports.
I researched carefully, and this is what I found. I may have missed a spot. Which ones did I miss?
I could export them, but they are easily accessible (I think) as properties of the default export, no? I think that we should leave it like that. But if you think otherwise, tell me which, and I'll export them "legally". |
refering third party interfaces: see here in our wiki |
@juergba Thanks for the pointer. As far as I can tell, the third party ui interface functions will hang the interface functions on If they wish to have an entry point similar to what Mocha exports via this PR, then we can't do that for them, and they will need to do supply one on their own (outside of Mocha). This is because if we'd wanted to supply one, we'd need to:
BTW, the proxy part of this PR has been superseded by a much cleaner method to do the proxying in #4574 (thanks @nicojs!). Once that PR is merged, I will merge my PR and remove all the proxy code that won't be needed anymore. |
This PR hasn't had any recent activity, and I'm labeling it |
Description of the Change
Now that Mocha supports ESM test files, I found that importing Mocha in ESM files is awkward, if you're like me and don't like to rely on the
it
/before
/... globals. So, if you used to do this in CJS:You'd like to do this in ESM:
But you can't, because Mocha doesn't have an ESM entry point, and relies on the fact that CJS files can be imported, but only using default import. So you have to do this:
This PR exports an ESM entry point so that you can use named exports in a natural manner when importing Mocha itself.
The way it does this is to add an
exports
section to thepackage.json
, as described in the Node.js documentation for exports. This exports has a "conditional export" that defines separate entry points for ESM and CJS.Note that
exports
affects both ESM and CJS, so we should be careful (see ramifications below).Alternate Designs
There is no alternate design, as this is the only way to do what are called dual-mode packages in ESM.
Why should this be in core?
Well, where else can it be?☺️
Benefits
Importing mocha in a manner that is natural for ESM.
Possible Drawbacks
Based on the case of
is-promise
, theoretically this can break anybody using Mocha, because addingexports: ...
topackage.json
affects CJS too! It means that the only entrypoints allowed (in CJS and ESM) are the ones defined in theexports
.Which is why I added
"./": "./"
to theexports
, which says to Node.js: allow any deep importing such asrequire("mocha/foo/bar")
in the case that somebody, somewhere, is using that. This was also the solution used byis-promise
.But this has not been tested, as Mocha doesn't have an E2E test that checks that the package is OK. The way to write this test is to do an
npm pack
that creates atar.gz
, and then create a package that has as a dependency thattar.gz
, and then test whatever we want in there. This ensures that the package as a package (without the original source code) is OK. I did not add this test, as it feels way out of scope of this little addition.Applicable issues