The highs and lows of using Lerna to manage your JavaScript projects

16,608 reads

Overview, pain points, highlights and tips

Lerna is a tool for managing large scale JavaScript projects with multiple packages.

Anyone that’s worked with huge projects that are made up of granular components or dependencies knows that it becomes a hassle to make updates to your work after a while. In the world of 2017 JavaScript we’re importing packages all over the place and Lerna is helping us manage them for our big projects at Yoox NET-A-PORTER.

Who’s using Lerna?

BabelJS

create-react-app

react-router

Jest

And many, many more

What it really does & why it’s great

Lets start with an example.

Imagine you have a React application with a Button component — this button component needs to use a Text component (granular but just humour me for the examples sake):

// inside the super-button NPM package + repo

import SuperText from 'super-text'

const SuperButton = props => (

<button>

<SuperText value="Click me!" />

</button>

)

export default SuperButton



// inside the super-text NPM package + repo

const SuperText = props => (

<span>

{props.value}

</span>

)

export default SuperText

Each of these components live in their own repos and are their own NPM packages — they need to be maintained, versioned, and worked on by 20+ developers.

Lets say we have a consuming application of both of these components — if we wanted to update both of these components as part of a feature then we would have to make the changes to each, update tests, update the versions, commit the changes, get them code reviewed, publish the packages, update the consuming application and use them — phew.

But wait! You just realised your changes are slightly different to the requirements and/or it doesn’t work as expected — lets pretend these components are far more complicated or might involve complex styling etc. You’d have to redo that entire process again — if your team is busy maybe they won’t get around to code reviewing it, maybe you’ll be blocked for the next 2 hours and have to resort to reading Medium articles until they’ve unblocked you!

Lerna to the rescue! Lerna lets you construct your application into a very large repository of packages and apps (can all be renamed and configured); these apps are the consumers and the packages are the granular dependencies (SuperButton & SuperText above). When you’ve made all the changes required, you execute a command:

$ lerna run bootstrap

What this will do is go through all of your applications (in our self-named apps folder)and symlink each apps dependencies to any local version found inside the packages by using the respective packages name (and version!) in package.json . Any that aren’t found in packages will simply be installed from npm the same way you would anyway.

This is huge — it allows massive refactoring, updating and feature enrichment without the developer process headache. Make changes to your dependencies, bootstrap, check and implement them in your consumer apps and you’re done! Save the pull request until everything is ready.

Why it can be annoying & how to mitigate the pain

Sounds great right? We initially though so then we ran into some headaches porting our large app over — we’ve mostly solved all of them:

If you have a lot of dependencies in each application, bootstrapping can take a very long time. 2017 web development usually means you have 500+ dependencies of all manner of packages running your application — whether it’s for a build step, transpilation, bundling, a reusable component or simply something to left-pad your strings.

Mitigate this by moving all of your shared dependencies between apps & packages to a root package.json file and specify the --hoist flag in your bootstrap command. It’ll still take a while but it’ll greatly reduce the time taken.

2017 web development usually means you have 500+ dependencies of all manner of packages running your application — whether it’s for a build step, transpilation, bundling, a reusable component or simply something to left-pad your strings. Mitigate this by moving all of your shared dependencies between apps & packages to a root file and specify the flag in your bootstrap command. It’ll still take a while but it’ll greatly reduce the time taken. Tests take a long time to run and lose syntax highlighting.

The $ lerna run test command goes through each package and runs the test script declared in package.json — the issue here is it will spawn a test runner for every single instance it finds — in our case we had ~60 which ate our laptops up. It also meant that our syntax highlighting (passing/failing/warnings etc) were being omitted due to the test runs being spawn in seperate shell process.

Solve this by running your test runner from the root level with a config file there to specify which directory to find tests in — we use jest and the config file makes this all pretty easy. Our tests went from ~2m to run to ~15s and we got our colour coding back!

The command goes through each package and runs the test script declared in — the issue here is it will spawn a test runner for every single instance it finds — in our case we had ~60 which ate our laptops up. It also meant that our syntax highlighting (passing/failing/warnings etc) were being omitted due to the test runs being spawn in seperate shell process. Solve this by running your test runner from the root level with a config file there to specify which directory to find tests in — we use jest and the config file makes this all pretty easy. Our tests went from ~2m to run to ~15s and we got our colour coding back! Ways of working with one gigantic repo.

We’re still solving this incrementally and will depend on your project, team structure and requirements — if you’re building a large shared platform of reusable, atomic components you sometimes ask yourselves ‘who owns this?’, often the answer is everyone should but things don’t always work out that way and is a talk for another blog post.

We’re still getting used to Lerna, it’s been a rocky path of frustration but ultimately it’s worked out for the best. It was great for our project and it might just be great for yours.

Want to learn more about Lerna?

Check out the official site or check out the github page

Enjoyed my ramblings? Follow me on twitter to hear more of my development tales or keep up with my side projects on my personal site. 💻

Tags