|
4 | 4 |
|
5 | 5 | # Summary
|
6 | 6 |
|
7 |
| -Allow Yarn CLI to execute a package script on each packages from the workspace root. |
| 7 | +Allow Yarn CLI to execute a package script on each workspace package from the workspace root. |
8 | 8 |
|
9 | 9 | # Motivation
|
10 | 10 |
|
11 |
| -"Lerna". Lerna does a great job for handling monorepos. Since Yarn has a built-in |
12 |
| -workspaces feature, we could use some of the functionalities that being used in |
13 |
| -lerna (not entirely though!) for handling the monorepo more efficiently. |
| 11 | +Lerna does a great job for handling monorepos. Yarn's built-in workspaces feature would benefit from borrowing more of functionality that Lerna exposes, to handle monorepos more easily. |
14 | 12 |
|
15 |
| -Just like installing all dependencies from one place (workspace root), it'd be great |
16 |
| -to execute all the sub-package scripts from the workspace root using a single command. |
17 |
| -Not only this would make a less back-and-forth traveling between the packages to |
18 |
| -execute scripts, but also it'll help a lot for CI/CD configuration. |
| 13 | +Just like installing all dependencies from one place (workspace root), it'd be useful to execute a specific package script for each of the workspace packages from the workspace root using a single command. Not only this would make for less back-and-forth traveling between the packages to execute scripts, but also it'll help a lot for CI/CD configuration. |
19 | 14 |
|
20 | 15 | # Detailed design
|
21 | 16 |
|
22 |
| -As @BYK mentioned [here](https://github.com/yarnpkg/yarn/issues/4467#issuecomment-330873337), |
23 |
| -we could create two commands for this feature. |
| 17 | +As @BYK mentioned [here](https://github.com/yarnpkg/yarn/issues/4467#issuecomment-330873337), to start we'd create two commands for this feature: |
24 | 18 |
|
25 | 19 | * `yarn workspaces list`
|
26 | 20 | * `yarn workspaces run <command>`
|
27 | 21 |
|
28 |
| -By introducing `workpaces` command, it brings a modular approach from the CLI's perspective. |
| 22 | +Unifying all of the workspace-specific commands under the `workpaces` namespace allows for a modular approach from the CLI's perspective, making future commands easy to add. |
29 | 23 |
|
30 |
| -## `yarn workspaces list --args` |
| 24 | +## `yarn workspaces list [flags]` |
31 | 25 |
|
32 |
| -This command will list out all the packages for all the workspaces (alphabetically). If no workspace is found, this will fail with error. |
| 26 | +This command lists all of the packages for all of the workspaces alphabetically. If no workspaces are found it will error. |
33 | 27 |
|
34 |
| -Additionally, we can pass a `--filter` argument followed by a workspace name. In that case, it'll list out all the package inside that specified workspace. |
| 28 | +## `yarn workspaces run [flags] <command> ...` |
35 | 29 |
|
36 |
| -## `yarn workspaces run <command>` |
| 30 | +This command runs a specific package script (as defined in the `scripts` property in `package.json`) for all of the packages for all of the workspaces. |
37 | 31 |
|
38 |
| -This will execute the specified `<command>` in all workspaces. For a _fail fast_ operation, we could traverse all the workspaces to check whether the specified command exists within that workspace, before we actually start executing. If not found, display an error with which workspace is missing that command. |
| 32 | +Just like the `yarn run` command, any arguments after the command name will be passed as arguments to the package script. |
39 | 33 |
|
40 |
| -The ordering of execution is also important. It must be executed _topologically_. So that it won't break the inter-dependant workspaces. |
| 34 | +For a _fail fast_ operation, we could traverse all the workspaces to check whether the specified command exists within that workspace, before we actually start executing. If not found, display an error with which workspace is missing that command. |
| 35 | + |
| 36 | +The ordering of execution is also important. It must be executed _topologically_, so that it won't break the inter-dependant workspaces. From the Lerna documentation: |
| 37 | + |
| 38 | +> By default, all tasks execute on packages in topologically sorted order as to respect the dependency relationships of the packages in question. Cycles are broken on a best-effort basis in a way not guaranteed to be consistent across Lerna invocations. |
| 39 | +> |
| 40 | +> Topological sorting can cause concurrency bottlenecks if there are a small number of packages with many dependents or if some packages take a disproportionately long time to execute. The --no-sort option disables sorting, instead executing tasks in an arbitrary order with maximum concurrency. |
| 41 | +> |
| 42 | +> This option can also help if you run multiple "watch" commands. Since lerna run will execute commands in topologically sorted order, it can end up waiting for a command before moving on. This will block execution when you run "watch" commands, since they typically never end. An example of a "watch" command is running babel with the --watch CLI flag. |
| 43 | +
|
| 44 | +The output should be prefixed with the name of the workspace (eg. `packages/package-a:`), so the user has a better idea of what is currently running. |
| 45 | + |
| 46 | +### `--concurrency` |
| 47 | + |
| 48 | +The `--concurrency` flag changes the number of child processes that are spawn when commands are run in parallel, defaulting to `4` (like Lerna). |
| 49 | + |
| 50 | +### `--parallel` |
| 51 | + |
| 52 | +If the `--parallel` flag is passed, it will runs the commands in parallel in separate child processes, instead of running them in series. This command will ignore the concurrency flag and topological sorting requirements. (Just like Lerna.) |
| 53 | + |
| 54 | +## `yarn workspaces exec ...` |
| 55 | + |
| 56 | +This commands runs an arbitrary shell command in each package. It is similar to `yarn workspaces run`, and respects the same flags, but instead of running a package script defined in `package.json` you can pass it arbitrary shell commands. |
| 57 | + |
| 58 | +This is helpful for cases where you want to execute something that isn't worthy of storing in `package.json`, often when debugging or running a one-off. |
| 59 | + |
| 60 | +For example: |
| 61 | + |
| 62 | +``` |
| 63 | +$ yarn workspaces exec babel --out-dir ./lib ./src |
| 64 | +``` |
| 65 | + |
| 66 | +## Common Flags |
| 67 | + |
| 68 | +### `--packages` |
| 69 | + |
| 70 | +The `--packages` flag takes a package name or glob, and it restricts the command being run to only take affect in those packages. |
| 71 | + |
| 72 | +**Note:** this flag operates on the package names, as defined by the `name` field in `package.json` files. |
| 73 | + |
| 74 | +For example: |
| 75 | + |
| 76 | +``` |
| 77 | +$ yarn workspaces list --packages 'babel-*' build |
| 78 | +``` |
| 79 | + |
| 80 | + |
| 81 | +### `--workspaces` |
| 82 | + |
| 83 | +The `--workspaces` flag takes a workspace name or glob, and it restricts the command being run to only take affect in those workspaces. |
| 84 | + |
| 85 | +**Note:** this flag operates on the workspace names, not the package names. For example `packages/my-package` would be a workspace name. This is helpful when working with multiple directories of workspaces. |
| 86 | + |
| 87 | +For example, with a `workspaces` setup of: |
| 88 | + |
| 89 | +```json |
| 90 | +[ |
| 91 | + "packages/*", |
| 92 | + "services/*", |
| 93 | + "utils/*" |
| 94 | +] |
| 95 | +``` |
| 96 | +``` |
| 97 | +packages/ |
| 98 | + package-a/ |
| 99 | + package-b/ |
| 100 | + ... |
| 101 | +services/ |
| 102 | + api/ |
| 103 | + cdn/ |
| 104 | +utils/ |
| 105 | + ... |
| 106 | +``` |
| 107 | + |
| 108 | +You could restrict the command to only run in `services/api` and `services/cdn by doing: |
| 109 | + |
| 110 | +``` |
| 111 | +$ yarn workspaces run --workspaces 'services/*' start |
| 112 | +``` |
41 | 113 |
|
42 | 114 | # How We Teach This
|
43 | 115 |
|
44 |
| -Since this is a new feature and doesn't affect existing functionalities, it shouldn't affect existing/new users. However, a slight documentation should be written under the workspace CLI. |
| 116 | +Since this is a new feature and doesn't affect existing functionality, it won't change any existing user behavior. However, documentation should be added to explain the new features to those who want to opt-in to them. |
45 | 117 |
|
46 | 118 | # Drawbacks
|
47 | 119 |
|
48 |
| -Complexity. Especially while executing the package scripts. We need to keep track of the package dependencies. And also, there's already a library (lerna) does the same thing and is compatible with yarn without any extra configuration. |
| 120 | +This will increase the complexity of Yarn, instead of letting it live in Lerna and work in tandem. Especially while executing the package scripts, because we need to keep track of the package dependencies. |
49 | 121 |
|
50 | 122 | # Alternatives
|
51 | 123 |
|
52 |
| -Don't have an alternative way (I can think of) inside yarn. |
| 124 | +There's no current alternative using Yarn. You have to use Lerna and Yarn in concert, which causes confusion as to which one to use when. |
53 | 125 |
|
54 | 126 | # Unresolved questions
|
55 | 127 |
|
56 |
| -How to handle multiple workspaces? |
| 128 | +- Should package names and workspace names be handled? or only packages? |
| 129 | +- What does Yarn define as a single "workspace"? |
| 130 | +- Should parallel execution be handled? |
| 131 | +- Should an `exec` command be added as well, similar to Lerna? |
0 commit comments