-
-
Notifications
You must be signed in to change notification settings - Fork 498
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
Support async configs for scripts (fix #190) #196
Conversation
…, so that APIs like createJestConfig continue to work as before
Hi @spautz Thanks for the PR. I do have a few questions! 1- I haven't played with scripting for a while, i've been stuck in React components for the last year.... How does node scripts handle promises at the root? If the async code takes too long to return, won't the script terminate before the CRA code is executed? If you do have relevant documentation to refresh my mind, that would help a lot! 2- The config object is also loaded by a babel-jest transform script. Does babel-jest transform support async? Otherwise it would mean that CRACO offer partial support async and I am not sure I do like that. 3- Since start / build / test script now expect to await on a promise, does it still support a CRACO config returning an object literal? Thank you, Patrick |
It keeps the script alive until the promise finishes. This seems to apply to any promises or timeouts: it keeps the process alive even if there's an unreachable anonymous promise somewhere. Under the hood, I think it waits for the event queue to be empty: https://nodejs.org/api/process.html#process_event_exit says that exit will happen after "The Node.js event loop no longer having any additional work to perform".
I don't think it does: I played around with a few of the APIs under lib/, but trying to make them wait for the promise spiraled into a very large changeset -- and even if babel-jest supports promises, changing the craco functions to async would be a breaking change for anybody using them. I viewed this as being similar to the partial support for functions (where the caller has to resolve the config themselves before passing it to the craco function they want), but after looking at the code a little more I think (1) this is already not supported for the babel-jest transform script (i.e., a caller cannot pass in the config themselves when it requires the babel-jest transform), and (2) it may be possible to add support for both. Current behavior:
Proposal:
Does that seem reasonable?
It does, yes: the async/await automatically wraps the object literal in a promise. The start / build / test scripts should support object literals, functions, promises, or functions that return promises (so long as it eventually resolves to an object literal). |
I implemented the "function that takes a config and returns the transform" proposal in commit 52980fb (with a minor bugfix in f2080ca). It should now fully support async everywhere, and should also apply transforms if somebody passes a config directly to the API instead of using a file. That commit migrates the main body of I've tested this against my own project and a few test configs, but I'm not sure how rigorously to exercise the transform overrides. Are there any thorough test examples for the "override both |
Thanks, i'll have a look. Do you know of any popular projects who support async config file? To be honest, this does seem like a weird use case to me. |
Sorry, I haven't added any test coverage to the project. I usually create a sandbox locally and try a few use cases. |
Webpack is the one for my current situation: they've supported promises in config files since Webpack 2. https://webpack.js.org/configuration/configuration-types/#exporting-a-promise Jest supports promises (they have an async example for |
I tryed to run
craco.config.js is returning an empty object literal:
When I switchto CRACO master branch, everything works fine. |
Can you give any more information about your environment and what steps you're running? I was able to run each of the CRACO scripts in a a new boilerplate CRA without issue, using both Node 12 and Node 14. Here are the exact steps I did: what were yours?
I also tried it against the fork only (without first installing the current release of CRACO), using npm for everything instead of yarn (just to be certain), and by pointing the dependency in my-app at the actual path to the package on disk (instead of linking through yarn/npm). |
Hi @spautz Ended up working not sure what happened yesterday. I did the same steps as you did with Node 14.4. Have you tried the For the following craco config:
I get the following error message when running Jest:
|
…time. Transforms cannot be provided as functions -- only string paths to modules -- so instead of trying to generate a function from the config, the config is referenced from within the jest-babel-transform module. It's then used to generate the "real" transformer (one which honors the config).
After some research, I've learned I completely misunderstood the I've found a solution that seems to work, though, based on this comment -- but I'm worried it might be too hacky. What do you think? The basic idea: This is not too far off from how ts-jest's transformer does things: it uses Jest's config as a global space as well, and redirects to the |
Thanks for the investigating @spautz The proposed solution looks fine to me. As you said it's a bit hacky but this project IS A BIG HACK so it's fine haha. I'll run a few tests later tonight. |
packages/craco/lib/features/test/create-jest-babel-transform.js
Outdated
Show resolved
Hide resolved
// specifies. So, the first time this transform is run, it generates a new transform -- using cracoConfig -- and | ||
// uses that to process files. | ||
module.exports = { | ||
...createJestBabelTransform(), |
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.
What do you need this for? It is called without a craco config. Is it why you also load the craco config inside the transformer?
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.
This populates any other keys that babelJest.createTransformer
generates: in addition to process()
, they make a getCacheKey
function and set a canInstrument
prop. That's the only thing it's used for.
We could set all keys directly here -- it just seems possibly more future-proof to start with whatever babel-jest creates and override just the process()
. I can update it if you'd prefer. Or, for about the same work we could probably override all functions (i.e. have getCacheKey
do the same "generate and use jestBabelTransform from the config" that process
does), although in my tests it seemed unnecessary.
Did a few tests and it does work great! One last thing... could you also update the installation docs to showcase that a config file can return an async function? Thanks! |
I've updated the installation docs and made all the changes you commented on, except for the one left open (the question about calling I tested the latest change against the same configs I'd used before. |
Merged, thank you :) Will release tonight! |
This is intended to address issue #190, and it uses the same approach as was written there.
I added a second option for loading the craco config:
loadCracoConfigAsync
, which is exactly likeloadCracoConfig
except it returns a promise.loadCracoConfig
is unchanged, so it still works the same for the APIs that use it.With that addition, the built-in scripts (build, start, test) can support
craco.config.js
files which return a promise or an async function, while API calls likecreateJestConfig
work exactly like before (i.e. the caller has to resolve the config as an object.)This seemed similar to the "config might be a function" discussion in PR #195, so I tried to match that by adding validation that checks for promises.