-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
Meta: Native support for ES Modules #9430
Comments
I've landed very basic support with #9772. I've only tested the simplest cases, and there are many known limitations (most notably no |
25.4.0 has been released with the first pieces of support. In addition to #9772 mentioned above, I've also included #9842. In theory mixing CJS and ESM should work correctly now (🤞). The one main missing feature is supporting the I haven't written docs for this yet, but to activate it you need to do 3 things
Please try it out and provide feedback! If reporting bugs, it'd be wonderful if you can also include how running the same code (minus any test specific code) runs in Node. I've read https://nodejs.org/api/esm.html a lot over the last few weeks, but I've probably missed something. |
For the typescript use-case it is better to have an explicit import. |
Yup, I've added (and the temporarily reverted) a |
+1 for the explicit import, it's a bit more verbose but simpler to understand |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Can we add to Jest support for "main/module" fields in package.json? For example |
The module field is non-standard. Many bundlers (parcel, vite, etc) respect it but NodeJs for example completely ignores it. The new standard way of defining CJS and ESM endpoints is the (Note however that neither the |
@ChristophP Thank you for your answer, we discovered that Jest, despite the presence of "exports" field, does not understand the |
Great sounds good. Sadly a bunch of packages do not specify the exports field correctly and need to update. :-/ |
To speed up tests execution. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.759s ± 0.027s [User: 3.324s, System: 0.219s] Range (min … max): 2.690s … 2.870s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.815s ± 0.018s [User: 1.763s, System: 0.140s] Range (min … max): 1.775s … 1.904s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.668s ± 0.008s [User: 0.802s, System: 0.137s] Range (min … max): 1.643s … 1.689s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.755s ± 0.046s [User: 3.335s, System: 0.221s] Range (min … max): 2.675s … 3.044s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.815s ± 0.018s [User: 1.763s, System: 0.140s] Range (min … max): 1.775s … 1.904s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.642s ± 0.009s [User: 0.792s, System: 0.140s] Range (min … max): 1.616s … 1.682s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.755s ± 0.046s [User: 3.335s, System: 0.221s] Range (min … max): 2.675s … 3.044s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.815s ± 0.018s [User: 1.763s, System: 0.140s] Range (min … max): 1.775s … 1.904s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.642s ± 0.009s [User: 0.792s, System: 0.140s] Range (min … max): 1.616s … 1.682s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.755s ± 0.046s [User: 3.335s, System: 0.221s] Range (min … max): 2.675s … 3.044s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.815s ± 0.018s [User: 1.763s, System: 0.140s] Range (min … max): 1.775s … 1.904s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.642s ± 0.009s [User: 0.792s, System: 0.140s] Range (min … max): 1.616s … 1.682s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.755s ± 0.046s [User: 3.335s, System: 0.221s] Range (min … max): 2.675s … 3.044s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.815s ± 0.018s [User: 1.763s, System: 0.140s] Range (min … max): 1.775s … 1.904s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.642s ± 0.009s [User: 0.792s, System: 0.140s] Range (min … max): 1.616s … 1.682s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.751s ± 0.040s [User: 3.329s, System: 0.220s] Range (min…max): 2.692s … 2.861s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.785s ± 0.017s [User: 1.751s, System: 0.139s] Range (min…max): 1.750s … 1.834s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.657s ± 0.006s [User: 0.800s, System: 0.139s] Range (min…max): 1.623s … 1.679s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.751s ± 0.040s [User: 3.329s, System: 0.220s] Range (min…max): 2.692s … 2.861s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.785s ± 0.017s [User: 1.751s, System: 0.139s] Range (min…max): 1.750s … 1.834s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.657s ± 0.006s [User: 0.800s, System: 0.139s] Range (min…max): 1.623s … 1.679s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.751s ± 0.040s [User: 3.329s, System: 0.220s] Range (min…max): 2.692s … 2.861s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.785s ± 0.017s [User: 1.751s, System: 0.139s] Range (min…max): 1.750s … 1.834s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.657s ± 0.006s [User: 0.800s, System: 0.139s] Range (min…max): 1.623s … 1.679s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
In order to speed up test executions. hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t lint" Time (mean ± σ): 2.751s ± 0.040s [User: 3.329s, System: 0.220s] Range (min…max): 2.692s … 2.861s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t build" Time (mean ± σ): 1.785s ± 0.017s [User: 1.751s, System: 0.139s] Range (min…max): 1.750s … 1.834s 100 runs hyperfine --warmup 5 --prepare "nx reset && nx clear-cache" \ --runs 100 "nx run-many -t test" Time (mean ± σ): 1.657s ± 0.006s [User: 0.800s, System: 0.139s] Range (min…max): 1.623s … 1.679s 100 runs More: - https://docs.nestjs.com/recipes/swc#monorepo - nrwl/nx#11289 (comment) - jestjs/jest#9430 - https://npmjs.com/package/jest_workaround
Hi, I have a question: Is it possible to let Jest run in ESM mode when detecting Reference https://nodejs.org/docs/latest-v16.x/api/esm.html#enabling |
No, 'node esm flag' required to experimental (still...) modules VM API. Problem is not in detection, problem is how to execute module in VM context. |
EDIT: quick guide for getting started: https://jestjs.io/docs/ecmascript-modules
ESM support will be unflagged in a future release of Node 12 (maybe not before April nodejs/node#29866 (comment)) and it is already unflagged in Node 13.2, so I think it's time to evaluate how we can add native support in Jest. I'll try to list which features Jest currently provides that are impacted by ESM support, and how we can solve/investigate them.
There is issue #4842, but I think that's more of a discussion issue, while this issue will be geared towards actually implementing support and more suitable to track for those who just want to get the current implementation status. Any comments added to this issue not related to how we can implement support for the below enumerated features will be marked as spam - please direct any workarounds/discussions to separate issues. Also feel free to tell us if anything related to ESM features is missing from the list!
Please note that Jest will use the
vm
API (https://nodejs.org/api/vm.html) and as of writing (nodev13.6v16.10) the ESM parts of this API is still flagged (--experimental-vm-modules
). So saying ESM is unflagged is a bit of a misnomer at the moment. But I think we should start experimenting and potentially provide feedback to the Modules WG.EDIT: Tracking issue for stabilization in Node: nodejs/node#37648
Lastly, I'm writing this issue mostly for people who will implement support, so it'll be somewhat low-level and specific to how Jest works. For people who just want to know whether support has landed or not, I recommend using GH's wonderful "custom notification" and only subscribe to notifications on closing/reopening.
We achieve sandboxes by running a script within a given
vm.Context
(either provided by JSDOM or node core APIs). We need to do the same for ESM, but we'll need access to thecontext
during construction of the module, not just when executing the module. I've opened up #9428 which adds the necessary APIs toJestEnvironment
.expect
,test
,beforeEach
etc will still be added as globals, nothing should change here.jasmine
global will also still be here.jest
"global" propertyThis is not really a global - it's injected into the module scope. Since the module scope is gone in ESM, we need to move it somewhere. Adding it to
import.meta
seems natural - there's an option calledinitializeImportMeta
which we can use.EDIT: Solution here is to fetch it via
import {jest} from '@jest/globals'
. We might still add it viaimport.meta
in the future, but this should be enough for now.jest.(do|un)mock
Since ESM has different "stages" when evaluating a module,
jest.mock
will not work for static imports. It can work for dynamic imports though, so I think we just have to be clear in the docs about what it supports and what it doesn't.jest.mock
calls are hoisted, but that doesn't help in ESM. We might consider transformingimport 'thing'
toimport('thing')
which should allow hoisting to work, but then it's async. Using top-levelawait
is probably a necessity for such an approach. I also think it's invasive enough to warrant a separate option. Something to discuss - we don't need to support everythingjest.mock
can for for an initial release.PR: #10976
jest.requireActual
Not sure if how it should behave in ESM. Should we provide a
jest.importActual
and letrequireActual
evaluate inCJS
always?import.meta
Node has
url
as its only property (for now, at least). We need to make sure it's populated in Jest as well. We provideidentifier
instead offilename
when constructing the module so I don't think it'll happen automatically, buturl
is essentiallyfilename
passed thoughpathToFileURL
.There's also an open PR for
import.meta.resolve
: nodejs/node#31032import thing from 'thing'
This should actually be fairly straightforward, we just need to implement a
linker
where we can also transform the source before returning it, meaning we don't need the loader API (which doesn't exist yet). This allows us to return mocks as well (albeit they'll have to come from a__mocks__
directory).import('thing')
Essentially the same as above, but passed as
importModuleDynamically
when constructing the module. Will also supportjest.mock
,jest.resetModules
etc more cleanly, so likely to be used quite a bit.This can also be done for
vm.Script
via the same option.Right now it's a runtime error (e.g. module not found), but that's not necessarily true with ESM. Does it matter for us? We should verify errors still look nice.
module.createRequire
We need to deal with this for people wanting to use CJS from ESM. I've opened up #9426 to track this separately as implementing it is not really related to ESM support.
EDIT: Implemented in #9469
module.syncBuiltinESMExports
https://nodejs.org/api/modules.html#modules_module_syncbuiltinesmexports. Do we care about it, or is just making it a no-op enough? Not sure what the use case in Jest would be. Messing with the builtins is already breaking the sandbox and I don't think this should matter.
EDIT: #9469 made this into a no-op. I think that's fine?
Inspecting
type
field in a module'spackage.json
seems reasonable: https://nodejs.org/api/esm.html#esm_enabling. Should we also have our own config flag? Also needs to respect file endings.nodejs/node#49446
moduleNameMapper
Not sure if this impacts anything. I think not since we'll be linking the modules together ourselves. Needs investigation, though.
EDIT: This is all resolution logic, which we control. So no changes here.
jest.config.mjs
Through #9291 we support
jest.config.cjs
- do we need to do anything special for.mjs
? Probably useimport('path/to/configFile.mjs')
which means it'll have to be async. Is this an issue? Might be worth making config resolutionasync
in Jest 25 so it's not a blocker for incremental support of ESM in Jest 25.EDIT: #9431
Node supports package exports, which sorta maps to Jest's
moduleNameMapper
, but also provides encapsulation features. Hopefullyresolve
will implement this, but if they do not we'll need to do something. Might be enough to use thepathFilter
option? Unsure.EDIT: #9771
https://nodejs.org/api/esm.html#esm_experimental_json_modules. Do we need to care? Probably, especially for
json
. It's trivial for us to supportimport thing from './package.json'
since we control the linking phase, but we probably shouldn't do it by default as it'll differ from default node. Should we force people to define a transform for it?WASM: #13505
Does it matter? I don't think it's affected as we can still transform the source with babel (maybe it'll be confused by
import
statements, probably not) and V8 coverage definitely shouldn't care. We should verify though.This is absolutely no blocker as sync resolution will work just fine. But we can use async resolution now, which is great. I wonder if we should look into just using the
resolve
module off of npm again, as it already supports async. See #9505.Similar to above, not blocking, but would be nice to support it. Might make
@jest/transformer
more usable in other environments as well. See #9504.EDIT: #9889 & #11191
Due to #5163 we have the
extraGlobals
option as a workaround - that workaround is no longer viable in ESM. I've opened up and issue with node here: nodejs/node#31658https://nodejs.org/api/esm.html#import-assertions
The text was updated successfully, but these errors were encountered: