Skip to content

Commit 916d9f2

Browse files
arcanisBYK
authored andcommitted
Update: Prevent yarn add from being run from the workspace root directory (#4166)
**Summary** This PR prevents using `yarn add <pkg>` from within a workspace root folder, in order to prevent common mistakes where a package is added to the workspace root folder instead of being added to the right workspace (which, because of the node resolution algorithm, would be effectively invisible to the user). If the user really wants to add a dependency to the workspace root folder, then we suggest them to use `yarn add <pkg> --dev` instead. This should be fine since the workspaces will probably only be used in development mode anyway. An alternative would be to introduce a new flag `--force` that would bypass this check, but I think the current heuristic is fine until we receive complaints. **Test plan** Added two tests.
1 parent 634c239 commit 916d9f2

File tree

3 files changed

+20
-0
lines changed

3 files changed

+20
-0
lines changed

__tests__/commands/add.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ const runAdd = buildRun.bind(
4242
},
4343
);
4444

45+
test.concurrent('add without --dev should fail on the workspace root', async () => {
46+
await runInstall({}, 'simple-worktree', async (config, reporter): Promise<void> => {
47+
await expect(add(config, reporter, {}, ['left-pad'])).rejects.toBeDefined();
48+
});
49+
});
50+
51+
test.concurrent("add with --dev shouldn't fail on the workspace root", async () => {
52+
await runInstall({}, 'simple-worktree', async (config, reporter): Promise<void> => {
53+
await expect(add(config, reporter, {dev: true}, ['left-pad']));
54+
});
55+
});
56+
4557
test.concurrent('adds any new package to the current workspace, but install from the workspace', async () => {
4658
await runInstall({}, 'simple-worktree', async (config): Promise<void> => {
4759
const inOut = new stream.PassThrough();

src/cli/commands/add.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ export class Add extends Install {
106106
*/
107107

108108
async init(): Promise<Array<string>> {
109+
if (this.config.workspaceRootFolder && this.config.cwd === this.config.workspaceRootFolder) {
110+
if (this.flagToOrigin === 'dependencies') {
111+
throw new MessageError(this.reporter.lang('workspacesPreferDevDependencies'));
112+
}
113+
}
114+
109115
this.addedPatterns = [];
110116
const patterns = await Install.prototype.init.call(this);
111117
await this.maybeOutputSaveTree(patterns);

src/reporters/lang/en.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ const messages = {
167167
createMissingPackage:
168168
'Package not found - this is probably an internal error, and should be reported at https://github.com/yarnpkg/yarn/issues.',
169169

170+
workspacesPreferDevDependencies:
171+
"You're trying to add a regular dependency to a workspace root, which is probably a mistake (do you want to run this command inside a workspace?). If this dependency really should be in your workspace root, use the --dev flag to add it to your devDependencies.",
170172
workspacesRequirePrivateProjects: 'Workspaces can only be enabled in private projects',
171173
workspaceExperimentalDisabled:
172174
'The workspace feature is currently experimental and needs to be manually enabled - please add "workspaces-experimental true" to your .yarnrc file.',

0 commit comments

Comments
 (0)