2020-10-08
|~3 min read
|549 words
Yarn workspaces are ways to register applications with Yarn without needing to install them globally and even avoid a link or pack (both of which mirror to the global /bin
directory for node
).
Let’s take a contrived example and see how it might work and why it’s useful.
Imagine you have a CLI that you’re developing, mycli
. It starts as a humble directory
.
└── mycli
├── README.md
└── bin
└── run
We would be able to run this cli from the command line with
./mycli/bin/run
Note: We don’t need to tell the shell to use the node interpretter because the run
script starts with a shebang:
#!/usr/bin/env node
//... entry point
But how could we register it so that we can just call it as mycli
? The first and most straightforward way is to set the bin
property within package.json
and then install it globally:
{
"name": "mycli",
"bin": {
"mycli": "./bin/run"
}
}
Then, if the cli is published to a package registry like npm
, you can install it globally:
yarn install -g
If it’s not, you can link it:
yarn link
But today, we want to talk about workspaces which give us the same benefits of rapid iteration of our CLI without polluting our global namespace or having to manage links. Even better, we can use the application as if it’s installed within other packages within the workspace.
The first thing to understand about Yarn Workspaces is that they are built around a monorepo approach. By this, I simply mean that in order to use a package within a workspace as if it’s installed, it needs to be managed by a shared package.json
.
The bare minimum we need in this controlling package.json
are two properties: private
and workspaces
. The latter is where we’ll store our CLI.
{
"private": true,
"workspaces": ["packages/*"]
}
Now run yarn
to register our project. Our project directory now looks like:
.
├── package.json
├── packages
│ └── mycli
│ ├── README.md
│ └── bin
│ └── run
└── yarn.lock
At this point, as long as we’re within the project, we can run our CLI with:
yarn mycli
While that’s helpful, we can go one step further and enable the workspace to be run within a series of examples that we create alongside the source code for the CLI.
For example, let’s add an examples folder:
.
├── examples
│ └── package.json
├── package.json
├── packages
│ └── mycli
│ ├── README.md
│ └── bin
│ └── run
└── yarn.lock
The examples/packages.json
is very basic and just requires a name:
{
"name": "example",
"version": "1.0.0",
"main": "index.js",
"license": "MIT"
}
In our package.json
in the root, we’ll update our workspaces to include example
:
{
"private": true,
"workspaces": ["packages/*", "example"]
}
Now, we can specify that we want to run mycli
from within the example
workspace from the command line:
yarn workspace example mycli
This is a contrived example, so we’ll only create a package.json
within examples
, but you can imagine how it might work if you had more fleshed out examples that would benefit from being able to run with mycli
as if it were installed.
Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!