davidjbradshaw / eslint-config-auto

Automatically configure ESLint based on project dependencies

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Usage in a monorepo

alecmev opened this issue · comments

I'm using this in a monorepo, where 99% of the development deps are declared in the root workspace, including ESLint and this config. If I go and run ESLint in one of the sub-workspaces (with yarn run -T eslint), I get the following:

Oops! Something went wrong! :(

eslint-config-auto could not find the following package

  eslint-config-adjunct

To install the missing package, please run the following command:

npm install eslint-config-adjunct@latest --save-dev

I tried aliasing hasAnyDep to moduleNotAvailable, but that has its own fatal side effects. So I went here:

const { packageJson: pkg, path: packagePath } = readPkgUp.sync({
// eslint-disable-next-line security/detect-non-literal-fs-filename
cwd: fs.realpathSync(process.cwd()),
})

And prepended process.cwd() with process.env.npm_package_json ?? , and everything started to work as expected. It's available in npm 7+ and Yarn 3.2.2+. Why did it help? Because -T in yarn run -T means --top-level, so it executes the ESLint binary from the root of the monorepo, and npm_package_json resolves to the package.json which "owns" that binary. I'm not sure how npm handles run commands, but I know that they do hoisting too, so I imagine the behavior should be the same.

This assumes that a project-level eslint is used, not a system-level one, and that eslint-config-auto is installed alongside eslint, not in a sub-workspace, along with every single dependency that eslint-config-auto might look for.

The above is a quick fix that will make monorepos work now, but it's not a complete solution. For example, eslint-config-auto might be installed in the root, and one of the packages might depend on react, and even with this fix it will not pick up React, because hasAnyDep will look only in the root package.json.

The real solution is to find the root of the monorepo, and then go down the tree, merging all dependencies. Note that workspaces can be nested infinitely, it's not just one level. Unfortunately, I wasn't able to find any existing package that does this correctly (they all go down only one level). But I think a good enough version could be to just do a find-up of either yarn.lock, pnpm-lock.yaml or package-lock.json. Here's how Yarn does it, and pnpm. If no lock file is found then fall back to the current behavior.

Or could use a flawed existing library (ignore the "yarn" in its name, it works for any package manager). It's easy and it covers 99.(9)% of use cases, I haven't seen a 3+ level workspace yet.

Thoughts?