31

Why and how we made our react monorepo

 5 years ago
source link: https://www.tuicool.com/articles/hit/FFNnErZ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
YJJVjiB.jpg!webrENNBbb.jpg!web

Preface

The goal of this article is to explain why you would want to adopt a monorepo approach for your React components and solidify the use cases where it would be helpful. It is not a step-by-step guide and does not include a real-world implementation or workflow. If you want to see a detailed post on how to introduce a monorepo into your project, leave a comment below letting us know you’re interested!

Intro

When working with React, there comes a time when you want to reuse your components on different pages or for different projects. At first, everything seems fine. But after a while, you’ll need to change a prop or make a breaking change in one component but you don’t want/can’t go to every project and fix all the references in a timely manner.

That’s when you start to look for solutions to this problem and you discover the magical word—“Monorepo”. In this post, I am going to review some concepts and use cases you need to know when adopting a monorepo strategy for your shared UI components library using React as the UI library and Lerna as our monorepo orchestrator.

Why

One of the major problems, when you start to share code with other projects (repos), is to keep compatibility when making changes or adding new functionalities. Most occasions you don’t have the time to track down all the references to the component you are maintaining and fix them all, or you don’t even know they are being used in that particular app.

That’s where versioning becomes super important to allow your team to move forward with confidence and the monorepo approach lets you version your components independently. I will share some of the use cases in which monorepos excel.

Common Problems

Updating a component

Let’s take a simple example where having independent versioned components will save your life. In this example, we have an Avatar component:

EriIbqj.jpg!web

Then we made a few changes:

EriIbqj.jpg!web

What changed:

  • Style prop doesn’t exist anymore ( This is a hard breaking change )
  • Hovering the component blurs the image ( This is a soft breaking change )
  • A placeholder image is now inserted if imageUrl is not provided ( This is a behavioral change )

What we need to do now:

  1. Update every place that was using the old Avatar component within the library
  2. Card component uses Avatar so we need to update the calls on Card
  3. What about two or more levels of dependency? What if we had these dependencies:
    Avatar -> Card -> Profile
    Avatar -> Card -> Sale Widget
    Avatar -> Instructor bio -> ???
  4. Keeping track of all dependencies is hard
  5. We may or may not want the new changes/behaviors in some pages/components but we need to update all references
  6. Tons of conflicts when merging this new code
  7. The list goes on and on…

Dependency Changes

Another big use case is when dependencies need to be updated. We had React 15 as our main React version. Without a monorepo, if we wanted to update to React 16, we needed to update all the components to be compatible because some of them had breaking changes (while others did not).

In the monorepo approach, each package has its own dependency tree so you can update Package A to React 16 and keep Package B in React 15 and you can start using the newest version immediately.

One of the most common problems is with smaller packages like modal libraries— as the request/response libraries will get updated with breaking changes and you’ll need to fix/update ALL your components.

A Better Approach

If you find yourself in one of these scenarios, a monorepo might be a good idea for your team.

Using a monorepo, you could have Avatar, Card, Profile, etc. that are all v1. This is our starting scenario. Then we make breaking changes and bump Avatar to v2. Now we can update the Avatar dependency on Card to v2.

The required changes stop here:

  • The Card component is now on v2
  • Profile, Bio, etc. can still depend on Avatar v1 and are not affected ( it is a valid npm package )
  • When it is time/convenient, you can go back to Profile (which depends on Card, that depends on Avatar) and update Card to v2 and fix any code that needs to be fixed

Everything else stays the same. Everyone that is adding Card, Avatar, Profile etc. can STILL use v1 or v2 of those components and update them when they think it’s necessary. No more blowing up the scope of a simple task because you need to update the calls on all your company projects using those components—you can do it incrementally.

How

Now that you know how this approach can benefit your workflow, I will go over the tool we chose and a little bit about how we are using it at Thinkific.

The tool we are using is called Lerna . Lerna is a monorepo manager, and it:

  • Takes care of local (unpublished) dependencies
  • Takes care of versioning
  • Takes care of the changelog
  • Takes care of the publishing
  • Keep all packages in sync

With Lerna, all the managerial tasks that would be a pain to do manually are a breeze (well, most of the time ). We’ve had a few bumps along the way, but nothing we couldn’t overcome. For instance, there aren’t a ton of guides on how to set it up, the documentation is lacking and the workflow can be confusing or hard to learn when a new dev is onboarded.

Even with these challenges, it can greatly improve your speed, productivity, and confidence to deploy independent versioned packages with their own independent dependency tree .

Base Workflow

Once you set up the project and get Lerna in place, this could be your day-to-day workflow:

  • Make a change to one component
  • Commit using the proper message. IMPORTANT: Lerna depends heavily on the SemVer pattern to generate the changelog, determine which package needs to be updated, updating the dependencies, creating tags, and re-publishing to npm. So make a habit to create good, standardized commit messages.
  • Push your changes to your SCM (git, etc.)
  • Run “Lerna publish” to trigger a publish. At this point, Lerna will do all the wiring for you. Based on the commit message, Lerna will check your dependencies in your local packages and update them as necessary. If you did a feat change on component A, Lerna will go over all your components and update all the components that depend on component A to use the new version, but it will respect the SemVer rules. You can see how the versioning and commit messages are important!
  • That’s it! You can now go to whatever is using your component and update the version to the new one without needing to track down every instance using component A and update them.

I’ve left the workflow and the implementation details out of this post since I’ll need another post or a full-on series dedicated to explaining the intricacies of it. Please leave a comment below if you‘d like more information on it.

Conclusion

My goal is to give you enough information so you can make a decision to explore further the world of monorepos. Hopefully, you now understand the use cases where a monorepo is beneficial and will make sense for your company. This is not intended to be an extensive step-by-step tutorial to implement a monorepo tool into your workflow.

If you want to see more posts like this, don’t forget to like this post and follow us for more content. If you have any questions, please leave a comment and we will try to answer you as quickly as possible.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK