From 2a2950356d9ef33ca43e86775df4e81ce5e99ac7 Mon Sep 17 00:00:00 2001 From: Mato Ilic Date: Mon, 6 Mar 2017 22:24:16 +0100 Subject: [PATCH 1/3] activate "import/no-extraneous-dependencies" to throw an error when transitive or non-existent dependencies are imported --- packages/eslint-config-react-app/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index b909db3e21b..dfc4ad0df6d 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -200,13 +200,13 @@ module.exports = { // 'import/namespace': 'warn', // 'import/no-amd': 'warn', // 'import/no-duplicates': 'warn', - // 'import/no-extraneous-dependencies': 'warn', // 'import/no-named-as-default': 'warn', // 'import/no-named-as-default-member': 'warn', // 'import/no-unresolved': ['warn', { commonjs: true }], // We don't support configuring Webpack using import source strings, so this // is always an 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-equals-spacing': ['warn', 'never'], From 12108bd6d97d4e86c743b5ae9510d6812b5eaea4 Mon Sep 17 00:00:00 2001 From: Mato Ilic Date: Thu, 9 Mar 2017 23:19:37 +0100 Subject: [PATCH 2/3] First version of WatchPackageJsonPlugin. It takes care of recompiling erroneous files when package.json is changed, because it might resolve the issue. --- .../react-dev-utils/WatchPackageJsonPlugin.js | 51 +++++++++++++++++++ packages/react-dev-utils/package.json | 1 + .../config/webpack.config.dev.js | 4 ++ 3 files changed, 56 insertions(+) create mode 100644 packages/react-dev-utils/WatchPackageJsonPlugin.js 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 64037886a0e..710eb35ab88 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -23,6 +23,7 @@ "openChrome.applescript", "prompt.js", "WatchMissingNodeModulesPlugin.js", + "WatchPackageJsonPlugin.js", "webpackHotDevClient.js" ], "dependencies": { diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index c7948b66f6e..60e157f8d3f 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -16,6 +16,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 getClientEnvironment = require('./env'); const paths = require('./paths'); @@ -244,6 +245,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), ], // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. From 00e0f58598a5123b87fb25588e4ccb6aa088e046 Mon Sep 17 00:00:00 2001 From: Mato Ilic Date: Fri, 10 Mar 2017 21:20:33 +0100 Subject: [PATCH 3/3] ensure NODE_PATH environment variable is honored when checking for extraneous dependencies --- packages/eslint-config-react-app/index.js | 3 +++ packages/eslint-config-react-app/package.json | 1 + .../eslint-config-react-app/utils/resolveNodePath.js | 11 +++++++++++ 3 files changed, 15 insertions(+) create mode 100644 packages/eslint-config-react-app/utils/resolveNodePath.js diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index dfc4ad0df6d..c9f3640acea 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -9,6 +9,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. @@ -49,6 +51,7 @@ module.exports = { 'import/resolver': { node: { extensions: ['.js', '.json'], + moduleDirectory: ['node_modules'].concat(resolveNodePath()), }, }, }, diff --git a/packages/eslint-config-react-app/package.json b/packages/eslint-config-react-app/package.json index 855713e4f46..8d6c0714b63 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;