question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Usage of recent versions within Lenra monorepos is unclear

See original GitHub issue

Description

I have a repo that’s previously made light use of lint-staged; that I am now slowly converting to a monorepo with two related packages.

(For one thing, the lint-staged monorepo documentation doesn’t seem to jive with recent versions of Husky (after v1); for instance, no longer is "precommit" an npm "scripts" entry, it’s a separate piece of "husky" configuration, or an entry in a .huskyrc file. That means the suggested lerna run precommit command in sudo-suhas/lint-staged-multi-pkg doesn’t make a whole lot of sense. Easy enough to fix that, though!)

Unfortunately, although lint-staged seems to use cosmicconfig, and suggests configuring Husky and lint-staged in the root directory, not in the Lerna ‘projects’ … it doesn’t seem to be recognizing the .lintstagedrc.json files in the projects themselves when invoked from the project root:

$ cd lernaroot

$ cat packages/bs-excmd/.lintstagedrc.json 
{
   "linters": {
      "*.{js,json,css,md}": [
         "prettier --ignore-path .gitignore --write",
         "git add",
         "jest --bail --findRelatedTests"
      ],
      "*.{ml,mli}": ["npm run format:ml ; :", "git add", "npm run changed:ml"]
   },
   "ignore": ["docs/**/*", "package.json"]
}

$ lint-staged
Config could not be found.

Please make sure you have created it correctly.
See https://github.com/okonet/lint-staged#configuration.

