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 Lerna and/or Yarn Workspaces #1333

Open
rovansteen opened this Issue Jan 1, 2017 · 113 comments

Comments

Projects
@rovansteen

rovansteen commented Jan 1, 2017

Are there any plans to support Lerna? By default Lerna uses the packages directory to store the packages. Right now the content of that folder is not transpiled so it's not possible to use ES6 code in there. It would be nice to have the possibility to use Lerna to create a monorepo application with create-react-app.

I've tried using the src directory with Lerna, but that conflicts with not ignoring node_modules directory inside the src directory, so it gives a ton of lint errors when you do so.

@rgbkrk

This comment has been minimized.

rgbkrk commented Feb 11, 2017

I'm using a create-react-app created app within a lerna monorepo and am quite pleased with it. Steps:

~/someRepo/packages$ create-react-app app
~/someRepo/packages$ cd ..
~/someRepo$ lerna bootstrap
~/someRepo$ cd packages/app
~/someRepo/packages/app$ npm run start

🎉

You can require your other packages by name within the create-react-app after adding them to app's package.json and running lerna bootstrap.

@gaearon

This comment has been minimized.

Member

gaearon commented Feb 11, 2017

This is pretty nice. Does Babel transpilation still work in this case though?

@rgbkrk

This comment has been minimized.

rgbkrk commented Feb 11, 2017

The individual packages under packages/ need to do a transpilation step. They'll be linked via lerna but the main entrypoints still need to be ES5.

@rgbkrk

This comment has been minimized.

rgbkrk commented Feb 11, 2017

I would prefer to not have to transpile all our packages when used in an overall app and yet I know that when we publish to npm we need them to be ES5-consumable.

@jedrichards

This comment has been minimized.

jedrichards commented Sep 7, 2017

For me the holy grail of Lerna support with CRA would look something like,

/web-clients
├── package.json
└── packages
    ├── api
    │   └── package.json
    ├── components
    │   └── package.json
    ├── cra-app-1
    │   └── package.json
    ├── cra-app-2
    │   └── package.json
    └── something-else
        └── package.json

The idea here is that we have a monorepo for web clients that can contain multiple CRA-based apps as peers that have access to a few shared other packages (e.g. a lib of shared presentational components, maybe a lib with some api calling utils, anything else). The CRA apps should be able to require code from the other packages and Babel should know to transpile such code coming from within the monorepo automatically.

Is this possible with Lerna and CRA at the moment? Any related issues or info I can look at?

@rgbkrk

This comment has been minimized.

rgbkrk commented Sep 7, 2017

While I'm no longer using create-react-app (using next.js), this is how we do it in nteract for various components and the notebook-preview-demo (the next.js app): https://github.com/nteract/nteract/tree/master/packages

@tbillington

This comment has been minimized.

tbillington commented Sep 8, 2017

Yarn added workspaces in 1.0 recently, don't know how it impacts this but thought it might be worth mentioning.

@ashtonsix

This comment has been minimized.

Contributor

ashtonsix commented Nov 29, 2017

@gaearon I've got babel transpilation working alongside Lerna in a private fork of CRA.

Add something like this to the end of /config/paths:

module.exports.lernaRoot = path
  .resolve(module.exports.appPath, '../')
  .endsWith('packages')
  ? path.resolve(module.exports.appPath, '../../')
  : module.exports.appPath

module.exports.appLernaModules = []
module.exports.allLernaModules = fs.readdirSync(
  path.join(module.exports.lernaRoot, 'packages')
)

fs.readdirSync(module.exports.appNodeModules).forEach(folderName => {
  if (folderName === 'react-scripts') return
  const fullName = path.join(module.exports.appNodeModules, folderName)
  if (fs.lstatSync(fullName).isSymbolicLink()) {
    module.exports.appLernaModules.push(fs.realpathSync(fullName))
  }
})

Webpack configs:

// before
{
  include: paths.appSrc
}
// after
{
  include: paths.appLernaModules.concat(paths.appSrc)
}

Jest config:

// before
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$'],

// after
transformIgnorePatterns: [
  // prettier-ignore
  '[/\\\\]node_modules[/\\\\](?!' + paths.allLernaModules.join('|') + ').*\\.(js|jsx|mjs)$'
]

Don't have the time to make a PR & add tests, comments, etc. but should be easy for someone else to do

