Skip to content

Instantly share code, notes, and snippets.

@andywer
Last active April 8, 2022 03:50
Show Gist options
  • Save andywer/d25770fdbfa111ec4ec84e8e26232868 to your computer and use it in GitHub Desktop.
Save andywer/d25770fdbfa111ec4ec84e8e26232868 to your computer and use it in GitHub Desktop.
Monorepo Setup

Overall Approach

This document is a short description of the monorepo setup that I came up for a few different smaller projects in the last 8 months or so.

Directory structure

/
  services/
    product/
    topup/
    ...
.dockerignore
.gitignore
.gitlab-ci.yml
README.md
docker-compose.yml
package.json
yarn.lock

Continuous Integration

We can use GitLab CI as we already do, merging X small-ish existing GitLab CI config files into one larger one.

The only property makes it easy to only run test or deploy the services that actually changed.

image: node:10-alpine

stages:
  - test

test purchase service:
  stage: test
  services:
    - mongo:3.4
    - redis:4
  only:
    changes:
      - .gitlab-ci.yml
      - services/topup/**/*
  script:
    - cd services/topup
    - yarn install --pure-lockfile
    - yarn test

Yarn instead of npm

Why? Because yarn comes with monorepo support out of the box: See Yarn workspaces.

A simple top-level yarn install will install the dependencies of all services as well and if you have packages referencing each other, it will also automatically link them against each other.

Nice side effect: It installs dependencies faster and does not constantly modify the lock file while nothing changed.

Lerna

Lerna is a handy tool to manage monorepos. You can easily:

  • Run a package.json script in every service / package
  • Can run scripts and commands either in parallel or serially
  • Publish all packages at once or only those that changed (if a package monorepo)

Alternative: oao

Link-Parent-Bin

Small npm package that is run from CLI on monorepo-wide yarn install. Creates symlinks to the monorepo-wide node_modules/.bin/* in all service directories. Otherwise executing those tools from a service's package.json scripts might fail.

{
"name": "@satoshipay/services",
"version": "0.0.0",
"private": true,
"scripts": {
"postinstall": "link-parent-bin -c services/",
"build": "lerna run build",
"test": "lerna run --parallel test"
},
"workspaces": [
"services/*",
"tools/*"
],
"devDependencies": {
"lerna": "^3.6.0",
"link-parent-bin": "^0.2.3"
}
}
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"target": "es2017",
"module": "commonjs",
"lib": ["es2015", "es2016", "es2017", "es2017.object"],
"strict": true,
"baseUrl": ".",
"paths": {
"*": [
"./node_modules/*",
"../../node_modules/*"
]
}
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment