stylelint: Fix "TypeError: opts.node.rangeBy is not a function" with PostCSS 8.4.4
What steps are needed to reproduce the bug?
folder structure: package.json .stylelintrc.json styles.scss (empty file)
package.json:
{
"name": "untitled2",
"version": "0.0.0",
"private": true,
"scripts": {
"lint": "npx stylelint '**/*.scss'"
},
"devDependencies": {
"stylelint": "^14.1.0",
"stylelint-config-standard-scss": "^3.0.0"
}
}
npm i npm run lint
What Stylelint configuration is needed to reproduce the bug?
{
"extends": "stylelint-config-standard-scss"
}
How did you run Stylelint?
npx stylelint β**/*.scssβ
Which version of Stylelint are you using?
^14.1.0
What did you expect to happen?
I expect stylelint to show list of errors.
What actually happened?
TypeError: opts.node.rangeBy is not a function
at new Warning (node_modules/postcss/lib/warning.js:9:29)
at Result.warn (node_modules/postcss/lib/result.js:26:19)
at report (node_modules/stylelint/lib/utils/report.js:103:9)
at node_modules/stylelint/lib/rules/no-empty-source/index.js:28:3
at node_modules/stylelint/lib/lintPostcssResult.js:112:8
at Array.map (<anonymous>)
at lintPostcssResult (node_modules/stylelint/lib/lintPostcssResult.js:103:18)
at lintSource (node_modules/stylelint/lib/lintSource.js:88:8)
at async node_modules/stylelint/lib/standalone.js:218:27
at async Promise.all (index 0)
Process finished with exit code 1
The problem is in this line

Does the bug relate to non-standard syntax?
No
Proposal to fix the bug
Works correctly with exactly 8.3.11 version of postcss.
I compared the code in warning.js between these versions of postcss (8.3.11 and 8.4.4), they changed the method name. π¦
Proposal: change dependencies of stylelint to use exactly 8.3.11 version.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 27
- Comments: 71 (39 by maintainers)
Commits related to this issue
- build: Generate RTL version of Codex CSS using rtlcss Add a custom Vite plugin that generates RTL versions of all built .css files. This causes our Codex build to generate both codex.style.css and co... — committed to wikimedia/design-codex by catrope 2 years ago
- chore(deps): upgrade postcss to ^8.4.16 close #5766 — committed to stylelint/stylelint by JounQin 2 years ago
- chore(deps): upgrade postcss to ^8.4.16 (#6244) close #5766 — committed to stylelint/stylelint by JounQin 2 years ago
- static/frontend: upgrade postcss and fix stylelint config and errors Upgraded postcss to fix a type error when running stylelint --fix. See stylelint/stylelint#5766. Fixed the fileglob for CSS files... — committed to golang/pkgsite by jamalc 2 years ago
Also started with a fresh install of
stylelint@14.1.0andstylelint-config-standard-scss@3.0.0. Ran into the same error described above. Installedpostcss@8.4.4as @BroFox86 did, and the error is gone.Now letβs bump Stylelint with the latest PostCSS version and ask every user just to update
stylelintin theirpackage.json.Thanks to @JounQin and @snebjorn for solving this very complex bug.
In my case I just added PostCSS to my project by
npm i postcssand the error from the Stylelint VSC plugin was gone.@snebjorn @JounQin @ai I appreciate your work very much! ππΌ
Gentlemen, we have a winner!
I have an idea, give me a weekend.
Here is a plan:
postcss-lessto use PostCSS 8.4hi! so users have to wait stylelint v14.9.2, yep?)
update: no, iβve just updated postcss to 8.4.16 and it all works *___* thx a lot guys!
Thanks for the quick responses. It kept me motivated π Itβs been a pleasure!
@snebjorn exactly! I added the fix https://github.com/postcss/postcss/commit/f289e173b07bfb72265692662db94e5c49e5f583
I released a fix in PostCSS 8.4.15. Can we try it?
@JounQin The assignment of the rangeBy function is done here https://github.com/postcss/postcss/blob/main/lib/container.js#L415-L423 via Object.setPrototypeOf()
However the node that is throwing the error is of type
rootwhich the function doesnβt handle.The function is being called for the root type.
@ai could that be the issue?
@JounQin Yes, right. The
rangeBymethod has been added with PostCSS 8.4.0. See the changelog:https://github.com/postcss/postcss/blob/main/CHANGELOG.md#84-president-camio
@ai Stylelint uses
LazyResultto get parsing results. For example, when a user specifiescustomSyntax: 'postcss-less', thepostcss-lesssyntax object is passed tonew LazyResult(). See below:https://github.com/stylelint/stylelint/blob/e424be5eca77c5532b13147c4a7dad14085a4276/lib/getPostcssResult.js#L40-L47
https://github.com/stylelint/stylelint/blob/e424be5eca77c5532b13147c4a7dad14085a4276/lib/getPostcssResult.js#L77
Given the following dependency tree (see the snebjorn/styelint-no-rangeBy repo),
Then,
LazyResultreturns a result object including nodes produced bypostcss@8.3.5(postcss-less@6.0.0), whilestylelint@14.9.1tries to handle them as a node compatible withpostcss@8.4.14that has therangeBy()method. However, since actual nodes donβt haverangeBy(),TypeErrorraises:https://github.com/stylelint/stylelint/blob/e424be5eca77c5532b13147c4a7dad14085a4276/lib/utils/report.js#L31
Weβre looking for how to absorb node differences between PostCSS versions.
I found it! The issue is with the custom syntax parsers. Here Stylelint is handing over control to PostCSS and itβs using the correct 8.4.14 version. The parser in this case is
postcss-less.Inside LazyResult we end up here. At this point weβre still using the nested PostCSS bundled with Stylelint. (This is good)
source: https://github.com/postcss/postcss/blob/e731697dffd2e14da609503a5114d3a28c948334/lib/lazy-result.js#L133
So far so good. But now it starts to go wrong. Because
postcss-lessimport PostCSS.source: https://github.com/shellscape/postcss-less/blob/master/lib/index.js#L3
But weβre no longer in the scope of Styellint. Looking at the stack track makes it very clear that weβre no longer βinsideβ stylelint
postcss-lesshave correctly declared PostCSS as a peer dependencysource: https://github.com/shellscape/postcss-less/blob/984f4901aced4b74535d96b04242681d538d628b/package.json#L50
In my case, because I updated packages, I have this dependency graph
A solution? I think the correct fix for this is to have Stylelint declare PostCSS as a peer dependency. That way Stylelint can increase the version of PostCSS and plugins that correctly list PostCSS as a peer dependency (with a range that compatible with Stylelint) will follow along.
I think I have part of the answer.
Stylelint it self have a dependency on
@csstools/selector-specificityhttps://github.com/stylelint/stylelint/blob/0d2c6cd98192b48d2cd5c8b305154aadd63a8a22/package.json#L111
@csstools/selector-specificityhave a dependency onpostcss@^8.2https://github.com/csstools/postcss-plugins/blob/cb7490ed905947e6877fa7261dce8990ea24166f/packages/selector-specificity/package.json#L41
I have a project where I updated stylelint from an older version. The postcss version that satisficed ^8.2 when I first installed stylelint was
postcss@8.3.6. When I went to update stylelint to 14.9.1 then my installedpostcss@8.3.6still satisficedpostcss@^8.2and thus I end up with this dependency graphSo in my local install when a rule using
@csstools/selector-specificitywould trigger Iβd end up withnode.rangeBy is not a functionbecause@csstools/selector-specificity@2.0.2is usingpostcss@8.3.6internally.Iβm still working on a minimal reproducible repo. But with the above dependency graph I got this error from a built-in stylelint rule
This basically means that somewhere a
nodewas created usingpostcss@8.3.6.And moreover, you can then uninstall postcss and all works fine for current and all future projects. I wasnβt been able to reproduce the issue for any new projects as well.
In our case we have a problem using https://github.com/ismay/stylelint-no-unsupported-browser-features/blob/master/package.json this package has postcss as a dependency
@ybiquitous
Edit: Never mind, it seems to be caused by
stylelint-test-rule-tape.Indeed, Iβm surprised too. Iβm getting postcss from stylelint and it is the latest of
8.4.21.FYI: That is my PR to upgrade my plugin to
v15https://github.com/AndyOGo/stylelint-declaration-strict-value/pull/310@AndyOGo That error should never occur if you are using the latest PostCSS. Please recheck your dependency tree.
@ismay I mean itβs not required to upgrade to v14, you only need to upgrade the postcss dep on your side.
I agree with this part. But it seems we only have this issue for
node.rangeByand we do rely on this prototype method to work correctly. Another solution would be that we just copy therangeBymethod intostylelint, but this has the same situation as you said.You know that it is not acceptable for
yarnorpnpmornpm < 7, a large mount of users would be affected, not only the ones you expected.I think monkey patching is a dangerous path to take. When looking through the code of Stylelint itβs not obvious that a different PostCSS version might be used at runtime. Itβs just a matter of time before the next thing needs to be monkey patched, and so on.
If PostCSS can somehow guarantee that the
postcssProcessorpassed to it is the version used then all is well. Though I think thatβll be a tough one to crack. Though I havenβt given it much thought.I must mention the Peer Dependency solution again as it fixes everything. I did a simple test where I wrapped Stylelint in a package with these peerDependencies
Using NPM v8.16.0 I installed my wrapper package
npm i -D wrapped-stylelintand I ended up with this dependency graphNote I didnβt install PostCSS. I just installed
wrapped-stylelint. So the impact of this breaking change is minimal for NPM users since v7 (I didnβt actually test NPM v7)The only bad thing about this solution is Yarn users will have to manually install PostCSS. But perhaps some traffic here https://github.com/yarnpkg/yarn/issues/1503 could change that
@JounQin Thanks for the comment. To be honest, I donβt know how to apply the way on https://github.com/stylelint/stylelint/issues/5766#issuecomment-1200504530β¦ π
If PostCSS would provide a more elegant solution, Iβm glad to adopt it.
Thanks for your efforts first.
But I donβt think itβs acceptable for stylelint.
In details, stylelint is a singleton cli tool without any peer dependencies, changing postcss as peer would be a breaking change and changes a lot for end users.
It maybe something the package manager should address by deduplication, or you can try https://github.com/scinos/yarn-deduplicate#deduplication-strategies with
fewerstrategy.I believe the simplest way to resolve the error is to install the latest versions of Stylelint and PostCSS.
Iβm not sure if Stylelint should do something to address this problem. I wish anyone would provide a minimal reproduction repository to make investigation easier (for some package managers if possible)β¦ π
I can confirm this. When I removed the
//comments from my file the error stopped showing up.It seems the error only happens when I comment using // instead of /* ?
https://user-images.githubusercontent.com/15921402/152132550-6c588314-bff4-499f-910a-2c579860647b.mp4
Thanks for the help.
I will try to find solution during this weekend.
thanks! Iβll try to clone your repo and see if it will work on my side. Then I will compare lock file and node_modules and to see whatβs differs.
Could it happen because of the different PostCSS versions at chimeraβs AST containing nodes from different PostCSS versions?
Can you look
npm lsfor different PostCSS versions?