Yarn workspaces and Ember

Recently I added yarn workspaces to my Ember project and I’ve been super happy with the workflow! I’m able to work on an npm package alongside my Ember application without having to worry about npm link or npm publish.

However, it seems in doing this I broke ember install, since it causes yarn to error. Here’s an example.

~/my-ember-app$> ember install ember-cli-clipboard                                                                                                                                                       

Command failed: yarn add --dev ember-cli-clipboard --non-interactive
error Running this command will add the dependency to the workspace
root rather than the workspace itself, which might not be what you
want - if you really meant it, make it explicit by running this
command again with the -W flag (or --ignore-workspace-root-check).

My workspace root is the Ember app and all of the workspaces are subdirectories in lib under the Ember application. I think that’s what is causing the issue.

I found this article from Square and it looks like they keep all their workspaces in a packages folder, without any project at the root. Is that what I should be doing if I want to use workspaces in an Ember app?

Hey @ryanto! — we’ve been using Yarn workspaces for some time.

We keep the root-level directory basically empty and keep all of our modules in a packages folder (same, it seems, as what Square does).

For what it’s worth, we also moved our .eslintrc.js and .prettierrc files to the top level — so those are only specified in the nested packages on a case-by-case basis. Not sure if this ended up being the best idea because we have our yarn workspaces configured not to hoist any eslint package:

This is roughly our root-level package.json:

{
  "name": "our-monorepo",
  "version": "0.0.0",
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "eslint"
    ]
  },
  "license": "SEE LICENSE IN README.md",
  "dependencies": {
    "eslint-config-prettier": "2.7.0",
    "eslint-plugin-prettier": "2.3.1"
  }
}
2 Likes

Hi, I wrote that blog post. :grin:

If I’m reading this correctly:

My workspace root is the Ember app and all of the workspaces are subdirectories in lib under the Ember application.

… your project looks like this?

package.json # with "workspaces" config
ember-cli-build.js
app/
lib/
├── some-package/
├── ├──  package.json
├── ├──  index.js
├──  another-package/
├── ├──  package.json
├── ├──  index.js

Yeah, I don’t think that’ll work. The top-level “package” shouldn’t be a real package and generally doesn’t have its own dependencies. You don’t have to nest projects under a “packages” directory, but it’s very common in monorepos like babel so I used that as the example layout in the blog post.

My current project layout looks like this:

package.json
.eslintrc.js # and other dotfiles
team-one/
├──  engine-a/
├── ├──  package.json
├── ├──  index.js
├── ├──  addon/
├──  addon-b/
├── ├──  package.json
├── ├──  index.json
├── ├──  addon/
├── ├──  app/
team-two/
├── ├──  engine-c/
... # more packages
host-application/
├──  package.json
├──  ember-cli-build.js

The top-level package.json is just:

{
  "private": true,
  "workspaces": [
    "host-application",
    "team-one/*",
    "team-two/*"
  ]
}

Hope this helps!

1 Like

It’s a very excellent blog post!

I have a question, you use yarn add command directly or ember install on ember addon installation if all are workspace packages including the host app?

Also, I have another question on how to install an ember addon with a default addon blueprint to a workspace package, like the ember-highcharts? Cause it’ll add another dependency “highcharts” to it’s package.json and ember-cli just doesn’t support to install a addon to a workspace package.

Thanks!

@2hu12 I run ember install within each package in the workspace if I need the addon’s blueprint to run during installation. I basically pretend that I’m working on each addon/app independently and never install packages in the top-level package.json.

I’m not sure I understand your second question, especially the “ember-cli just doesn’t support to install a addon to a workspace package” part. Can you elaborate?

@lennyburdette

ember-cli just doesn’t support to install a addon to a workspace package

When all dependencies are installed on the workspace root node_modules and if I run ember install within each paceage, it will get an error of “node_modules appears empty, you may need to run yarn install”.

Do you use the “nohoist” option of yarn workspace to avoid this problem?

When you say dependencies are installed in the workspace root, do you mean that that they’re listed in the root package.json’s dependencies or devDependencies? Or just that the packages exist in the top-level node_modules folder?

If it’s the former, that’s not what you want. Make sure you’re always installing dependencies in each ember app or addon.

If it’s the latter, are you on a recent version of ember-cli? Yarn workspaces support wasn’t complete until 3.1.

I mean the latter one and I use the ember-cli@3.9.0.

Does it have node_modules folder within each package or there is only one node_modules folder of the workspace root?

@2hu12 You will have n+1 node_modules folders (where n is the number of packages in your workspace root.)

Most dependencies will end up in the top-level node_modules folder. This is also where the symlinks to your workspaces live so node’s require algorithm can find them.

You’ll also have a node_modules folder in each workspace. If there aren’t conflicting dependencies, it will be mostly empty. It will always contain a .bin directory with executables though.

Sounds like you have everything set up correctly. I’m not sure why you’re still seeing an error.

I got the “node_modules appears empty, you may need to run yarn install” error cause it only has one workspace root “node_modules” when I run “ember install” within one package.

If you have “n+1 node_modules folders”, the “nohoist” option is necessary, right?

I only get that error message when I’m running the ember command outside of an app or addon directory. Is your globally installed version of ember-cli up to date?

I haven’t found a need for nohoist yet—what you’re trying to do should work without it.

Thank you @lennyburdette and sorry for this late response.

According to the first item in the Limitations & Caveats section,

the workspace dependencies will be hoisted higher into the filesystem hierarchy

If you don’t use the “nohoist” option, how do you make sure that there will be n+1 “node_modules”? Image that if one workspace package “addon-a” only has common dependencies with another workspace package “addon-b”, the dependencies of “addon-a” and “addon-b” will be hoisted to the root-level “node_modules”, right?

I have a GitHub repo branch for the problem i had which is I don’t know how to install an ember addon like “ember-fetch” or “ember-highcharts” to one of it’s packages like “engine-a-lazy”, it also has a doc for the issues.

Node’s module resolution algorithm will traverse the file system hierarchy to find packages when they’re hoisted. This is what makes workspaces work!

I think the issue in your example repo is that the root is both a package and a workspace root. You have things set up the way ryanto did at the top of this thread. (My response to that)

Compare my demo repo: GitHub - lennyburdette/ember-monorepo-demo … the host application is just another package in the workspace root, and the "workspaces" key in the root package.json can find it.