Similar to how there's an option to use "browser", it would be awesome to specify that Jest respect the "module" package.json field to resolve ES modules when using Babel with Jest.
Are you interested in shipping a PR with this? :)
Working on it right now :)
Awesome 馃槑
@thymikee would you mind reviewing that PR? I asked a few others but they seem to be busy.
Just wondering where we stand on this PR? Jest support for the "module" field would really help me out.
I submitted a PR and it was ignored for a while, so I closed it.
anyone can help unlock this freeze here? I聽am pretty much in the same situation than @probablyup and having this module
parameter is very helpful for mono-repo based environment such as lerna
@canercandan Had same case as you. Got around the issue by configuring Jest with a custom resolver
that remaps module
& main
fields: https://gist.github.com/loklaan/9fe7768576466c5a31c2e7af4cfdecd0
Until the fields become configurable, this is the only (?) way to do what you need. You might need to write this resolver anyway, if you end up enabling watched-compilation for interdependent packages in your repo.
@loklaan awesome thanks I聽will give it a try
@probablyup looks like the maintainers are still interested in merging if you want to re-open the pull request: https://github.com/facebook/jest/pull/2704#issuecomment-338410586
I鈥檓 currently away but might have some time to reboot the PR this weekend. If someone else wants to grab it that鈥檚 fine too.
This is a touch of a blocker for me. I'm using lerna to manage my repository. At present I need to run babel to build my dependencies and then run jest. Otherwise jest won't be able to find my import since the path in the main
key in package.json
doesn't exist until babel is run.
e.g. babel runs and generates files in lib
. If babel isn't run, then the module doesn't resolve.
in package.json:
{
"main": "lib/index.js",
"jsnext:main": "src/index.js"
}
I'm really excited about this PR as it will significantly speed up our test times.
FYI @dmk255 and others who might have the same setup:
I have a lerna setup as well with main
set to dist/index.js
in the package.json
files, while the source files are src/index.ts
.
Until this issue is resolved, I currently use the moduleNameMapper
option to remap @myscope/x
to <rootDir>/packages/x/src
in jest.config.js
:
moduleNameMapper: {
'^@myscope\\/([^/]+)': '<rootDir>/packages/$1/src',
},
@jeysal Thank you! That's a great idea. I actually use the projects feature in lerna so each project has its own jest.config.js
.
Due to this I had to tweak your example slightly (I also needed to exclude one package):
moduleNameMapper: {
'^@myscope\\/((?!config)[^\\/]+)': '<rootDir>/../$1/src',
},
So happy I found this thread. Ty @jeysal!
This would be great to mentioned in the jest docs. The Babel site that has a section dedicated for monorepo concerns. If there was mention made some where close to the --projects
config section, it'd probably help a lot of people out
Thanks @jeysal for the excellent solution! In my case I also had imports to subdirectories of packages in the monorepo, so I had to do the following:
moduleNameMapper: {
// Note that the order of these two is important!
'^@scope\\/([^/]+)\\/(.*)': '<rootDir>/../../packages/$1/src/$2', // import '@scope/package/sub/dir'
'^@scope\\/([^/]+)': '<rootDir>/../../packages/$1/src', }, // import '@scope/package'
}
Even though I think jest now does support the module
field, it doesn't support other main field names (which you can configure in webpack with the mainFields
option). So using this workaround works well if you want to use a field other than main
or module
.
Is this the code that needs to be changed to support this? https://github.com/facebook/jest/blob/master/packages/jest-resolve/src/defaultResolver.ts#L131
This feature is still definitely not supported.
Are there any plans on finishing this after 3 years?
Support ESM modules through the "module": "x/y/z.js"
field in package.json. (module > main)
See webpack which resolves it by default: https://webpack.js.org/configuration/resolve/#resolvemainfields
Great idea, thanks @jeysal!
Here's another possible mapping, for those who might have packages in nested directories.
For example if
@scope/package-a
is in /packages/components/a
and @scope/package-b
is in /packages/utilities/x/b
moduleNameMapper: {
'^@scope\\/([^/]+)': '@scope/$1/src'
//Turns your @scope/package to @scope/package/src
}
This might only work if you are already exposing the /src directory in the package.json alongside the /dist though... ie through "files": ["src", "dist"]
or something like that
Jest will never* support ESM through the module
entry in package.json out of the box, as it's not in any widely adopted spec and there are no guarantees it's actually ESM (e.g. a single usage of process
, require
, module
, __dirname
, __filename
anywhere will break), for much the same reason Node chose to introduce a new field rather than reuse it. ESM will be supported through the same way Node itself supports it (track #9430 for implementation status of native ESM support).
When it comes to how you as users can use the module
field, I think plugging in a custom resolver that uses resolve
and its packageFilter
like @loklaan did in https://github.com/facebook/jest/issues/2702#issuecomment-338071583 is the correct approach. That gist can be packaged up in a module and distributed on npm, and then in your Jest config you can say resolver: 'jest-module-field-resolver'
. Config wise as simple as module: true
except for a single yarn add
or npm install
first.
(the same can (should) be done for the browser
field, but removing it is potentially very breaking)
* of course things might change, but I highly doubt it
Note that the official way of supporting this in node is through conditional exports: https://nodejs.org/api/esm.html#esm_conditional_exports
When we support that (#9771) it might make sense to add an option to define "priorities" from that object so you could say you want browser
or some such.
Hi,
I hit this issue like the others and resolved by using @loklaan 's code as a customized resolver as Simen suggested.
Then, I created a npm repo as his suggestion. I hope it'd help others.
Thanks!
@makotoshimazu thank you so much for making that! Worked like a champ.
FYI, I still had to add the es module in question to transformIgnorePatterns
If I'm reading the code of jest-resolve
correctly, there is a problem with implementing a custom resolver: when running in watch mode, Jest will clean up the cache of the _default_ resolver on every run, but not the cache of a custom resolver.
Ideally the custom resolver could use options.defaultResolve
(as documented in https://jestjs.io/docs/en/configuration#resolver-string) to call the original resolver and preserve the cache functionality. But the original options.defaultResolve
does not pass all the options (specifically, it doesn't pass packageFilter
) to resolve
, so we can't map pkg.module
to pkg.main
In other words, I'd like to write a resolver like:
module.exports = ( request, options ) =>
options.defaultResolver( request, {
...options,
packageFilter: ( pkg ) => {
return {
...pkg,
main: pkg.module,
};
},
} );
But I don't see how it can be done without changing https://github.com/facebook/jest/blob/master/packages/jest-resolve/src/defaultResolver.ts#L42 to pass down options.packageFilter
thanks @scinos!
Most helpful comment
FYI @dmk255 and others who might have the same setup:
I have a lerna setup as well with
main
set todist/index.js
in thepackage.json
files, while the source files aresrc/index.ts
.Until this issue is resolved, I currently use the
moduleNameMapper
option to remap@myscope/x
to<rootDir>/packages/x/src
injest.config.js
: