Skip to content
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

Please consider adding native support for ES modules #4842

Closed
kirlat opened this issue Nov 5, 2017 · 88 comments
Closed

Please consider adding native support for ES modules #4842

kirlat opened this issue Nov 5, 2017 · 88 comments

Comments

@kirlat
Copy link

kirlat commented Nov 5, 2017

Do you want to request a feature or report a bug?
I want to request a feature.
What is the current behavior?
Right now Jest does not support test suites with import statement. They result in the following error:

SyntaxError: Unexpected token import
      
      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
          at Generator.next (<anonymous>)
          at new Promise (<anonymous>)

What is the expected behavior?
Would be great if Jest supported ES modules natively.

Please provide your exact Jest configuration and mention your Jest, node, yarn/npm version and operating system.
Jest: 21.2.1
node: 8.9.0
npm: 5.5.1

Before, native support of ES modules was not possible since node.js did not support them. Starting from a few versions ago, node.js added support of ES modules with a flag (https://nodejs.org/api/esm.html). It would be absolutely great if Jest would match this with adding support of ES modules too, probably with a flag or even without it.

Node.js requires ES modules to have an .mjs extension. In order to support ES modules Jest needs to add a recognition of those extensions. Jest will also need to pass an --experimental-modules flag to node.js until node will implement support of modules without a flag. I'm not sure if any other required changes would be needed within Jest in order to support this. I can only hope it will not be terribly hard.

Ideally, it would be cool if Jest would recognize modules even in files without .mjs extensions since code that targets browsers do not use them, but I don't know if it is ever possible. Node.js provides loader hooks for that (https://nodejs.org/api/esm.html) but this still doesn't solve the issue with a reliable determination of what type of module the file is.

I believe ES modules are a great feature vastly superior to all existing JS module solutions. Having it implemented in node.js opens a door for Jest to have it too. This would allow developers stick to using the first truly standardized JS module format not only throughout development, but trough testing as well.

@SimenB
Copy link
Member

SimenB commented Nov 6, 2017

Jest has its own require implementation (https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/index.js), so it would be way more involved than just supporting the syntax and default to looking at .mjs. I'm also against activating experimental flags.

It might be possible to automatically transpile import/export, but implementing the semantics is a huge undertaking, and probably blocked for a year because of support for node 6.

@cpojer
Copy link
Member

cpojer commented Nov 6, 2017

I agree with SimenB. We need a number of hooks from the node team to be able to make this work together with the vm module. However, I think we should support this in the meantime, but not by mirroring the full native implementation but rather by using babel and compiling it to require inside of babel-jest. I think for testing purposes this will work fine and we do not have to provide the same guarantees the node runtime needs to provide anyway.

@SimenB
Copy link
Member

SimenB commented Nov 6, 2017

So just adding babel-plugin-transform-es2015-modules-commonjs & babel-plugin-dynamic-import-node to babel-jest?

@cpojer
Copy link
Member

cpojer commented Nov 6, 2017

Yeah, that's what I was thinking.

@TrySound
Copy link
Contributor

TrySound commented Nov 6, 2017

Guys, what about integrating https://github.com/standard-things/esm ? It's fast and maintain a lot of edge cases.

@cpojer
Copy link
Member

cpojer commented Nov 6, 2017

@TrySound what would that look like concretely? Can you make a prototype?

@SimenB
Copy link
Member

SimenB commented Nov 6, 2017

We still have our own require-implementation (needed for mocks), so I don't think that'd help much.

And we need to work both with Node's rules and the browser's rules.

I'd be very happy to be corrected and have it work perfectly for us :D

@SimenB
Copy link
Member

SimenB commented Nov 14, 2017

@std/esm apparently should just work with jest: https://twitter.com/jdalton/status/930257653292400640

Could anyone give it a whirl and come back with a PR for the docs? 🙂

@TrySound
Copy link
Contributor

TrySound commented Nov 14, 2017

I guess users would like to have support everywhere, but I found it works only for dependencies of test files.

// test.js
require = require('@std/esm')(module, { esm: 'js', cjs: true });
const utils = require('./utils');
// utils.js
export { default as update } from './update';

It's better, but not ideal.

@uipoet
Copy link

uipoet commented Nov 16, 2017

@gaearon
Copy link
Contributor

gaearon commented Nov 27, 2017

So just adding babel-plugin-transform-es2015-modules-commonjs & babel-plugin-dynamic-import-node to babel-jest?

I don't think this is a great solution, as it doesn't perform any "missing export" checks that are so valuable with ES modules. For example, in React repo I started running build more often just because Rollup finds these mistakes but Jest with es2015-modules-commonjs does not.

@std/esm apparently should just work with jest

It would be pretty great to invest some time into their interop. Pretty sure this hacky solution will break eventually: https://stackoverflow.com/questions/46433678/specify-code-to-run-before-any-jest-setup-happens. But if it's just a matter of exposing something on Jest side, would be cool to see it supported.

@awidjaja
Copy link

awidjaja commented Dec 9, 2017

@SimenB, in my mind the immediate step would not be too complex. What is urgent is to allow people to work with .mjs module, even if babel is helping behind the test scene. Otherwise people might have to find different testing solution if they want to use .mjs.

  1. Fix the testMatch property to allow .mjs file to be found
    (currently it doesn't work even the regex seems correct already, maybe there's a hard code somewhere rejecting .mjs extension)
  2. Pass --experimental-modules flag when running node.js so that it will run natively
  3. Jest should treat .mjs the exact same way as .js today (e.g. in jest require) -- the import statements are already allowed inside .js today, so only need to allow .mjs extension.

The final solution might be complex and takes time, but it is inevitable isn't it?

@jcguarinpenaranda
Copy link

Hello, has someone been able to fix this error?

@skkap
Copy link

skkap commented Feb 7, 2018

We are using .mjs with "node --experimental-modules" option. Any workaround?

@jdalton
Copy link
Contributor

jdalton commented Feb 7, 2018

We are using .mjs with "node --experimental-modules" option. Any workaround?

That's experimental and not fully fleshed out. There is lots of churn still with basic things, like how to import a builtin module, still up in the air. Projects like AVA have started allowing the use of @std/esm as their loader pipeline if used (bypassing Babel). Maybe jest could take a similar approach.

@SimenB
Copy link
Member

SimenB commented Feb 7, 2018

Supporting @std/esm is something we want to do, help to implement it is more than welcome!

@jdalton
Copy link
Contributor

jdalton commented Feb 8, 2018

@SimenB Can you chat sometime on hangouts?

@jdalton
Copy link
Contributor

jdalton commented Mar 23, 2018

Hi @SimenB 👋

An esm user has contributed esm + Jest demo and I figured it might be a good starting point for creating a more official cow path.

Update:

The esm + Jest demo has been updated with basic module name mapping support.

@SimenB
Copy link
Member

SimenB commented Mar 29, 2018

That's pretty cool! Thanks for sharing.

We'll have to figure out where we want the integration to be. How would it handle CSS (or other non-js assets) files? Should it just be a transform? What about the built-in babel transform? How should Jest behave when it comes to the incoming loaders, if it does affect anything?

@kenotron
Copy link

It seems like there may be a benefit for a community contrib esm-enabled alternate jest runner (or an unofficial / experimental flag) so we can make progress on something like that. Would there be interest in that from jest team?

@SimenB
Copy link
Member

SimenB commented Mar 29, 2018

require is not implemented in a runner, it's in the runtime itself. Any contributions towards making it pluggable is very much welcome (ref #848).

I'm sure if you can get the example code @jdalton linked to to work without issues (or close to it), it should be simple enough to load in the esm loader behind a flag in jest itself. One thing I see as an issue is that it wants the real module global, not the fake one we create. Not sure if it means modules can leak between tests? I don't know what esm does with it under the hood. It also doesn't handle mocks, so mocks with import would still break

@jdalton
Copy link
Contributor

jdalton commented Mar 29, 2018

May just need some tweaking of how Jest taps into CJS. For example when mocking the module object, instead of using a plain object, it could use require("module") and then wrap/overwrite module.require to intercept requests and juggle as needed.

Update:

I'm now working on enabling Jest out of the box with esm (with hopefully nothing Jest has to do differently). I'll continue to experiment over the weekend but early signs look good.

@JasonCust
Copy link

@jdalton Any update with the esm compatibility?

@jdalton
Copy link
Contributor

jdalton commented Apr 30, 2018

Hi @JasonCust, wow my comment has gotten some attention!

I have made progress in identifying the work needed to enable Jest support in esm. In my experiments I got Jest loading and evaluating tests written in ESM. The work required on the esm loader side is to make the way we handle vm.Script use more generic. At the moment we hook into that primarily for REPL use which assumes a single module. We have to make that a bit more generic for Jest support to shake out. It doesn't look like Jest will have to change anything. The refactor of our vm.Script support is still on my TODO and will still be tackled before I release things like experimental WASM support. At the moment I've been squashing bugs that have popped up around improved APM and mocking support.

@mcshaz
Copy link

mcshaz commented Apr 30, 2020

You'll need to transpile import/export until support lands, both user and library code

Any rough timetable on this?
from node 14 release:

It is our belief that the current implementation offers a future proof model to authoring ESM modules that paves the path to Universal JavaScript. Please read more in our documentation.

The ESM implementation in Node.js is still experimental but we do believe that we are getting very close to being able to call ESM in Node.js “stable”. Removing the warning is a huge step in that direction.

as such I am reluctant to export NPM packages (which may well be consumed by tests implementing the JEST testing framework) using commonJS for much longer.

@SimenB
Copy link
Member

SimenB commented Apr 30, 2020

We're shipping an experimental version from Jest 25.4. Quite a few bug fixes in 25.5, but it's still not where it should be. You can follow the progress in #9430

@woss
Copy link

woss commented Apr 22, 2021

wow, 1 year later after the last comment and still not working on "jest": "^26.6.3",

@nicolo-ribaudo
Copy link
Contributor

The discussion has been moved to #9430.

ESM support is being introduced in Jest 27, so even if today was "10 years later" it would still not be working on "jest": "^26.6.3".

@ambroiseRabier
Copy link

Got this issue with react-icons, my project use electron-forge webpack typescript template, well... I did not manage to make something work. The best work-around I found was... mocking the whole module : jest.mock('react-icons/all', () => 'sdf'). Not so great.

@github-actions
Copy link

github-actions bot commented Jun 6, 2022

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Jun 6, 2022
@yordis
Copy link
Contributor

yordis commented Jun 7, 2022

I think this could be close now, right @SimenB?

@github-actions github-actions bot removed the Stale label Jun 7, 2022
@SimenB
Copy link
Member

SimenB commented Jun 7, 2022

Yeah, we can probably do that. Support is mostly done on our side, documented at https://jestjs.io/docs/ecmascript-modules. Further work has been blocked for about 15 months in node itself: nodejs/node#37648

@wahengchang
Copy link

i m hanging here for the answer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests