DEV Community

Cover image for Beware of Colons in Yarn Scripts
Leonid Fenko
Leonid Fenko

Posted on

Beware of Colons in Yarn Scripts

Let us say you have a monorepo that uses the latest Yarn with workspace-tools plugin. There you have two child workspaces, e.g. frontend and backend. They list some linting scripts like lint:js and lint:css that use the common convention of separating the scope with a colon (:).

For obvious reasons, backend doesn't have a lint:css script. The root workspace exists only for grouping purposes and therefore doesn't have any linting scripts.

- root workspace
  - backend workspace
    - lint:js
  - frontend workspace
    - lint:js
    - lint:css
Enter fullscreen mode Exit fullscreen mode

Now you want to lint all workspaces at once using the yarn workspaces foreach run command that tries to run the specified script in each workspace, including the root one. You will do something like this:

# Lint all JS
yarn workspaces foreach run lint:js

# Lint all CSS
yarn workspaces foreach run lint:css
Enter fullscreen mode Exit fullscreen mode

As mentioned before, not all workspaces have the specified scripts, but that should not be a problem because the documentation states the following:

If the command is run and the script being run does not exist the child [or current] workspace will be skipped without error.

However, linting all JS results in a cryptic message in the root workspace (as a side note, this is already fixed in the canary version):

Usage Error: Couldn't find a script named "lint:js".
Enter fullscreen mode Exit fullscreen mode

Linting all CSS is even funnier: the lint:css from frontend is executed three times, once for each workspace.

This is because Yarn has a little-known feature that makes any script with a colon in its name global. For lint:js, this means that there are two conflicting versions of this script in the root workspace, which leads to the "Couldn't find..." error (again, this is fixed in the canary version). For lint:css, this means that the frontend script is global, so it can be called from any workspace.

A script with a colon in its name implicitly "exists" in every workspace, so yarn workspaces foreach run will always execute it in all workspaces (if there is only one version of the script). In contrast, missing scripts without colons are properly ignored.

The issue with implicit global scripts is described in detail in this feature proposal.

Conclusions

  • In Yarn, use colons (:) in script names only if you want those scripts to be callable from any workspace.
  • The yarn workspaces foreach run command does skip a workspace if the specified script is missing there. Just make sure that the script name does not contain colons.

Discussion (0)