-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
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
Add support for yarn and lerna monorepos. #3741
Conversation
Sorry, had to cancel the CI build because I'm working on fixing some test flakiness and need very quick feedback loop. Please remind me to restart the CI tomorrow (or push another commit in a few hours). |
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need the corporate CLA signed. If you have received this in error or have any questions, please contact us at cla@fb.com. Thanks! |
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks! |
Just realized that Issue 3031/PR 3435 isn't actually a prerequisite for this PR, so I've removed PR 3435 changes here which cleans up this PR considerably to focus it on Issue 1333. Notes: |
Sorry, had to cancel CI build again, please try in an hour or so |
f0f8f12
to
0dab8d2
Compare
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.
Please resubmit this against the next
branch and try to remove Jest-specific things that have been resolved in 22
// jest < 22.0.x transform patterns don't resolve symlinks, ie. don't match against realpaths | ||
// jest >= 22.0.04 matches against realpaths, but this method might be preferable anyway | ||
const babelProcess = babelTransformer.process; | ||
babelTransformer.process = (src, filename, config, transformOptions) => { |
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.
I'd prefer to remove this (and rely on Jest 22 behavior). After ejecting, the project is already complex enough. We should try to reduce the area for complexity that the user will have to maintain directly.
// | ||
// BELOW IS TO SUPPORT JEST TRANSPILING SOURCE FOR MONOREPOS | ||
// * JEST DOESN'T MATCH ON REALPATHS, BUT DOES WITH JEST >= 22.0.?, SO | ||
// THIS CAN BE REMOVED WITH JEST > 22.0.? |
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.
Please verify this?
// temp fix until JEST 22.0.0+ with realpath matching arrives | ||
// after ejecting, we can't filter using our custom babelTransform | ||
// ... with below, monorepo source won't transpile, so monorepos won't work | ||
// after ejecting |
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.
Same
packages/react-scripts/package.json
Outdated
@@ -42,6 +42,7 @@ | |||
"eslint-plugin-react": "7.4.0", | |||
"extract-text-webpack-plugin": "3.0.2", | |||
"file-loader": "1.1.5", | |||
"find-pkg": "^1.0.0", |
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.
Please pin the version.
// Use this instead of `paths.testsSetup` to avoid putting | ||
// an absolute filename into configuration after ejecting. | ||
const setupTestsFile = fs.existsSync(paths.testsSetup) | ||
? '<rootDir>/src/setupTests.js' | ||
: undefined; | ||
|
||
const toRelRootDir = f => '<rootDir>/' + path.relative(rootDir || '', f); |
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.
Can you explain more about why this block is necessary, what it does, and what happens on eject?
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.
toRelRootDir
itself converts a path to be relative to the jest string-literal <rootDir>
thing, producing strings like <rootDir>/src
and <rootDir>/../../cra-comps
. These are what end up in the ejected jest config and allow that static ejected jest config to work.
Much of the code below that is to include only tests from cra-comps in the monorepo that the app actually references via dependencies, rather than including tests from all cra-comps in monorepo. That was mostly a proof-of-concept -- my latest thinking is that is not the desired functionality, so that code should be removed. I'll start some more discussion on the desired functionality in the main comments area of this PR. I'll just remove the functionality/code for now and can re-add later if it's decided that functionality is desired, and I suggest we re-visit the code at that time.
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.
Sounds great!
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.
Does this need updating now?
We’re going to need integration tests around this. I don’t know what’s the best place to put them yet. Maybe worth setting up a separate end to end suite similar to the ones we already have. |
Was just about to ask where would be a good place to add tests for this -- a new e2e suite sounds like a good idea -- I'll start there. Also, I think it'd be helpful to have some info on source sharing in the user guide, so planning on adding something there. |
Open questions on desired functionality. Was hoping to generate some discussion in #1333 (comment), but hasn't gotten action so far, so I'll re-post those questions here, along with my preferences:
Would be really good to get input on these questions and generally have more feedback on how this should work. It's obvious many folks are wanting to share source in their cra apps ... maybe the initial implementation just needs to get out there, and then the feedback will come ?? :) |
How about we start with just supporting |
The initial feature probably should account for monorepos that use some non-CRA JS. Transpiling stuff that doesn't really need to be transpiled might not be a huge problem, but linting and testing could be issues: linting files that don't meet CRA lint, and picking up test files that match CRA file patterns, but aren't jest tests. Also, I'm not a fan of using 'packages' top-level -- to me it's a meaningless extra path I have to drill into to get to what I really want to see. So would prefer not to require that, but not something I'll quibble over. |
We can still start with that and later relax the requirement. It seems like there's many unknowns and it's easier to start stricter to learn about them.
Would a single monorepo always fall on one side or the other, or is it likely we'll have a mix? What are some common use cases for wanting to share lint/test/build pipeline, or not share it? |
If some code doesn't match CRA specs, can it be outside of the CRA monorepo? e.g. if we support CRA being in a monorepo. |
I have a monorepo that has both backend node services and frontend CRA apps, mainly because the backend and apps share some JS, but also just for managing the project. There's other stuff in the repo.
|
Fair enough. I think you have enough context to do good decisions here. How do you feel about writing up a more complete proposal where you make some opinionated decisions about how it should work, taking the existing project philosophy into consideration? |
I think the picture below describes the complete proposal.
|
5181797
to
c2e3f61
Compare
In your proposal, which |
Only the cra-apps. |
* Support for multiple source paths via package.json srcPaths entry. Initial support for yarn workspace. Support lerna workspace, fix for when to use template files. Remove support for specifying srcPaths in package.json. Re-enable transpilation caching. * Clean up, use file matching (similar to original) in webpack configs instead of matching function. * Remove package lock files. * Fix for eject. Note: monorepos won't work after eject. Can be fixed easily with JEST 22.0.?+ which has file pattern matches against realpaths. * Filter tests to run only tests in monorepo components included by the app. (Not sure this is desireable, might be cool to be able to easily run all tests in monorepo from one app.) * Fix conditions for when to use template. * Fix eject. * Remove code that is not needed w/ Jest 22. * Include all cra-comp tests in monorepo instead of trying to include only tests that are dependencies of app. (tests can be easily filtered via jest cli if desired, e.g. 'npm test -- myapp comp1') * Pin find-pkg version. * Hopefully fix jest test file matching on windows by removing first slash. * E2E tests for monorepo. * Run monorepo tests in CI. * Fix and test post-eject build. * Fix e2e test. * Fix test suite names in appveyor. * Include individual package dirs as srcPaths instead of top-level monorepo root. Fixes build/start after eject. * Fix running tests after eject. * Clean up test workspace, add some verifcations. * Cleanup. * Try to fix hang when running test on appveyor. * Don't write babel or lint config to package.json when ejecting. * Incorporate review comments. * Simply monorepo pkg finder * Only include monorepo pkgs if app itself is included in monorepo * Check for specific tests in e2e * Fixes for windows. * Fix for kitchensink mocha tests compiling. * Add lerna monorepo test. * Fix lerna bootstrap on windows. * Incorporate more review comments: * remove support for lerna w/o yarn workspace * add react and react-dom as devDeps to comp1 and comp2 * Add monorepo info to user guide.
From the documentation:
This all works pretty well, except for one thing. Transpiling what already is transpiled is bad idea - the linter breaks because it is not supposed to lint transpiled packages. |
Thanks for pointing this out. Has potential. I will also play a bit with this on the forked repo. I was thinking that the first very small step would be to just make sure that only private packages are added to I also I like your comment from parcel/pull#1101:
I still hesitate though for point (1): is it better to look for Actually our path to realise there is a problem was yet slightly different. We were trying to run all the jest tests in the mono repo from the root. So most of our packages are valid packages that are meant to be published at some point so they do have properly resolving Lastly, having something like In my current state of mind, I would like the most if we could run the tests from the root using just if (mono.isAppIncluded) {
Array.prototype.push.apply(module.exports.srcPaths, mono.pkgs);
} You can check it here: https://github.com/marcinczenko/create-react-app/commits/mono In this approach I am still not sure how to get the packages automatically rebuilding when their sources change - maybe this logic should belong to yarn workspaces. Sorry if something turns out to be inconsistent - I am still searching myself what would be the most reasonable approach. |
After playing around with react-scripts@2 in monorepo, I am more and more convinced that we should be very careful with the things like We use now the fork I mentioned in my previous comment (https://github.com/marcinczenko/create-react-app/commits/mono) and we are really happy with it. We can run all the tests in the monorepo from the root (including the tests of the apps created with create-react-app - we just need to add our own |
@marcinczenko I think the problem that you're experiencing with the current 2.0 implementation is that there is no way to opt monorepo packages out -- if your CRA app includes a package from the monorepo, it will be transpiled and linted. I think #4092 should solve that issue because it requires you to opt packages in by listing them in your app package's sourceDependencies. I think your 2.0 fork just disables CRA monorepo functionality, right? ... the effect should be the same when #4092 is implemented, as long as your app doesn't list any sourceDependencies. But, if there will still be a problem after #4092 is implemented, can you point it out so it can be addressed? Additionally...can you explain a bit more about how your solution is working to help others understand other ways to handle a monorepo? Eg, when you're working on your app and other packages in the monorepo at the same time, how do you rebuild other packages in the monorepo? Do you have a top-level script that kicks off watchers/builders for each packages? |
@bradfordlemley You're right. If the "to be managed by react-scripts" workspaces are only those that are explicitly white-listed in Just for the matter of completeness, currently, to my best knowledge, as soon as you have a single workspace including For the automatic rebuilding of the dependent workspaces: we did not make our minds yet, but we are thinking about. Currently, we just manually rebuild using lerna with scopes, and because all our packages are scoped, then this is just one command for all of them. I was thinking this: yarn knows which workspaces are there. Let's say that, by default, yarn does not automatically rebuild anything, but a given workspace could have in its "workspaces": {
"watch": ["sources"],
"watchScript": "yarn build"
} Or, maybe it calls Even if we have this functionality in yarn, then Let's take an example. Imagine you have a the following source-tree:
So, above, To summarize, I would expect the following semantics:
Does #4092 already distinguish between these three cases? I am not sure about the syntax, but what I like about this semantics is that it gives you flexibility and control. |
For the package2 case (has its own watch/build), it seems like it should "just work" (automatically update devserver) without having to specify it as source. I haven't tried that case, but I'm assuming it doesn't "just work" right now. I think it should be pretty straight-forward to make it work with a tweak to the devserver config. Do you see any problems with that proposal of making it "just work" without having to specify it as source? |
So it would also mean that we do not distinguish between |
Currently CRA reads package.json "main" field as the entrypoint. {
"name": "my-package",
"main": "src/index.js"
} I'd prefer something like {
"name": "my-package",
"source": "src/index.js",
"main": "lib/index.js",
"module": "lib/index.esm.js",
"browser": "lib/index.umd.js"
} It let me work on a package without using a babel watcher, but still compile the package before publishing. |
@alex-pex are you able to use an already transpiled package in an CRA app? I developp in a monorepo, some packages are really small so I import them in CRA app with: Now for some big packages, I wish to import them in my app already transpiled. But when I set in the imported package package.json file: Most of the time, I want to import packages not transpiled to benefit from tree shaking. But sometimes I wish to export it already transpiled so having an option to indicate which files to pull from package.json (either main or source as alex suggest woule be great). |
@trompx I'm currently using lerna + nwb. I transpile every package using a babel watcher, and use them in my app like a regular package. I need this setup because the package are also used by a different team (working on a separate app), and I publish versions for them, on a private repository. I didn't try but with CRA v1, but it should already work, except there is no automatic compilation. The problem here is how the source entrypoint is declared: using "main" conflicts with regular package (main should point to a compiled es5 version). I propose "source", as microbundle does https://github.com/developit/microbundle#specifying-builds-in-packagejson |
This reverts commit b43ad04.
* Support for multiple source paths via package.json srcPaths entry. Initial support for yarn workspace. Support lerna workspace, fix for when to use template files. Remove support for specifying srcPaths in package.json. Re-enable transpilation caching. * Clean up, use file matching (similar to original) in webpack configs instead of matching function. * Remove package lock files. * Fix for eject. Note: monorepos won't work after eject. Can be fixed easily with JEST 22.0.?+ which has file pattern matches against realpaths. * Filter tests to run only tests in monorepo components included by the app. (Not sure this is desireable, might be cool to be able to easily run all tests in monorepo from one app.) * Fix conditions for when to use template. * Fix eject. * Remove code that is not needed w/ Jest 22. * Include all cra-comp tests in monorepo instead of trying to include only tests that are dependencies of app. (tests can be easily filtered via jest cli if desired, e.g. 'npm test -- myapp comp1') * Pin find-pkg version. * Hopefully fix jest test file matching on windows by removing first slash. * E2E tests for monorepo. * Run monorepo tests in CI. * Fix and test post-eject build. * Fix e2e test. * Fix test suite names in appveyor. * Include individual package dirs as srcPaths instead of top-level monorepo root. Fixes build/start after eject. * Fix running tests after eject. * Clean up test workspace, add some verifcations. * Cleanup. * Try to fix hang when running test on appveyor. * Don't write babel or lint config to package.json when ejecting. * Incorporate review comments. * Simply monorepo pkg finder * Only include monorepo pkgs if app itself is included in monorepo * Check for specific tests in e2e * Fixes for windows. * Fix for kitchensink mocha tests compiling. * Add lerna monorepo test. * Fix lerna bootstrap on windows. * Incorporate more review comments: * remove support for lerna w/o yarn workspace * add react and react-dom as devDeps to comp1 and comp2 * Add monorepo info to user guide.
This reverts commit b43ad04.
* Support for multiple source paths via package.json srcPaths entry. Initial support for yarn workspace. Support lerna workspace, fix for when to use template files. Remove support for specifying srcPaths in package.json. Re-enable transpilation caching. * Clean up, use file matching (similar to original) in webpack configs instead of matching function. * Remove package lock files. * Fix for eject. Note: monorepos won't work after eject. Can be fixed easily with JEST 22.0.?+ which has file pattern matches against realpaths. * Filter tests to run only tests in monorepo components included by the app. (Not sure this is desireable, might be cool to be able to easily run all tests in monorepo from one app.) * Fix conditions for when to use template. * Fix eject. * Remove code that is not needed w/ Jest 22. * Include all cra-comp tests in monorepo instead of trying to include only tests that are dependencies of app. (tests can be easily filtered via jest cli if desired, e.g. 'npm test -- myapp comp1') * Pin find-pkg version. * Hopefully fix jest test file matching on windows by removing first slash. * E2E tests for monorepo. * Run monorepo tests in CI. * Fix and test post-eject build. * Fix e2e test. * Fix test suite names in appveyor. * Include individual package dirs as srcPaths instead of top-level monorepo root. Fixes build/start after eject. * Fix running tests after eject. * Clean up test workspace, add some verifcations. * Cleanup. * Try to fix hang when running test on appveyor. * Don't write babel or lint config to package.json when ejecting. * Incorporate review comments. * Simply monorepo pkg finder * Only include monorepo pkgs if app itself is included in monorepo * Check for specific tests in e2e * Fixes for windows. * Fix for kitchensink mocha tests compiling. * Add lerna monorepo test. * Fix lerna bootstrap on windows. * Incorporate more review comments: * remove support for lerna w/o yarn workspace * add react and react-dom as devDeps to comp1 and comp2 * Add monorepo info to user guide.
This adds support for lerna and yarn workspace monorepos, #1333.
There are some open questions as to how monorepos should work, so this is just a starting point.
Testing was performed with example and instructions at: https://github.com/bradfordlemley/cra-monorepo-examples
(Note: this PR pulls in changes from #3435 which is for supporting running create-react-app in a monorepo space.)