@shendepu

This comment has been minimized.

shendepu commented Dec 26, 2017

Great!! @ashtonsix . I also have the lerna set up with CRA based on your code.

My folder structure is

lerna
  -- packages
      -- local package 1 (not published to npm registry)
      -- local package 2
      -- local package 3 
      -- local package ... 
      -- real app (created with CRA)
  -- lerna.json

For anyone else, the key for webpack in CRA app to transpile jsx is add lerna packages absolute path in include of babel-loader

BTW: I have it done without forking CRA, but used a mechanism to extend CRA webpack config, you may find more detail steps in #1328 (comment)

@bradfordlemley

This comment has been minimized.

Contributor

bradfordlemley commented Jan 11, 2018

I've created an example monorepo and PR 3741 that adds support for it.

monorepo
  |--packages.json: workspaces: ["apps/*", "comps/*", "cra-comps/*"] <-- (yarn workspace)
  |--lerna.json: packages: ["apps/*", "comps/*", "cra-comps/*"] <-- (lerna w/o yarn workspace)
  |--apps
    |--cra-app1 <-- basic cra-app, doesn't use any monorepo comps
    |--cra-app2 <-- basic cra-app, doesn't use any monorepo comps
    |--cra-app3 <-- uses some monorepo comps
      |--package.json: dependencies: ["comp1": <vsn>, "comp2": <vsn>]
  |--comps
    |--comp3 <-- not a cra component?
      |--package.json: main: build/index.js
      |--build/index.js  <-- don't transpile?
      |--index.js
      |--index.test.js <-- don't test?
  |--cra-comps
    |--comp1 <-- standard-ish cra component with JSX
      |--package.json: main: comp1.js
      |--comp1.js
      |--comp1.test.js
    |--comp2 <-- cra component with dependency on other cra-comp in monorepo
      |--package.json: dependencies: ["comp1"]
      |--comp2.js: import comp1 from 'comp1'
      |--comp2.test.js

I assume that it is agreed that cra-comps should be transpiled just like app src (including JSX) since that seems to be the request from above comments, but some further questions about desired functionality:

  1. Which (if any) tests from cra-comps should run when running app tests? (only comps that the app specifies as dependencies?)
  2. Should files from cra-comps be linted when building app?
  3. Should a directory structure be enforced for cra-comps? (e.g. files need to be under /src)
  4. How to flag components that should not be treated as cra-comps? (or should cra-comps be by convention, e.g. well-known directory in monorepo?)

Is this the correct place to try to get the answers for those questions?

@bugzpodder

This comment has been minimized.

Collaborator

bugzpodder commented Nov 13, 2018

@MikeSuiter set main field in package.json to make regular imports work: import App from 'wp-core/containers/App
https://github.com/bugzpodder/yarn-workspace-cra/blob/master/common/package.json#L4

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 13, 2018

@bugzpodder We already have an existing app that is pretty big and looking to move it to workspaces so we can share code with new apps we need to develop. Since we already import using import EditorTab from 'containers/Process/EditorTab'; it would be nice to keep it that way. Also, we have several components with the same name so importing deep is safer. This is a sample of our structure.

packages
  containers
    Process
      EditorTab
        index.js
      HomeTab
        index.js
    Job
      EditorTab
        index.js
      HomeTab
        index.js
    Script
      EditorTab
        index.js
      HomeTab
        index.js

I took your yarn-workspace-cra app and tried a few things. Move your common/src/index.js to common/src/Test/index.js and make a new common/src/index.js that contains this:

export { default as Test } from './Test';

Now try these three ways to import in admin/src/App.js. In my code the way I want to do it (2nd line) fails.

import { Test } from 'common'; // Works
import Test from 'common/Test'; // Fails
import Test from 'common/dist/Test'; // Works

Another thing I haven't been able to figure out is how to get Chrome to use the source code instead of the transplied code. Put a debugger in Test.render() and Chrome will show the transpiled code in the debugger.

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 13, 2018

@alistair-hmh Yeah maybe I should think about using just an index.js and only exporting/importing from that. Since our current code is a big CRA all under src, we currently have only full folder-style imports. Also we don't plan to publish anything under packages - it is in a monorepo.

In our real code we are using @company/package.

I did make a cra2-ga branch of the repo I made above if you want to look at it. This is my POC for what we're doing in our real app.

https://github.com/MikeSuiter/cra2-alpha-yarn-workspace/tree/cra2-ga

PS - I think you can get rid of packages in lerna.json if you have them defined in package.json (yarn workspace). That will save some duplication.

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 13, 2018

@alistair-hmh I just figured out how to get IntelliJ IDEA to go to the src folder instead of dist when doing a ctrl-click

  "main": "dist/index.js",
  "jsnext:main": "src/index.js",

I didn't know if this might help you with what you posted above:

#1333 (comment)

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 14, 2018

@alistair-hmh Do you have it where you only have to build you CRA app and it automatically builds the packages? If you are do you have a repo that demos it?

@alex-pex

This comment has been minimized.

alex-pex commented Nov 14, 2018

#1333 (comment)

Option 1 is not applicable as we use the scope to publish private packages

@alex-pex

This comment has been minimized.

alex-pex commented Nov 14, 2018

#1333 (comment)

Some docs about jsnext:main and module : https://github.com/rollup/rollup/wiki/pkg.module

pkg.module will point to a module that has ES2015 module syntax but otherwise only syntax features that the target environments support.

It shouldn't be used to point at src/index if src/index need to be transpiled


Packages like microbundle use a "source" field

https://github.com/developit/microbundle#specifying-builds-in-packagejson

@nloding

This comment has been minimized.

nloding commented Nov 14, 2018

I don't understand what I'm missing with my repo setup, but unfortunately I can't share much because it's all private/proprietary code. I cloned @FelixKuehl's cra-monorepo repository to start, but I cannot reference any packages, it just says it cannot resolve the module.

Here's the rough setup:

- packages
  |--> ui (name: @myapp/ui)
- web
  |--> client (CRA2 app, dependency on @myapp/ui)

No matter what I've done - build, watch, start, etc., the client throws an error that it cannot resolve @myapp/ui.

@nloding

This comment has been minimized.

nloding commented Nov 14, 2018

@alistair-hmh I finally made progress, but I don't like it. Not sure what step I'm missing. I have to import from the src folder. import { Component } from '@myapp/ui/src/Component' even though in my src/index.js file I'm exporting Component. I should note that @myapp/ui is a CRA2 app as well, that is using styleguidist to document the components.

@nloding

This comment has been minimized.

nloding commented Nov 14, 2018

@alistair-hmh @MikeSuiter I think I'm officially dumping CRA due to all this nonsense. It's a nice tool for some workflows, but not for mine. It's time for me to start my own, and I'm using this as my starting point: https://github.com/bradfordlemley/create-react-app

When the monorepo/workspace changes were pulled from the CRA2 release, the guy who did the original PR created a fork that he's maintained. I'm just going to eject from that and build from there.

@nloding

This comment has been minimized.

nloding commented Nov 14, 2018

I linked to it in my comment.

@bradfordlemley

This comment has been minimized.

Contributor

bradfordlemley commented Nov 14, 2018

FWIW, I would recommend trying to stay on the path that the CRA maintainers are laying out, if possible.

It seems like @bugzpodder 's example monorepo is the current recommended approach. I don't think that approach will be able to offer quite the same dev-friendly experience as CRA-integrated monorepo support as what was in CRA 2 alphas, but let's try it and see.

It would be helpful to have a more official best-practice monorepo example (including how to test the whole monorepo) to help folks get going and be something that the community can contribute improvements toward.

@bradfordlemley

This comment has been minimized.

Contributor

bradfordlemley commented Nov 14, 2018

From #5024:

We're going to revert monorepo support in favor of consuming library packages via nwb and provide excellent documentation on how to do so.

@nloding

This comment has been minimized.

nloding commented Nov 15, 2018

@bradfordlemley I'll give that example a shot, but my concern is what @alistair-hmh mentioned above - delay for transpiling and hotloading that didn't exist in the CRA alpha

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 15, 2018

Should be simple enough to wrap that pkg config and workspace paths resolver into a CRA fork - and create a POC monorepo. If anyone is interested in seeing it working in a re-usable way like that, let me know.

@alistair-hmh I would love to see a CRA fork and POC monorepo. One gripe I have with the Babel way in packages is I haven't been able to figure out a way to debug src in packages - only the transpiled code.

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 15, 2018

