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.