mrdr
(pronounced: /mordor/) is a Swiss-army knife for running tasks in a monorepo.
This app requires a bit of setup, which you probably already have, but let's re-iterate what's needed.
In your monorepo there's a parent package.json
that needs to have your workspaces
listed. Given that your project contains 3 packages, a
, b
and c
here's the necessary configuration:
/package.json
{
"workspaces": [
"packages/a",
"packages/b",
"packages/c"
]
}
Each project can either be a shared library or an application.
In the case of a shared library you need to tell it what artifacts are exposed from it. This is standard npm package configuration, but for the sake of completeness here's an example, where package c
from the above workspaces
definition is a shared library:
/packages/c
{
"name": "c",
"exports": {
".": {
"default": "./dist/c.js",
"require": "./dist/c.umd.cjs",
"types": "./dist/index.d.ts"
}
}
}
Let's assume package a
is an application that would like to use package c
as a library. The standard way of expressing that dependency is to put it in the list of dependencies:
{
"name": "a",
"dependencies": {
"c": "*"
}
}
It can also be a devDependency
- doesn't matter as long as one of those sections contain the dependency to c
.
Now to the good part - running builds.
Once you have all your exports and dependencies defined it's time to define scripts that will build your project for both development and final build.
In this example I am going to assume you're going to use vite because if you're still using webpack you should rethink your life, maybe change jobs or just upgrade. It is worth every effort (unless you can't for some technical reason...)
In your common library (c
) you define the scripts
as follows:
/packages/c/package.json
{
"scripts": {
"dev": "vite build -w",
"build": "vite build"
}
}
In your application (a
) you define them as follows:
/packages/a/package.json
{
"scripts": {
"dev": "vite",
"build": "vite build"
}
}
This is pretty standard configuration that all examples on the Internet and all the templates will follow - because it is obvious and simple.
In the strictest sense you don't need them but it is surely a nice to have thing:
/package.json
{
"scripts": {
"dev": "mrdr",
"build": "mrdr build"
}
}
mrdr
is a very young utility so the options are few at the moment:
Usage: mrdr [options] [command]
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
run [options] [script] Run a task recursively within the monorepo
ls [options] List dependencies between projects
help [command] display help for command
The run
command is for running tasks
Usage: mrdr run [options] [script]
Arguments:
script Script to execute (default: "dev")
Options:
-q, --quiet Be quiet
-v, --verbose Be verbose
-P, --prefix <path> Workspaces root (default: ".")
-d, --delay <ms> Additional miliseconds to wait after the resource is created (default: 200)
-t, --timeout <s> Max time in seconds to wait for resources to be generated (default: 30)
-w, --workspace <workspace> Run only the given workspace and its dependencies (default: "")
-C, --clean [task] Call the "clean" task before building a project; defaults to "clean" task
--no-wait Do not wait for resources to be created (useful for running the "clean" task alone)
--vite-reload-hack Install a hack that kicks dependent projects when a dependency is rebuilt
-h, --help display help for command
The ls
task is for listing dependencies between projects:
Usage: mrdr ls [options]
List dependencies between projects
Options:
-w, --workspace <workspace> Run only the given workspace and its dependencies (default: "")
-P, --prefix <path> Workspaces root (default: ".")
-h, --help display help for command
It is possible to have the dependencies between projects listed, possibly for debugging
npx mrdr ls
Being in your top-level folder, if you want to run everything in dev mode all you need to do is:
npx mrdr
It will take the dev
script from your packages and run it in order from least-dependent to most-dependent.
WARNING! No circular dependency check is done. If you have a case like that, don't use mrdr before you cut them!
You also might want to build your project in the proper sequence:
npx mrdr build
At present there is a bug either in vite.js or in vue.js or the hot-reloader for vue.js. The bug manifests in such a way that you need to manually reload the page if a package is used that is located behind a symlink.
Since npm workspaces automatically link packages in the top-level node_modules
folder they are always behind a symlink. The hack does a touch
on vite.config.js
(if it exists) to poke vite
to restart the application. It may not be what you need, hence this is an option. Use it if it helps, forget it ever existed if it hurts your feelings
Have fun using mrdr
!