A little introduction. Most likely this post will be interesting only to those who know what ESLint is, but still I will do a little introductory - and then I myself get very upset when I open a publication, and it begins with the words “for 10 years we have been using xxx, which of course you you know, and we decided to write about xxx.yyy that no one ever did, but surely this is very cool. ”
So,
ESLint is a cool tool that allows you to analyze the quality of your code written in any selected JavaScript standard. He leads the code to a more or less uniform style, helps to avoid silly mistakes, knows how to automatically fix many of the problems found and perfectly integrates with many development tools (hello, Jetbrains, we love you!). By the way, he, like other linters, does not oblige you to one particular style. On the contrary - you can choose something from the best practices and refine it on your own!
Among the applications you can find rather unexpected cases - for example, a legacy code may be easier to get rid of by automatically correcting the linter, leading to modern standards in which errors are better visible than trying to edit it as it is. As a result, invalid constructs may well turn out - but, according to our observations, this means that before the conversion, there was just a disgusting code.
')
In general, living without a linter in Node.JS in 2017 is the same as writing code in a notepad while sitting on one hand.
And today I will tell you how we decided to implement it in order to work effectively with it in a team, and not one by one.
The big guys do a linter check as part of their CI process, and we'll get to that soon. But for now, we need to realize the primary need - launching the linter from the developer, with the guarantee that everything will take off and work more or less the same way.
It would seem - what is this, add. Eslintrc.json to the project, and let's go! However, the question arises - how, where and by whom should ESLint be installed and a pack of plug-ins necessary for our code style? Three approaches are usually used for this:
- Let's put them in devDependency;
- Let's not put them anywhere. Let everyone be globally standing mocha \ eslint \ other.
- Let them put everything and drive checks will task managers like gulp or grunt.
The second option is swept away immediately - I think it is clear that in this way the versioning of the tool itself from project to project disappears, and simply putting a lot of tools and plug-ins globally is not at all cool.
The third option is not bad, but until now we somehow did without task managers. To add them to projects for the sake of such a task is an obvious overkill.
The first option is generally optimal for github projects, but is not well suited for commercial development. Our CI provides for automated testing on test servers, and test dependencies can be set apart from devDependencies. But this is not the problem, but, in contrast to autotests, the tools for the linter should not fall on test servers. At least for the reason that then, when rolling out, the project suddenly begins to weigh more than 200 megabytes instead of 30. To some, this may seem insignificant, but to comply with the PCI DSS standards, we all use pretty serious encryption of any information, so rolling the update on 200 megabytes takes precious minutes. So the first version does not suit us either. Summing up:
- Linter and its plugins do not have to stand globally;
- A specific project must be tied to specific versions of the tools;
- These tools should not be in dependencies or devDependencies.
At first glance, a simple solution suggests itself: make an npm script, for example, npm run lint-install, which will pull a bash script that installs all packages of the specified versions via the command line. But, in addition to the clumsiness of such a solution, it also turns out that some of the dependencies (albeit the developer ones) leave package.json for some separate bash script ... And this is not cool at all. We think further, we recall the specifications package.json. In general, no one will hurt us to add any sections there as well - but I would like to follow certain standards.
From
the package.json specification , we recall that there is such a rather strange and rarely used section, like
peerDependencies :
It is not always necessary to make it necessary for your computer. This is usually referred to as a plugin. Notably, your module documentation should be notable.
They are not automatically placed, with the exception of a small pitfall:
NOTE: If you are not explicitly dependent on the dependency tree. In the next major version of npm (npm @ 3), this will no longer be the case. You will receive a warning message that the peerDependency is not installed instead. The behavior in npms 1 & 2 was a matter of course.
Fortunately, we no longer had npm, so we could safely use this section without fear of sudden consequences. But the problem came from no waiting ... It turned out that when uninstalling the automatic installation of peerDependencies, the authors of npm ... They didn’t make any way to install them manually. So all that is now for the peerDependencies section is a warning that they are not installed. In part, these are understandable, since these dependencies are optional, but still. I have a suspicion that after such a change, all the developers simply transferred everything to devDependencies ... And dependency hell did not go anywhere.
By the way, not only the absence of such an option seemed strange to me. There is even an
issue about this - it is closed, but marked as patch-welcome. That is, the authors of npm generally agree that this is a cant - they simply do not have enough time to fix it ...
So, we now have a section, but it is not clear how to use it. There are 18 likes of the same issue here:
npm info . peerDependencies | sed -n 's/^{\{0,1\}[[:space:]]*'\''\{0,1\}\([^:'\'']*\)'\''\{0,1\}:[[:space:]]'\''\([^'\'']*\).*$/\1@\2/p' | xargs npm i
In my opinion, hell. As a team leader, I just cannot allow this to come into our projects ...
In general, the idea went further in the direction of writing or finding a tool that can parse package.json itself and call npm install - but not as tough as the script described above. More or less I was satisfied with npm-install-peers. He has two minuses:
- If, for some reason, it does not find the npm installed in the system (through which it is now actually put), then it ... It installs it again locally, which causes the expenditure of time, traffic, and sometimes all sorts of hellish errors.
- He does not support any arguments. If the symlinks on windows can already be turned on, and --no-bin-links is no longer relevant, then --production is still desirable. For the same linter dependencies, this would greatly save installation time.
Probably in the near future I’ll just do a similar installer that does the same thing, but draws npm not as a module, but through bash. It’s not so beautiful, but everything is clear with the arguments, and you don’t need to install npm a second time. And it would be desirable to transfer arguments - at least not to put devDependencies from eslint and its plug-ins.
Then the question arises - how to install npm-install-peers globally? Assume that it is the default? Set silently when executing the script? Set locally in devDependencies? I did not like any of the options. As a result, I was satisfied with this simple solution:
"lint-install": "npm-install-peers || echo 'Please run npm install -g npm-install-peers first'",
This option seemed to me the most transparent for the developer.
And all that remains is to add a script to start the linter and the peerDependencies we actually need. Script:
"lint": "./node_modules/eslint/bin/eslint.js app.js routes modules test App.js"
Dependencies:
"peerDependencies": { "babel-cli": "^6.23.0", "babel-preset-es2015": "^6.22.0", "eslint": "^3.16.0", "eslint-config-airbnb": "^14.1.0", "eslint-plugin-import": "^2.2.0", "eslint-plugin-jsx-a11y": "^4.0.0", "eslint-plugin-promise": "^3.4.2", "eslint-plugin-react": "^6.10.0", "eslint-plugin-standard": "^2.0.1" }
By the way, as a side feature, we can now put into the peerDependencies any other dependencies that do not belong to the tests - for example, the divine
jsdoc-to-markdown .
It would seem - a simple task ... But there were quite a lot of interesting nuances. And I fully admit that it was possible to make it easier and better. And how do you use linters for corporate projects?