Skip to main content

Setup toolchain

4 min

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.

info

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.

package.json
{
// ...
"workspaces": ["apps/*", "packages/*"]
}
.yarnrc.yml
# ...
nodeLinker: 'node-modules'

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.

.moon/toolchain.yml
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?

info

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.

.moon/toolchain.yml
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.

.moon/toolchain.yml
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.

package.json
{
// ...
"scripts": {
// ...
"moon": "moon",
// For Yarn 2+
"moon": "$(yarn bin moon)"
}
}
caution

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).

Next steps