Setup toolchain
One of moon's most powerful features is the toolchain, which manages and
automatically installs Node.js and other tools. The toolchain is configured with
.moon/toolchain.yml
.
This toolchain article is currently Node.js only. If you're using another language, feel free to skip to the next article, creating a project.
Choosing a package manager
Before we continue, we should briefly talk about Node.js package managers. To start, moon does not
replace a package manager, nor does it apply any "magic" for them to work differently. Instead, moon
builds upon a package manager to provide a robust build system, assumes a standard node_modules
layout and module resolution algorithm, and supports any of the following 3 package managers.
Enabling workspaces (optional)
moon was built with monorepos in mind, and as such, has first-class support for them through package workspaces (but is not a requirement). To utilize workspaces, enable them for your chosen package manager.
- Yarn
- Yarn (classic)
- npm
- pnpm
{
// ...
"workspaces": ["apps/*", "packages/*"]
}
# ...
nodeLinker: 'node-modules'
{
// ...
"workspaces": ["apps/*", "packages/*"]
}
{
// ...
"workspaces": ["apps/*", "packages/*"]
}
packages:
- 'apps/*'
- 'packages/*'
Configuring Node.js
As Node.js is the backbone of a JavaScript based repository, let's define the version we want to
install in the toolchain, to enforce for developers, and to utilize when running moon
commands, by
updating node.version
in
.moon/toolchain.yml
.
This setting requires an explicit semantic version and does not support version ranges, so let's set it to the latest version. We suggest always using an Active LTS version.
node:
version: '18.0.0'
Let's now run moon setup --log debug
to verify that Node.js is downloaded and
installed correctly. Pretty cool right?
The Node.js version can also be customized per project using the
toolchain.node.version
setting in moon.yml
. This
setting exists to support legacy projects that are coupled to an old version and are unable to
upgrade. We suggest keeping all projects on the same version whenever possible.
Configuring a package manager
Even though Node.js is now installed, we need a package manager to install dependencies. Earlier we
talked about choosing a package manager, so let's use that
choice here by defining node.packageManager
.
node:
version: '18.0.0'
packageManager: 'yarn'
By default moon will install a stable version of the package manager, but this isn't consistently
updated, so we suggest defining an explicit semantic version for the package manager as well,
through the node.<packageManager>.version
setting.
node:
version: '18.0.0'
packageManager: 'yarn'
yarn:
version: '3.2.0'
Once again, let's run moon setup --log debug
to verify the package manager is
installed, and also take note that Node.js is already installed. Based on the example
configuration above, we'll be switching from npm (the default) to yarn.
Adding a package script
For scenarios like CI, moon
can be ran with through a root package.json
script — but this comes
with a cost — which is the overhead of launching Node.js and your chosen package manager to execute
the Rust binary, instead of executing the Rust binary directly. If this is problematic, feel free
to use the global binary.
{
// ...
"scripts": {
// ...
"moon": "moon",
// For Yarn 2+
"moon": "$(yarn bin moon)"
}
}
Yarn 2+ does not support executing Rust binaries through package scripts (issue), so we must access the full binary path and execute on that.
With this script, moon can then be run with npm run moon ...
(or yarn run
, or pnpm run
).