Skip to content

A CLI to manage monorepos with predictability and stability.

Notifications You must be signed in to change notification settings

ctrlplusb/monilla

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Monilla (✨ work in progress ✨)

A CLI to manage monorepos with predictability and stability.

 


 

 


1. Introduction

Monilla is a CLI tool which improves the development experience against npm-based monorepos.

It avoids the use of workspaces or hoisting, treating each of your monorepo packages as though they were independent packages. We find that this approach increases the predictability and stability of packages within your monorepo. Dependency updates to one package should not affect another.

We lean heavily into a "standard" npm experience and promote the capability for packages to be easily lifted in or out of your monorepo.

  • Install dependencies across your monorepo, and link internal packages;
    monilla install
  • Declare a link between internal packages;
    monilla link --from @my/components --to @my/ui
  • Perform interactive dependency upgrades across your monorepo;
    monilla upgrade
  • Watch your packages for changes, updated linked packages;
    monilla watch

 


2. Motivation

Coming soon

 


3. Prerequisites

Node.js version 18 or higher is required to use this CLI.

Note

There was a change in behaviour between npm versions in how linked package dependencies were installed. A flag (--install-links) was introduced to the npm CLI to address this issue.

Node 18 by default ships with a version of npm which includes support for this flag. Therefore we are making it a requirement that you utilise Node 18.

We highly recommend installing nvm on your machine. It enables you to manage multiple versions of Node.js seamlessly. Utilising nvm you can install the required version of Node.js via the following command;

nvm install --default 18

Note

The --default flag will make this installation the default version on your machine.

 


4. Install

We recommend installing monilla as a dev dependency in the root of your monorepo;

npm install monilla --save-dev

 


5. Requirements

Linked Packages package.json Design

We expect that each package within your monorepo is built almost as if it were independent package, that could be published to npm.

This means that you need to;

  • add all the expected dependencies to your package.json to meet your package's needs;
  • define the main or exports or module fields to indicate the entries and available imports from your package;
  • define the files list, declaring which dirs/files should be exposed by your package;

For e.g.

{
  "name": "@my/stuff",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "exports": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "files": ["dist"],
  "scripts": {
    "build": "tsup"
  },
  "dependencies": {
    "chalk": "^5.0.1"
  },
  "devDependencies": {
    "@types/node": "^16.11.41",
    "tsup": "^6.1.2",
    "typescript": "^4.7.4"
  }
}

Note

We declare our package as "private" with a version of "0.0.0". This is intentional as we never intend to actually publish our package to npm. It will only be used by other packages within the monorepo.

We will perform an "npm pack" of your linked packages, carrying across the expected files that would have been exposed if it were published to npm.

This enables us to produce an npm install behaviour for your linked packages that is essentially the same as a vanilla install should the package have been downloaded from the npm registry.

 


6. Guide

Imagine a monorepo with the following structure:

my-mono-repo
|
|- apps
|  |
|  |- @my/mobile-app
|     |- src
|     |  |- index.js
|     |- package.json
|
|- packages
|  |
|  |- @my/components
|     |- src
|     |  |- index.js
|     |- package.json
|
|- package.json

Using this as a reference, we'll describe a few scenarios below.

Note

All of the below commands should be executed at the root of your monorepo.

We have prefixed the commands with npx which enables you to quickly execute your local installation of the Monilla CLI.

 

6.1. Installing your dependencies

npx monilla install

This performs two functions;

  • Installs the required dependencies for each package within the monorepo, including the root
  • Ensures that any linked packages within the monorepo are bound

 

6.2. Linking packages

Linking enables you to utilise one of your monorepo packages within another as though it were installed via the NPM registry.

The example monorepo contains a mobile app, and a components library. If we wished to utilise the components library within the mobile app we can link the package.

You can do so by running the link command within the root of your monorepo;

npx monilla link --from @my/components --to @my/mobile-app

Note

Monilla will throw an error if you create a circular dependency between your packages.

Note

If the source package has a build script we will execute it prior to link, ensuring that all the required source files are available.

 

6.3. Updating linked packages

If you've performed updates to one of your linked packages, you can ensure that all dependants are using the latest version of them via the following command;

npx monilla refresh

Note

If your linked package has a build script it will be executed prior to performing the refresh.

 

6.4. Watching updates to linked packages

Watching your linked packages results in automatic building and pushing of the updates;

npx monilla watch

This command is especially useful when performing local development across your monorepo.

Note

We utilise your .gitignore file to determine which files to ignore when executing this process.

 

6.5. Upgrading package dependencies

We support interactive upgrading of the dependencies for all the packages within your monorepo;

npx monilla upgrade

You'll be asked which packages you'd like to update for each of the packages within your monorepo. After this has completed we'll take care of the installs and refreshing of your linked packages.

Note

The command has additional flags allowing you to select the type of upgrades you wish to consider. By default we will only look for patch or minor updates for existing dependencies.

 


7. CLI Reference

Work in progress. You can get help via the CLI --help flag;

npx monilla --help

7.1. clean

npx monilla clean

Removes all node_modules folders and package-lock.json files from across the monorepo. Supports the good old "nuke and retry" strategy when in dire need.

7.2. install

npx monilla install

This performs two functions;

  • Installs the dependencies for every package, including the root.
  • Ensures that any linked packages are bound.

7.3. link

npx monilla link --from @my/components --to @my/mobile-app

Link monorepo packages, declaring the from package as a dependency within the to package.

7.4. refresh

npx monilla refresh

Ensures that packages are using the latest form of their internal packages dependencies that have been linked against them.

7.5. watch

npx monilla watch

Starts a "development" process that will watch your linked packages for any changes, and will automatically update consuming packages to use the updated versions.

7.6. upgrade

npx monilla upgrade

Perform an interactive upgrade of the dependencies for all the packages within your monorepo.

 


8. Appreciation

A huge thank you goes to @wclr for the outstanding work on Yalc. The Yalc workflow is the specific seed which enabled this idea to grow. 🌻

An additional thank you is extended to @raineorshine for the amazing work on npm-check-update. Updating dependencies would be too laborious without this amazing tool. We couldn't have done it better ourselves, so we have incorporated npm-check-update directly. ☀️

 


9. Further Reading / References