BTW @alistair-hmh I'll update and cleanup my original cra2-alpha-yarn-workspace that currently works with CRA2 alpha if you want to use that as a test or starting point for your POC monorepo.

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 15, 2018

@alistair-hmh I updated my repo that currently works with CRA2 alpha and it has an app that uses dependencies from packages and also a standalone app. There is a core package that has a dependency on a shared package. Everything seems to be working great!

Some notes:

  • I moved most of the dependencies to the root package.json which is nice so you can update in one place instead of having to in each app/package
  • package.json in the packages are minimal
  • Running tests on the app also runs tests in packages
  • Each app and package needs its own lint script
  • I made a mix of functional and class components
  • Debugging in the packages shows the source code in Chrome
  • app-shared/index.js uses the react-hot-loader so the entire page doesn't reload on changes
  • The root package.json has several convenience scripts

Take a look at it and let me know if you want me add anything else added to it. Hopefully it will give you a good starting point for testing your CRA2 fork. When you do try to add your CRA2 to it you'll need to update the browserslist as it has changed since the alpha.

  "browserslist": [
    "> 0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]

https://github.com/MikeSuiter/cra2-alpha-yarn-workspace

@nloding

This comment has been minimized.

nloding commented Nov 15, 2018

@bugzpodder or @bradfordlemley or @alistair-hmh - trying the suggestion of using bugzpodder's repo (https://github.com/bugzpodder/yarn-workspace-cra) instead of Bradford's CRA fork. Going to give it a solid go ... except I have one quirk in my setup and curious if anyone of you have a suggestion, using that repos setup.

One of my packages is a CRA app itself, using Styleguidist to document all my lovely components. In the example repo, the entrypoint is listed as dist/index.js and the start command builds it and sets a watcher. That's different than how CRA's default start command works.

Development works (for now) setting the entrypoint on this library to src/index.js - but I'm not sure that's going to give me the right results in the end, especially when I go to build it.

Any thoughts?

@bugzpodder

This comment has been minimized.

Collaborator

bugzpodder commented Nov 15, 2018

@nloding styleguidist allows your own webpack config in styleguidst.config.js

module.exports = {
  webpackConfig: {
    module: {
      rules: [
        {
          test: /\.jsx?$/,
          exclude: /node_modules/,
          loader: require.resolve("babel-loader"),
        },
        ....
  },
 resolve: {
      alias: {
        "@foo/components": path.resolve(__dirname, "src"),
      },
    },
@bugzpodder

This comment has been minimized.

Collaborator

bugzpodder commented Nov 15, 2018

Yes, to test you'll need to do yarn link react-scripts or yarn create-react-app: https://github.com/facebook/create-react-app/blob/master/package.json#L9

@nloding

This comment has been minimized.

nloding commented Nov 16, 2018

@alistair-hmh very simple setup. Also seems incredibly easy to accomplish with react-scripts-rewired. How do you toggle between src/index.js and dist/index.js though?

@nloding

This comment has been minimized.

nloding commented Nov 16, 2018

@alistair-hmh perhaps I'm confused on your development: true and production: true settings in the package.json. When I push my master branch up for my CI/CD pipeline to build and deploy, how does it deploy the production bundles?

@nloding

This comment has been minimized.

nloding commented Nov 16, 2018

Why would you build with workspaces off if you're using workspaces?

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 16, 2018

@alistair-hmh I cloned your CRA fork and POC and get an error when trying to run the POC.

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS D:\Workspaces\React\cra-workspaces-support-1333> yarn install
yarn install v1.12.3
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.2.4: The platform "win32" is incompatible with this module.
info "fsevents@1.2.4" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning "workspace-aggregator-0ccba57c-2f4a-42b1-ae94-ddcf51bced8f > @project/comp-one > babel-eslint@10.0.1" has unmet peer dependency "eslint@>= 4.12.1".
warning "workspace-aggregator-0ccba57c-2f4a-42b1-ae94-ddcf51bced8f > @project/comp-one > babel-loader@8.0.4" has unmet peer dependency "webpack@>=2".
[4/4] Building fresh packages...
success Saved lockfile.
Done in 33.86s.
PS D:\Workspaces\React\cra-workspaces-support-1333> cd .\packages\apps\app-foo\
PS D:\Workspaces\React\cra-workspaces-support-1333\packages\apps\app-foo> yarn link react-scripts
yarn link v1.12.3
success Using linked package for "react-scripts".
Done in 0.13s.
PS D:\Workspaces\React\cra-workspaces-support-1333\packages\apps\app-foo> yarn start
yarn run v1.12.3
$ react-scripts start
Starting the development server...
Failed to compile.

./src/App.js
Module not found: Can't resolve '@project/comp-two' in 'D:\Workspaces\React\cra-workspaces-support-1333\packages\apps\app-foo\src'

I decided to try my CRA2 POC with your CRA2 fork which is a little more complicated than your POC and also has a PureComponent class which fails. Our current CRA 2.1.1 app uses static propTypes and doesn't get this error.

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS D:\Workspaces\React\cra2-alpha-yarn-workspace> cd .\apps\app-shared\
PS D:\Workspaces\React\cra2-alpha-yarn-workspace\apps\app-shared> yarn link react-scripts
yarn link v1.12.3
success Using linked package for "react-scripts".
Done in 0.12s.
PS D:\Workspaces\React\cra2-alpha-yarn-workspace\apps\app-shared> yarn start
yarn run v1.12.3
$ react-scripts start
Starting the development server...
Failed to compile.

D:/Workspaces/React/cra2-alpha-yarn-workspace/packages/core/components/Header/index.js
SyntaxError: D:\Workspaces\React\cra2-alpha-yarn-workspace\packages\core\components\Header\index.js: Support for the experimental syntax 'classProperties' isn't curre
ntly enabled (8:20):

   6 | 
   7 | class Header extends PureComponent {
>  8 |   static propTypes = {
     |                    ^
   9 |     title: PropTypes.string.isRequired
  10 |   };
  11 | 

Add @babel/plugin-proposal-class-properties (https://git.io/vb4SL) to the 'plugins' section of your Babel config to enable transformation.

I just updated my POC to 2.1.1 if you want to try it with your CRA2 fork and see if you get same error.

https://github.com/MikeSuiter/cra2-alpha-yarn-workspace

BTW - if you prefer I post stuff specific to your CRA2 fork in that repo let me know.

@nloding

This comment has been minimized.

nloding commented Nov 16, 2018

@alistair-hmh I guess I personally don't see a case where you're working in the monorepo and using the dist build just because another team has pulled in that component via a registry (bit, npm, whatever). As long as when I do yarn build in my monorepo, everything is built using the production configs ... what's the difference?

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 16, 2018

@alistair-hmh Two of us here, one on Mac and one on Windows, have followed your instructions on the POC app and both of us get this:

Failed to compile.

./src/App.js
Module not found: Can't resolve '@project/comp-two' in 'D:\Workspaces\React\cra-workspaces-support-1333\packages\apps\app-foo\src'

I'm also getting the same error on my CRA2 POC.

@ljharb

This comment has been minimized.

ljharb commented Nov 16, 2018

A lot of people are subscribed to this issue; perhaps you could discuss issues with your fork or POC, in an issue on your repo?

@nloding

This comment has been minimized.

nloding commented Nov 16, 2018

I second @ljharb - and I'd also say this issue should be abandoned here. The CRA maintainers have said they are favoring the approach of using nwb are working on documentation for that. Anything else, I would guess, is going to exist purely as a fork or a package that overwrites configs (a la react-scripts-rewired).

I have @alistair-hmh's code working with react-scripts-rewired and it seems pretty smooth so far. I have to rewire some CRA code anyway (my app needs to output a second entry point), so this is convenient for me. Feel free to @ me in another thread!

@nloding

This comment has been minimized.

nloding commented Nov 16, 2018

@alistair-hmh I'd suggest reading through the comment thread that was already linked - there's discussion there regarding CRA, why it dropped monorepos, and why they mentioned nwb; afaik that's all the "documentation" there is at this point: #5024

@MikeSuiter

This comment has been minimized.

MikeSuiter commented Nov 19, 2018

What would be nice at this point if someone from the CRA team would post what the status of supporting monorepos is. Do they still plan on going the nwb route with documentation and when can we expect to see it?

There are a lot of people interested in using CRA with monorepos so code can be shared among apps and several of them have posted what they've tried to do. One thing that is common with all the attempts to support monorepos with CRA is they work but not with the experience people want. What we currently have working is a decent solution but then there are annoyances like not being able to debug source code (debugging transpiled code is ugly).

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