Getting Started with Monorepo

Do you want monorepo? Here’s how you start!

Satrio Wibowo
5 min readNov 4, 2022
Source

Hello! If you decide to click this tutorial, there is a higher chance you already understand what is monorepo all about (if you don’t, check out my other story about monorepo vs multirepo to find out). But in a nutshell, monorepo is a git strategy to use a single repository that holds many projects or components instead of using multiple repositories for them.

You may be wondering, how do you start a monorepo project? And in this tutorial-ish, we need the help of Lerna.

What is Lerna?

Lerna is a tool for managing JavaScript projects with multiple packages. Lerna is designed to manage monorepo, which can hold projects containing multiple packages within itself. In this case, we need Lerna to do package bootstrapping and parallelized build. You can also add custom commands to which you can wrap commands to be run on each project in the monorepo.

With that out of the way, let’s start creating monorepo project. Note that in this tutorial we use Vue 3 as the software 😃

Step 1: Initialize the Root Directory

In this step, you need to do the following:

mkdir medium_monorepo   # Create new directory for your project
cd medium_monorepo # Enter the newly created directory
npm install -g lerna # Install lerna globally
lerna init # Initialize lerna
npm install -g @vue/cli # Install Vue-cli globally

This will generate the following files:

packages: This folder is where your projects will reside later.

.gitignore: This file will mark which folder will be ignored and not pushed to the repository

lerna.json: This file will be the configuration file for Lerna

package.json: This file is the configuration file for Node (NPM)

Step 2: Setup Shared Packages

Now, to take benefit of monorepo, try to add eslint, babel-eslint, and eslint-plugin-vue as the dependency on the root (these are just JavaScript and Vue Linter). To do that, we can run the following command:

npm install --save-dev eslint babel-eslint eslint-plugin-vue

Step 3: Create your app

Now we can start creating our app. To do that, enter packages folder, then just create the app. In this case, we will create main and shared program

cd packages                            # Enter package folder
vue create main --packageManager npm # Create appone project
vue create shared --packageManager npm # Create apptwo project

When running vue-create command, you may be presented selection for which Vue you want to install. If you know what you’re doing, select that option. Else, just select the default.

Step 4: Configure your app (AppOne)

Notice that we have created main and shared app. Now we need to make sure that our main application can also build based on the dependencies (both components and node_modules) that are already in shared application. To do that, we need to create a file named vue.config.js inside our main application. The file contains the following:

# Import path dependecy to make file lookup easier
const path = require('path')
# Get node_modules folder for "main" app
const mainNodeModules = path.resolve(__dirname, './node_modules')
# Get node_modules folder for "shared" app
const sharedNodeModules = path.resolve(__dirname, '../shared/node_modules')
# Get src folder for "main" app
const mainSrc = path.resolve(__dirname, 'src')
# Get src folder for "shared" app
const sharedSrc = path.resolve(__dirname, '../shared/src')
# Time to configure our Webpack Application
module.exports = {
configureWebpack: {
resolve: {
modules: [mainNodeModules, sharedNodeModules],
alias: {
'@shared': sharedSrc,
'@main': mainSrc
}
}
}
}

Step 5: Setup Global NPM Commands

Now that we’re done setting up our applications, time to add the commands. To do that, we need to open package.json in the root folder and add the following to the scripts section:

{
"scripts": {
"postinstall": "lerna bootstrap",
"admin": "cd ./packages/main && npm run serve",
"admin:build": "cd ./packages/main && npm run build",
"admin:test": "cd ./packages/main && npm run test",
"test": "lerna exec -- npm run test",
"lint": "lerna exec -- npm run lint"
}
}

The command on the left is just an alias for the command on the right. However, you may be confused about what these commands do. Here is the explanation for each command we just set:

lerna bootstrap: Basically this is the equivalent of npm install . However, instead of running it one by one, we use Lerna to ask every application inside packages folder to run it for us.

npm run (serve/build/test): This is npm commands that we need to use to run our apps later. As the name denotes, serve is for serving our application, build is for building, and test is for automated testing.

lerna exec -- <commands>: This command is used to run <commands> on each application inside the packages folder. It can be anything actually and not limited to npm command only

Step 6: Try it

Now we can try to import components from shared application into our main application. To do that, add the following code inside your App.vue file inside packages/main folder:

<!-- In template tag -->
<SharedHelloWorld msg="This is shared hello world!"/>
<!-- In script tag -->
import SharedHelloWorld from '@shared/components/HelloWorld.vue'

Your code more or less will be look like this:

<template>
<div>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<SharedHelloWorld msg="This is shared hello world!"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import SharedHelloWorld from '@shared/components/HelloWorld.vue'
...
</script>

Then, you can try to do run npm run main:build then npm run mainto run your application. The terminal will show an address for you to click and your page should be shown like this:

Yay! We have monorepo!

(see troubleshooting at the bottom of this tutorial page if you encounter an error)

Notice we now have shared hello world text here? Congratulations, you have a working monorepo now! 😃

Conclusion

How was it? Is it hard? It wasn’t, right? After this, you can adjust your application per your need. Or you can also push to your version control (git) as one repository (uhum.. monorepo 😏). Hopefully this will helps you on understanding how monorepo works in action.

Thank you for reading!

Troubleshooting

If for some reason your build process is stuck at 0% when building main app, do the following steps to solve it:

> Delete `node_modules` folder inside your packages/main folder> Add the following line in vue.config.js inside module.exports in packages/main
chainWebpack: config => config.plugins.delete('named-chunks')
> Re-run `npm run postinstall` then `npm run main:build && npm run main` on the root folder

--

--

Satrio Wibowo

Just a programmer that loves coding and learning new tech