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.
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.
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.
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!
**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.
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. 💻