diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index 6bb7897ff63..1a74ffcd3ef 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -7,6 +7,8 @@ 'use strict'; +const resolveNodePath = require('./utils/resolveNodePath'); + // Inspired by https://github.com/airbnb/javascript but less opinionated. // We use eslint-loader so even warnings are very visible. @@ -48,6 +50,17 @@ module.exports = { }, }, + settings: { + 'import/ignore': ['node_modules'], + 'import/extensions': ['.js'], + 'import/resolver': { + node: { + extensions: ['.js', '.json'], + moduleDirectory: ['node_modules'].concat(resolveNodePath()), + }, + }, + }, + rules: { // http://eslint.org/docs/rules/ 'array-callback-return': 'warn', @@ -185,6 +198,7 @@ module.exports = { 'import/first': 'error', 'import/no-amd': 'error', 'import/no-webpack-loader-syntax': 'error', + 'import/no-extraneous-dependencies': 'error', // https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules 'react/jsx-no-comment-textnodes': 'warn', diff --git a/packages/eslint-config-react-app/package.json b/packages/eslint-config-react-app/package.json index 6f2b244a1e5..d92d13a2079 100644 --- a/packages/eslint-config-react-app/package.json +++ b/packages/eslint-config-react-app/package.json @@ -8,6 +8,7 @@ "url": "https://github.com/facebookincubator/create-react-app/issues" }, "files": [ + "utils", "index.js" ], "peerDependencies": { diff --git a/packages/eslint-config-react-app/utils/resolveNodePath.js b/packages/eslint-config-react-app/utils/resolveNodePath.js new file mode 100644 index 00000000000..5e9795ae97a --- /dev/null +++ b/packages/eslint-config-react-app/utils/resolveNodePath.js @@ -0,0 +1,11 @@ +'use strict'; + +function resolveNodePath() { + const nodePaths = (process.env.NODE_PATH || '') + .split(process.platform === 'win32' ? ';' : ':') + .filter(Boolean); + + return nodePaths; +} + +module.exports = resolveNodePath; diff --git a/packages/react-dev-utils/WatchPackageJsonPlugin.js b/packages/react-dev-utils/WatchPackageJsonPlugin.js new file mode 100644 index 00000000000..513c5007c3f --- /dev/null +++ b/packages/react-dev-utils/WatchPackageJsonPlugin.js @@ -0,0 +1,51 @@ +'use strict'; + +// This Webpack plugin ensures that package.json is watched for changes and +// that appropriate actions are triggered, e.g. an eslint-loader recheck. + +class WatchPackageJsonPlugin { + constructor(packageJsonPath) { + this.packageJsonPath = packageJsonPath; + this.erroneousFiles = []; + } + + apply(compiler) { + compiler.plugin('compilation', compilation => { + const timestamp = compilation.fileTimestamps[this.packageJsonPath] || 0; + + if (timestamp > this.previousTimestamp && this.erroneousFiles.length) { + this.erroneousFiles.forEach(filename => { + compilation.fileTimestamps[filename] = timestamp; + }); + } + }); + + compiler.plugin('emit', (compilation, callback) => { + // Add package.json to the list of watched files. This needs to be done + // for every compilation run since the list is rebuilt every time. + compilation.fileDependencies.push(this.packageJsonPath); + + this.previousTimestamp = compilation.fileTimestamps[ + this.packageJsonPath + ] || 0; + + // First we extract all files related to any occurred errors. Then + // we remove any request params that could have been added by a plugin, + // loader or the user. + this.erroneousFiles = compilation.errors + .reduce( + (acc, error) => { + acc.push.apply(acc, error.dependencies); + + return acc; + }, + [] + ) + .map(entry => entry.request.replace(/\?.*$/)); + + callback(); + }); + } +} + +module.exports = WatchPackageJsonPlugin; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index da1a4e53329..bc78cb273d7 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -33,6 +33,7 @@ "openChrome.applescript", "printHostingInstructions.js", "WatchMissingNodeModulesPlugin.js", + "WatchPackageJsonPlugin.js", "WebpackDevServerUtils.js", "webpackHotDevClient.js" ], diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index c975a58c790..8933c144967 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -15,6 +15,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); +const WatchPackageJsonPlugin = require('react-dev-utils/WatchPackageJsonPlugin'); const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const getClientEnvironment = require('./env'); @@ -284,6 +285,9 @@ module.exports = { // makes the discovery automatic so you don't have to restart. // See https://github.com/facebookincubator/create-react-app/issues/186 new WatchMissingNodeModulesPlugin(paths.appNodeModules), + // This Webpack plugin ensures that package.json is watched for changes and + // that appropriate actions are triggered, e.g. an eslint-loader recheck. + new WatchPackageJsonPlugin(paths.appPackageJson), // Moment.js is an extremely popular library that bundles large locale files // by default due to how Webpack interprets its code. This is a practical // solution that requires the user to opt into importing specific locales.