-
-
Notifications
You must be signed in to change notification settings - Fork 27k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: react-scripts lint command #1217 #3850
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn’t work after eject.
That's on purpose to drive away from ejecting. |
a9c3973
to
6fe704b
Compare
Fixed and tested. Should work after ejecting now. |
6fe704b
to
4c89a1f
Compare
@@ -55,6 +55,10 @@ switch (script) { | |||
process.exit(result.status); | |||
break; | |||
} | |||
case 'lint': { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it need a separate case, and not using the same logic as above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure is node spawn needed in this case. But now I see. This way script feels no difference between being called with react-script command
and after eject with node scripts/command
.
{ stdio: 'inherit' } | ||
); | ||
if (args.indexOf('--init') >= 0) { | ||
console.log( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this for? I don't understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A part of eslint --init
wizard is to install dependencies using npm i
. Since we have yarn, this will make a small mess. This line of code is to inform, that after react-scripts lint
project has to be rebuilt with rm node_modules && yarn
and possibly rm package-lock.json
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this info after losing some time figuring out why all commands don't work anymore after react-scripts lint
.
4c89a1f
to
27d65f9
Compare
Lint case unified with rest of commands in |
@gaearon should project that was built by create-react-app come with default eslinter configuration? This is a suggested approach by ESLinter team. At the moment we don't provide such a file and users will probably need to make a copy of rules from other project or create a new eslinter config with |
I don’t think we want to add any wizard here. By default it should use the lint config that’s already used by default by commands like |
Thanks. I'll look for a way to integrate them into |
27d65f9
to
583132e
Compare
Added a default ESlint configuration, removed warning about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See below; we'll also need integration tests for this.
For example you could use some existing integration test in the tasks/
folder and verify that running ./node_modules/.bin/react-scripts lint
before ejecting and node scripts/lint.js
after ejecting doesn't break.
@@ -0,0 +1,3 @@ | |||
{ | |||
"extends": "react-app" | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After ejecting we already put eslint config into the package.json (as far as I remember).
Why is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to know ... now ... after few days of working on it (madman laugh: iiihahahaha).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file was added to run linter before ejecting.
Do you know how is it possible to have same effect but without such a file?
Side note: ESlinter can be run programmicaly:
const CLIEngine = require("eslint").CLIEngine;
const cli = new CLIEngine({
configFile: require.resolve('../config/eslint.json'),
fix: process.argv.slice(2).indexOf('--fix') >= 0
});
const report = cli.executeOnFiles(["src/**/*.{js,jsx,mjs}"]);
CLIEngine.outputFixes(report);
const formatter = cli.getFormatter();
console.log(formatter(report.results));
But it still seems it needs a config file. In supported options it is possible to pass rules, but not extends
. And, sadly, running above snippet after ejecting doesn't work, because eslint cannot find jsx-a11y definitions, even with this line added: plugins: ['import', 'flowtype', 'jsx-a11y', 'react']
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can baseConfig
argument help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it works
baseConfig: { extends: "react-app" },
however, after ejecting linter now reports
/private/tmp/demo-15/src/App.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
/private/tmp/demo-15/src/App.test.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
/private/tmp/demo-15/src/index.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
/private/tmp/demo-15/src/registerServiceWorker.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
✖ 4 problems (0 errors, 4 warnings)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding plugins: ['jxs-a11y']
throws `Error: Failed to load plugin jxs-a11y: Cannot find module 'eslint-plugin-jxs-a11y' (after yarn eject)
And trying these options didn't help
cwd: '/tmp/demo-15',
rulePaths: [
path.dirname(require.resolve('eslint-plugin-jsx-a11y')) + '/rules'
],
I wonder, why having baseConfig: { extends: "react-app" }
in scripts/lint.js
would be better than an explicit config file in the config directory? Both of these duplicate entry in package.json
.
.concat([ | ||
'src/**/*.{js,jsx,mjs}', | ||
'--config', | ||
require.resolve('../config/eslint.json'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this line can just be
require.resolve('eslint-config-react-app')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after eject it needs to be
require.resolve(paths.appPackageJson),
though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we can do it by playing around with eject comments 😅
// @remove-on-eject-begin
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @remove-on-eject-end
"use strict";
const spawn = require("react-dev-utils/crossSpawn");
const args = process.argv.slice(2);
// @remove-on-eject-begin
/**
// @remove-on-eject-end
const paths = require("../config/paths");
// @remove-on-eject-begin
*/
// @remove-on-eject-end
const result = spawn.sync(
"node",
[require.resolve("eslint/bin/eslint")]
.concat([
"src/**/*.{js,jsx,mjs}",
"--config",
// @remove-on-eject-begin
/**
// @remove-on-eject-end
require.resolve(paths.appPackageJson),
// @remove-on-eject-begin
*/
// @remove-on-eject-end
// @remove-on-eject-begin
require.resolve("eslint-config-react-app")
// @remove-on-eject-end
])
.concat(args),
{ stdio: "inherit" }
);
process.exit(result.status);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or just
// @remove-on-eject-begin
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @remove-on-eject-end
"use strict";
const spawn = require("react-dev-utils/crossSpawn");
const args = process.argv.slice(2);
const result = spawn.sync(
"node",
[require.resolve("eslint/bin/eslint")]
.concat([
"src/**/*.{js,jsx,mjs}",
// @remove-on-eject-begin
"--config",
require.resolve("eslint-config-react-app")
// @remove-on-eject-end
])
.concat(args),
{ stdio: "inherit" }
);
process.exit(result.status);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much! Suggestion to userequire.resolve('eslint-config-react-app')
as a config path is a gold.
7dc0f55
to
9998ca2
Compare
const CLIEngine = require('eslint').CLIEngine; | ||
|
||
const cli = new CLIEngine({ | ||
configFile: require.resolve('eslint-config-react-app'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hardcoding this won't respect the changes that user made in package.json
or .eslintrc
post eject. IMO we should wrap this line:
// @remove-on-eject-begin
configFile: require.resolve('eslint-config-react-app'),
// @remove-on-eject-end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes ... but then react-scripts lint
after eject has few errors:
/private/tmp/demo20/src/App.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
/private/tmp/demo20/src/App.test.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
/private/tmp/demo20/src/index.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
/private/tmp/demo20/src/registerServiceWorker.js
1:1 warning Definition for rule 'jsx-a11y/href-no-hash' was not found jsx-a11y/href-no-hash
✖ 4 problems (0 errors, 4 warnings)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, do you have eslint
installed globally / .eslintrc
file somewhere in the parent folder? i think we need to add root: true
to eslintConfig
property in package.json
post eject. https://eslint.org/docs/user-guide/configuring#using-configuration-files can you try adding it and see if it fix the problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sadly, no change after:
"eslintConfig": {
"root": true,
"extends": "react-app"
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also adding plugins: ['jsx-a11y']
to CLIEngine constructor options doesn't remove errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe running it with DEBUG=eslint:* yarn lint
would help you found the problem. I cannot reproduce it locally using the same code :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or DEBUG=eslint:config* yarn lint
if you just want the log related to config
a28a0f8
to
7a5ab30
Compare
E2E tests added, removed eslint config file. Huge thanks and ❤️ to @viankakrisna |
happy to help! so do you find what is the cause on the issue that you have on your machine? how do we avoid ejected users have the same issue as you? |
I haven't found the reason why this version of |
what's the output of |
Ha, it works now. Even when I install ESLinter globally. |
Might be a good idea to trigger |
That would allow chaining |
2529a76
to
67a774d
Compare
CLIEngine.outputFixes(report); | ||
console.log(formatter(report.results)); | ||
|
||
if (report.errorCount > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Condition to trigger exit(1)
could be different when a --fix
flag was used.
Report object has a count of fixable errors and it is possible to count how many unfixed errors are left:
{
'...': '...',
errorCount: 1,
fixableErrorCount: 1,
}
My concern is that in react-scripts lint --fix && git push
files will be changed by lint but they still need git commit
.
67a774d
to
7543ab4
Compare
7543ab4
to
aec1ba1
Compare
Any updates on this? |
I'm trying to understand what's missing to close this PR. I was checking if I could help, but I have the impression this is just a rebase away from being ready.
Did I get that right @maciej-ka ? |
Is this PR rejected? |
Adds lint command to react-scripts.
Typical use will be to:
EDIT: PR provides a default configuration for ESlinter, so these are no longer needed:
2.yarn lint --init
3.yarn
to install new dependencies4.yarn lint
to useScript passes all options to eslint, so this will work
yarn lint --fix
. Files checked are: .js, .jsx and .mjs in src folder. This includes test files too.