Now, I could just install lint-staged separately in every project, and add a separate npm run lint-staged script that just … invokes lint-staged, but that didn’t seem to be the Blessed Path? If this is how things are supposed to be done, despite the .lintstagedrc and Lerna hoisting and the new Husky configuration options, the documentation could also be improved to make that clear. (=

Steps to reproduce

  1. Create a new Lerna root-directory
  2. Install Husky and lint-staged in the root-directory
  3. Add a new Lerna “package” in a subdirectory
  4. Add package-specific configuration to a .lintstagedrc file in the subdirectory
  5. Invoke lint-staged in the Lerna root

Debug Logs

lint-staged --debug
  lint-staged:bin Running `lint-staged@10.0.0-1` +0ms
  lint-staged Loading config using `cosmiconfig` +0ms
Config could not be found.

Please make sure you have created it correctly.
See https://github.com/okonet/lint-staged#configuration.

Environment

  • OS: macOS “Catalina” 10.15.2
  • Node.js: v12.10.0
  • lint-staged: v10.0.0

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:2
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
ELLIOTTCABLEcommented, Jan 14, 2020

(I hope I’m not super-annoying you with these several Issues, or anything — just trying to contribute feedback and help lint-staged perform better for monorepo projects! Also, hi, I didn’t realize you were involved in ReasonConf Vienna — did I see you there, and just totally forget!?)

Ah, okay, so it’s working-as-intended — that’s helpful information. That said, can we re-open this, then, and consider it a feature-request?

At the moment, then, without the ability to pick up multiple configuration files with separate configurations and automatically merge them as I assumed was already supported / described in the OP, I have two options:

  1. I can create separate .lintstagedrc.json files in each project, install lint-staged into every project as a devDependency, and then invoke lint-staged once per project:

    // repo/.huskyrc.json
    {
       "hooks": {
          "pre-commit": "lint-staged && lerna exec 'npm run-script precommit'"
       }
    }
    
    
    // repo/.lintstagedrc.js
    module.exports = {
       // Prettier
       './*.{js,json,md}': ['prettier --ignore-path .gitignore --write'],
    
       // Jest
       '**/*.{ml,mli,mly,ts,js,json}': 'jest',
    }
    
    
    // repo/packages/foo/package.json
    {
       // ...
       "scripts": {
          // ...
          "precommit": "lint-staged"
       }
    }
    
    
    // repo/packages/foo/.lintstagedrc.js
    module.exports = {
       // Prettier
       '**/*.{js,json,md}': [
          'prettier --ignore-path .gitignore --write',
       ],
    
       // Dune, ocamlformat, and odoc
       '**/*.{ml,mli,mld}': [
          'npm run format:ml ; :',
          'npm run test:ml',
          'npm run build:doc',
       ],
    }
    
    
    // repo/packages/bar/package.json
    {
       // ...
       "scripts": {
          // ...
          "precommit": "lint-staged"
       }
    }
    
    
    // repo/packages/bar/.lintstagedrc.js
    module.exports = {
       // Prettier
       '**/*.{js,json,css,md}': [
          'prettier --ignore-path .gitignore --write',
       ],
    
       // Typedoc
       '**/*.{js,json,md}': ['npm run build:doc'],
    }
    

    This approach, clearly, leads to a bit of configuration-noise; it spreads what is, effectively, a single configuration concept amongst several otherwise-unrelated files; and worse, results in much slower pre-commit execution times (which people can be fairly sensitive to, of course), because you’re gonna add a whole series of copies of shell-startup, Node + npm run-script boot time, and lint-staged itself’s own boot time, to every single commit:

    husky > pre-commit (node v12.10.0)
    ✔ Preparing...
    ✔ Running tasks...
    ✔ Applying modifications...
    ✔ Cleaning up...
    ✔ Preparing...
    ✔ Running tasks...
    ✔ Applying modifications...
    ✔ Cleaning up...
    ✔ Preparing...
    ✔ Running tasks...
    ✔ Applying modifications...
    ✔ Cleaning up...
    [secondary-rollup-package cb99480] DELETEME test
    1 file changed, 1 insertion(+), 1 deletion(-)
    

    Yikes!

  2. Alternatively, I can reduce the lint-staged invocations to a single one, but then I have to compact the configuration itself into a single file … and, more importantly, I have to maintain paths for all of those configurations, both in terms of lint-staged’s triggers and working-directory manipulation for various tasks.

    // repo/.huskyrc.json
    {
       "hooks": {
          "pre-commit": "lint-staged"
       }
    }
    
    
    // repo/.lintstagedrc.js
    module.exports = {
       // Prettier
       './*.{js,json,md}': ['prettier --ignore-path .gitignore --write'],
       'packages/foo/**/*.{js,json,md}': [
          'prettier --ignore-path packages/foo/.gitignore --write',
       ],
       'packages/bar/**/*.{js,json,css,md}': [
          'prettier --ignore-path packages/bar/.gitignore --write',
       ],
    
       // Jest
       '**/*.{ml,mli,mly,ts,js,json}': 'jest',
    
       // Dune, ocamlformat, and odoc
       'packages/foo/**/*.{ml,mli,mld}': [
          'cd packages/foo/ && npm run format:ml ; :',
          'cd packages/foo/ && npm run test:ml',
          'cd packages/foo/ && npm run build:doc',
       ],
    
       // Typedoc
       'packages/bar/**/*.{js,json,md}': ['cd packages/bar/ && npm run build:doc'],
    }
    

    This isn’t much better:

    • Now, contributors have to carefully consider, and maintan, various input paths and working-directories for each task;
    • Globs for lint-staged itself have to be manipulated to only match particular packages, most likely causing a ton of duplication;
    • And, not least, configuration is dislocated from the work itself: anybody who starts spelunking the project they actually care about, isn’t going to notice any of this configuration, despite it being specefici to said particular project.

Now, to be clear, this totally works! It’s what I’ve ended up doing (This issue isn’t a huge blocker for me, personally, or anything); but, again, there are obvious downsides.


So, my proposal is fairly simple:

  1. Read a .lintstagedrc{,.js,.json} in any directory also containing a package.json (or, perhaps, only in projects containing a lerna.json … or only when using a --monorepo flag … or providing a --subpackages ./path/to/packages/dir flag …);
  2. Collect all tasks from such subdirectories into one lint-staged operation, prepending the parent-directory of the .lintstagedrc file to the minimatch invocation;
  3. Change working directory to that same directory before executing provided linting tasks.

Does this all make sense?

1reaction
okonetcommented, Jan 7, 2020

I just re-read the initial message and it occurred to me it is working as expected. lint-staged uses cosmiconfig and it looks for config in the directory it’s executed and goes upwards till it reaches the project root (afaik). It doesn’t search for configs inside sub-dirs.

That being said, it is still possible to have package-specific configs. We have a dedicated section in the readme on how to use it with Lerna.

Read more comments on GitHub >

github_iconTop Results From Across the Web

The issue with Monorepos - Squash
In this article, we will identify some of the monorepo benefits. Finally, we will focus on whether a monorepo is suitable for everyone....
Read more >
Can I manage same version for all the sub-package in lerna ...
Based on Lerna documentation if you want to publish all packages under the same version you need to use zero (0) as the...
Read more >
What is monorepo? (and should you use it?) - Semaphore CI
A monorepo is a version-controlled code repository that holds many projects. While these projects may be related, they are often logically ...
Read more >
Monorepos, mindsets, and perspectives | by Damian Cyrus
No more duplicated dependencies with different versions (me: Lerna will fail installation if you use hoisting on different dependency versions.) ...
Read more >
Things I wish I had known when I started JavaScript monorepo ...
It only made sense, dividing the code into separate packages with fixed or independent release cycles. Majority of those libraries used Lerna, a ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found