Let’s be lazy:
repository on github
That’s the code for the starter repository.
Also made this repository a template repository
This p...
For further actions, you may consider blocking this person and/or reporting abuse
Hi @shnyder,
I am trying to do the CI/CD pipelining, so added this script into gitlab but it is getting failed. Please let me know if there any issue in script.
Hi @anil ,
what's the output of your gitlab build log?
In this post I tried to focus on the basic monorepo setup, to get a clean local dev environment with as many "defaults" as possible (so as little config as possible). It would be great to connect this post to a default config for a (gitlab) CI/CD-pipeline, so what's your experience with it so far?
Hi @anil
Do you achieve to do the CI/CD pipelining? I'm using gitlab too and i would be helpfull if you explain me what you did..
Thanks in advanced!
Hi @shnyder, first of all very very thanks for writing this, it is very clean, understandable and helpful.
I ran the script through github and it works perfectly fine, but now I want build my component using the React Material UI (material-ui.com/), so what is the best way to add this dependency?
Should I directly run the
yarn add @material-ui/core
in the root of the project? How it will add the dependency to storybook and cra app?Both, you can also use
yarn lerna add @material-ui/core --scope=@my-org/my-monorepo-ui-lib
at the root. In my experience it works well for single packages, if you want to add many it often doesn't.Then you can import material ui Components in your own component inside the UI lib, e.g.
and run
yarn story
for adjusting it in storybook. Because it's a sub-dependency of the UI lib package, you'll have it included when you run CRA withyarn start
as well.Very Very thank you for the quick reply, I tried it and it is working fine.
Can you please share how do I create the builds. Dev (minify with js map files) and Prod (complete minify) ?
Please suggest me something to achieve this.
Hello. Thank you so much for this very good article.
After install / bootstrap the dependencies using
lerna bootstrap
and runlerna run start --parallel
on the root folder, the CRA package complains like this:This is an old and known common error when starting with CRA: we shouldn't add
babel-loader
ANDreact-scripts
at the same time. But, yeah, I know thatbabel-loader
is there because ofmy-monorepo-ui-lib
package. So, I'm kinda stuck in this error... do you have any suggestion?Thank you so much for your time.
Hi Pedro,
I know it's a bit late, but with the update to react-scripts 4.x and storybook, this error should be gone. It came from a version-mismatch of the babel-loader, because CRA comes with one version, but the older storybook needed another one to function. Storybook has really shortened the list of dependencies it needs to run, and babel-loader is still in the dependency tree, but not explicitly.
and today it is back - this time complaining that CRA supports only 8.1 while the one installed was 8.2.2.
Hi Joe, thanks for pointing that out. I just fixed it by adding a
to the main package.json. That feature is not so old, and the version needs to be adjusted to the one in the CRA error message. That's unfortunately the situation for now, both storybook and CRA have open issues for that topic. I'm happy to accept Pull Requests or Issues once the version needs to be bumped again =) But I hope the underlying dependency-mismatch gets fixed
We could have used lerna without yarn workspaces as well here? Why they are being used together here? Please provide insights on same.
We're combining the benefits of the two: yarn workspaces does the package/dependency management on the level of the package manager, which you'd otherwise do with lerna's
--hoist
flag. You can execute some commands monorepo-wide with yarn workspaces as well. If you want to do that, here's a good article that does just that.However, lerna is a toolset that provides higher-level capabilities e.g. for diffing your packages' versions in different ways, so it reduces the difficulty of managing a monorepo. Here are some more details, and how performance is affected.
Doesn't
learna boostrap
do the hoisting for us, I was thinking? - bcoz I think it would shift the dependencies from individual package to root? but, it also doesnpm install
in all packages, I think.Thanks for this great article. Why do we have lib-esm and lib folders. What happens If I remove lib folder? Just curious.
we're building against two target versions of javascript, one with ECMA Script Modules ('esm'), the other with a (one of the) module system that existed before. When people start using your library, the different entrypoints to your lib that are defined in package.json make sure that you don't break compatibility. Check out the media coverage of the 'is-promise' library if you want to see what impact a change to the module system can have ;)
Hi @shnyder this is a great read and really helped me get my head around monrepo's.
I have followed all the steps and have a working project. However I have two small issues I hope you can help with:
1)
--stream
(or any other flag) doesn't work with "yarn lerna run start --stream", any ideas why this would be?2) I want to be able to change my components in the ui-lib and have the cra app update with them (currently I have to restart the server), is this possible? how would I begin to make that work?
What happens if i remove main from the package.json and just keep lib-esm and provide it's access via module? and then import this package in another package via import (and not require())? Will this fail in older browsers? hence, I must keep both lib and lib-esm? - Also, I read on the internet that main is used when we import this package using require() and module is used when we import it using ES6 import? is this correct? is this the only relevance of main and module? I don't think so though, but couldn't find more on it. Thank you!
yes, javascript has evolved over the years and since version 6 supports modules out of the box. NPM has started as a package manager for node.js, so there were module systems before ES6 that solved the needs of the backend more or the frontend. If you're using typescript I would go for import-statements instead of require(). You're saving yourself some time if you start building with typescript, let babel take care of downwards compatibility (Babel is what's used in create-react-app under the hood) and learn the details of the javascript ecosystem later on =)
so, I have package1 and CRA. CRA imports package1. and package1's package.json just have module: "lib-esm/index.js" and no main. and CRA is in typescript. So, when babel (which react uses internally) will build my code, will it also provide downward compatibility for the es6 code I had imported = package1 = available as ES6 and not ES3 bcoz I am only exposing "lib-esm/index.js"? - so, I can safely do this in my monorepo right? w/o worrying about browser compatibility issues when running my CRA app?
good question. I haven't tested your particular case yet, but I'd recommend having both module and main if your app is build against esm and before: The problem here is that it depends on which code babel runs on. If you're running a full build, then dependencies are baked (and minified etc) into the different chunks for your app. If you're just running in development, it might pull in modules, and you can run into problems for example when an es6-class (which is native to the browser) is extended like a non-native class (because js didn't always have classes). Somewhere I read a statement from the CRA team saying that they try to create builds for the largest common denominator of configurations (Browser/OS) out there - so that means ES6 modules and classes, because both are pretty standard now
Fixes for latest versions (triggered by version and dependency conflicts).
1) change react-scripts for both packages to 4.0.3
2) add "babel-loader": "8.1.0" to the root package.json file (cra complains when 8.2.2 is found in the root, but storybook will install its override and use it)
3) add "@storybook/addon-docs": "^6.1.17", to the storybook package package.json file
with those, the root commands started working for me.
I believe that the main culprit is "@storybook/addon-docs": "^6.1.17". If the next version increases the babel-loader version again, you'd have to bump that then. The "resolutions" field actually changes the dependency tree resolution, but it is just in the RFC phase now. I was actually hoping to make it work with other package managers, and I'm happy for any input in that direction
Hi @shnyder,
The component CSS files are not getting copied from
my-monorepo-ui-lib
tomy-monorepo-cra-app
. So I am getting this error.../my-monorepo-ui-lib/lib-esm/components/card/card.js
Module not found: Can't resolve './card.css
Thanks,
Anil
Since you're using Material UI, I recommend you have a look at how it does styling with JSS, their approach to theming, etc: material-ui.com/styles/basics/
The different approaches to bundling css for libraries would be a good topic for another blog post, I deliberately chose not to cover that here, to focus on monorepo-structure more. In the end, CRA will split your css in chunks when building. So the question is how your library users will consume that. If your CRA App is the only consumer, I'd recommend importing css only in the *.story-files, keeping it out of your components. In your CRA App, add an scss file that imports all the css you need, e.g.
@import "../../ui-lib/src/components/yourfile.css
. This is more a practical approach than a clean approach, but it separates concerns and will thus continue to work, even if there's a version update to create-react-app.If you want to publish your library, see which CSS-with-javascript combination you're using (JSS, CSS Modules, ...) and check for the recommended build process.
Hi everyone,
with the update to react-scripts and storybook some things are simpler in the template. I've included basic scss/css compilation as part of the library build process. CRA supports both out of the box, so it's better if the monorepo-template does so as well.
I'm surprised there is still so much interest, so I want to ask - what's your biggest pain point with monorepos? Which development tasks are still hard for you in the frontend?
...thinking about which article/template to write next
Hi, I don't need ui-lib I only have CRA-app. I am getting this error
qterra-app: $ react-scripts start
qterra-app: /Users/nbasiri/projects/mono-qterra/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js:231
qterra-app: appTsConfig.compilerOptions[option] = suggested;
qterra-app: ^
qterra-app: TypeError: Cannot add property noFallthroughCasesInSwitch, object is not extensible
qterra-app: at verifyTypeScriptSetup (/Users/nbasiri/projects/mono-qterra/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js:231:45)
qterra-app: at Object. (/Users/nbasiri/projects/mono-qterra/node_modules/react-scripts/scripts/start.js:31:1)
qterra-app: at Module._compile (internal/modules/cjs/loader.js:1133:30)
qterra-app: at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
qterra-app: at Module.load (internal/modules/cjs/loader.js:977:32)
qterra-app: at Function.Module._load (internal/modules/cjs/loader.js:877:14)
qterra-app: at Function.executeUserEntryPoint as runMain
qterra-app: at internal/main/run_main_module.js:18:47
qterra-app: error Command failed with exit code 1.
Can you please help how to fix this error?
Hi @shnyder,
This is a very good article and helping me a lot in understanding how to setup a Lerna, CRA, Typescript, and Storybook monorepo.
But one question I have, how would we incorporate pre-styled components into our Storybook? I would like to use Sass to give all of my shared components a default styling that could then be overridden by the client application if desired. So I'm assuming we would need to use Webpack at this point to build our lib directories instead of using tsc directly?
Sorry, thanks for your patience and time. I'm very new to front-end development and still trying to piece all the different technologies together.
Hi @FlatPenguin,
sorry for the late reply. If you're new to front-end development and don't want to use one of the
css-in-js
solutions have a look at theBEM-Notation
for naming styles. It helps you structure your styles early on, even if you don't follow it 100%. Withnode-sass
you can actually compile the sass into css and ship it with the rest of your library, so no need to ship scssWhat if I just keep
lib
and don't expose/createlib-esm
at all? - bcoz CRA is anyway getting transpiled by babel? hence, can do away withlib-esm
?Thank you
isn't
yarn lerna run test
equivalent toyarn workspaces run test
? - when to use what? and why should we use yarn workspaces at all if lerna is able to do all that for us?Hi @shnyder
I'd like to leverage intellisense with TypeScript and VS Code. With the current, it's building, but VS Code does not find the reference to the shared components.
did you build your most recent code as a library? When you run "yarn start" in the CRA-project it will look into your node_modules folder for a library build. There should be a symlink to your ui-lib-project folder, but the package.json of the UI-lib only tells the "outside world" where to find the main javascript and typescript-files that you've built, not the content of its /src-folder:
"main": "./lib/index.js",
"module": "./lib-esm/index.js",
"types": "./lib/index.d.ts",