Published on

Getting Lerna Working With an Existing Create React App

Authors

The Issue

We have been using our own hand-rolled monorepo structure for our full stack JavaScript projects. This looks something like this:

package.json
            -> ui
                 -> package.json
                 -> ...
            -> server
                 -> package.json
                 -> ...

The package.json in the root of the project has scripts that help you control the rest of the project from the root. It is not as easy to use as Lerna but we opted going this route due to running into issues when using Lerna with Create React App (the ui folder above).

Searching for solutions many suggest ejecting your CRA but I would rather not have to worry about webpack, babel and other configs unless I have to.

Fixing It For the UI

Today I attempted to move one of our monorepos with CRA in to Lerna and succeeded by following this article with a few adjustments to get it to work with an existing CRA app. I opted for this route so that I could create a common module in my monorepo to easily share boilerplate utilities between the ui and server without having to copy/paste or go through the process of setting up a private npm registry.

The steps I used to migrate my existing repo and incorporate what was mentioned in the above article are:

  • Init Lerna: From the root of the project I ran: npx lerna init
    • This creates the lerna.json file in the root and the packages folder which will hold your sub-repos
  • Move the existing ui and server repos: mv ui packages && mv server packages
  • Use Lerna to Install React at the top level: npx lerna add react@^16.6.3 && npx lerna add react-dom@^16.6.3
    • In this case I made sure the versions I was installing matched those in my ui's package.json file
  • Clean and Hoist: As per the article I then ran: lerna clean -y && lerna bootstrap --hoist

I confirmed this worked by running: lerna run start --stream which starts both the ui and the server in the same shell showing the outputs for both.

Babel Issues

The whole point of the above move was to allow me to share utilities between my ui and server. This worked perfectly when sharing from my common utility module to the ui but I still need to tinker with babel at the root to get it allow me to import common utilities in the server module. The steps I used to create the common module were:

# from the monorepo root (where the lerna.json) is run:
lerna create @my-awesome-project/common -y

In the above you can use whatever you want after the create but I used the name of my monorepo with an @ before it.

Other Issues

Yarn does not play nice with lerna and create-react-app - I kept running into the original issues that kept me away from lerna. As a result I stuck to using npm. Also if you switch to yarn you lose the ability to hoist using Lerna and it looks like you end up having to use a mix of yarn workspaces and lerna.

Conclusion

As it stands this setup will work perfectly for creating a common module between one or more create react app sub-repos. It does not work when trying to import common modules into sub-repos that are not cra apps, some babel tweaking is needed still to get this to work. The other none-cra apps will still work correctly with lerna as long as you do not need to import common module items. Hopefully after a bit more digging I will get this to work too.