From 8e15dc2072220828ce9a1c8a98be6610180b72a2 Mon Sep 17 00:00:00 2001 From: Robin Ricard Date: Tue, 6 Dec 2016 01:37:34 +0100 Subject: [PATCH 1/6] Watch test files (so they retrigger webpack) This will not process them for now... --- .../react-dev-utils/WatchTestFilesPlugin.js | 39 +++++++++++++++++++ packages/react-dev-utils/package.json | 2 + .../config/webpack.config.dev.js | 10 ++++- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 packages/react-dev-utils/WatchTestFilesPlugin.js diff --git a/packages/react-dev-utils/WatchTestFilesPlugin.js b/packages/react-dev-utils/WatchTestFilesPlugin.js new file mode 100644 index 00000000000..039a66501e6 --- /dev/null +++ b/packages/react-dev-utils/WatchTestFilesPlugin.js @@ -0,0 +1,39 @@ +var glob = require('glob'); +var path = require('path'); + +function computeGlob(pattern, options) { + return new Promise((resolve, reject) => { + glob(pattern, options || {}, (err, matches) => { + if (err) { + return reject(err); + } + resolve(matches); + }); + }); +} + +function WatchTestFilesPlugin(testGlobs) { + this.testGlobs = testGlobs || []; +} + +WatchTestFilesPlugin.prototype.apply = function(compiler) { + compiler.plugin('emit', (compilation, callback) => { + console.log() + Promise.all(this.testGlobs.map(globPattern => + computeGlob(globPattern, { + cwd: compiler.options.context, + ignore: 'node_modules/**', + }) + )) + .then(globLists => [].concat.apply([], globLists)) + .then(testFiles => { + testFiles.forEach(testFile => { + compilation.fileDependencies.push(path.join(compiler.options.context, testFile)); + }); + }) + .then(callback) + .catch(console.error); + }); +}; + +module.exports = WatchTestFilesPlugin; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index 5d8051a8830..9811f261f06 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -20,12 +20,14 @@ "openBrowser.js", "prompt.js", "WatchMissingNodeModulesPlugin.js", + "WatchTestFilesPlugin.js", "webpackHotDevClient.js" ], "dependencies": { "ansi-html": "0.0.5", "chalk": "1.1.3", "escape-string-regexp": "1.0.5", + "glob": "^7.1.1", "html-entities": "1.2.0", "opn": "4.0.2", "sockjs-client": "1.0.3", diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index 96fd632b795..7677b8b5011 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -15,6 +15,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin'); var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); +var WatchTestFilesPlugin = require('react-dev-utils/WatchTestFilesPlugin'); var getClientEnvironment = require('./env'); var paths = require('./paths'); @@ -226,7 +227,14 @@ module.exports = { // to restart the development server for Webpack to discover it. This plugin // 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) + new WatchMissingNodeModulesPlugin(paths.appNodeModules), + // Tests won't have any linting unless they go through webpack. + // This plugin makes webpack aware of them without emitting them. + // See https://github.com/facebookincubator/create-react-app/issues/1169 + new WatchTestFilesPlugin([ + '**/__tests__/**', + '**/*.test.js', + ]), ], // 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 19f86d155d465235077a1342f7cb3ffb4fecd89b Mon Sep 17 00:00:00 2001 From: Robin Ricard Date: Tue, 6 Dec 2016 02:23:54 +0100 Subject: [PATCH 2/6] Structure where to put upcoming module addition --- .../react-dev-utils/WatchTestFilesPlugin.js | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/packages/react-dev-utils/WatchTestFilesPlugin.js b/packages/react-dev-utils/WatchTestFilesPlugin.js index 039a66501e6..9ce5c41d185 100644 --- a/packages/react-dev-utils/WatchTestFilesPlugin.js +++ b/packages/react-dev-utils/WatchTestFilesPlugin.js @@ -12,27 +12,40 @@ function computeGlob(pattern, options) { }); } +function getGlobs(patterns, cwd) { + return Promise.all(patterns.map(globPattern => + computeGlob(globPattern, { + cwd: cwd, + ignore: 'node_modules/**', + }) + )) + .then(globLists => [].concat.apply([], globLists)) +} + function WatchTestFilesPlugin(testGlobs) { this.testGlobs = testGlobs || []; } WatchTestFilesPlugin.prototype.apply = function(compiler) { - compiler.plugin('emit', (compilation, callback) => { - console.log() - Promise.all(this.testGlobs.map(globPattern => - computeGlob(globPattern, { - cwd: compiler.options.context, - ignore: 'node_modules/**', - }) - )) - .then(globLists => [].concat.apply([], globLists)) - .then(testFiles => { - testFiles.forEach(testFile => { - compilation.fileDependencies.push(path.join(compiler.options.context, testFile)); - }); + var testFiles = []; + compiler.plugin('make', (compilation, callback) => { + getGlobs(this.testGlobs, compiler.options.context) + .then(foundFiles => { + testFiles = foundFiles; + return Promise.all( + testFiles.map(filename => new Promise((resolve, reject) => { + // TODO: add to modules + resolve(filename); + })) + ) }) - .then(callback) - .catch(console.error); + .then(callback); + }); + compiler.plugin('emit', (compilation, callback) => { + testFiles.forEach(testFile => { + compilation.fileDependencies.push(path.join(compiler.options.context, testFile)); + }); + callback(); }); }; From e0d373b213faaa3961e7c29d6e430caeca8339b4 Mon Sep 17 00:00:00 2001 From: Robin Ricard Date: Thu, 8 Dec 2016 18:08:50 +0100 Subject: [PATCH 3/6] Create some sub compilations for tests This result will not be used for serving the pages but will be used for tracking lint/type errors in those files --- .../react-dev-utils/WatchTestFilesPlugin.js | 60 +++++++++++++------ packages/react-dev-utils/package.json | 6 ++ 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/packages/react-dev-utils/WatchTestFilesPlugin.js b/packages/react-dev-utils/WatchTestFilesPlugin.js index 9ce5c41d185..b7b25fd4713 100644 --- a/packages/react-dev-utils/WatchTestFilesPlugin.js +++ b/packages/react-dev-utils/WatchTestFilesPlugin.js @@ -1,5 +1,7 @@ var glob = require('glob'); var path = require('path'); +var os = require('os'); +var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); function computeGlob(pattern, options) { return new Promise((resolve, reject) => { @@ -26,26 +28,48 @@ function WatchTestFilesPlugin(testGlobs) { this.testGlobs = testGlobs || []; } -WatchTestFilesPlugin.prototype.apply = function(compiler) { - var testFiles = []; - compiler.plugin('make', (compilation, callback) => { - getGlobs(this.testGlobs, compiler.options.context) - .then(foundFiles => { - testFiles = foundFiles; - return Promise.all( - testFiles.map(filename => new Promise((resolve, reject) => { - // TODO: add to modules - resolve(filename); - })) - ) - }) - .then(callback); +function compileTestFile(compiler, compilation, context, testFile) { + var outputOptions = { + filename: path.join(os.tmpdir(), '__compiledTests__', testFile), + publicPath: compilation.outputOptions.publicPath, + }; + var compilerName = "WatchTestFiles compilation for " + testFile; + var childCompiler = compilation.createChildCompiler(compilerName, outputOptions); + childCompiler.context = context; + childCompiler.apply( + new SingleEntryPlugin(context, path.join(compiler.options.context, testFile)) + ); + return new Promise((resolve, reject) => { + childCompiler.runAsChild((err, entries, childCompilation) => { + if (err) { + return reject(err); + } + resolve({ + errors: childCompilation.errors, + warnings: childCompilation.warnings, + }); + }); }); +} + +WatchTestFilesPlugin.prototype.apply = function(compiler) { compiler.plugin('emit', (compilation, callback) => { - testFiles.forEach(testFile => { - compilation.fileDependencies.push(path.join(compiler.options.context, testFile)); - }); - callback(); + getGlobs(this.testGlobs, compiler.options.context) + .then(foundFiles => Promise.all( + foundFiles.map(filename => { + // Add them to the list of watched files (for auto-reloading) + compilation.fileDependencies.push(path.join(compiler.options.context, filename)); + // Create and run a sub-compiler for the file to send it through the loaders + return compileTestFile(compiler, compilation, compiler.context, filename) + }) + )) + .then((results) => { + var errors = results.reduce((list, res) => list.concat(res.errors || []), []); + var warnings = results.reduce((list, res) => list.concat(res.warnings || []), []); + compilation.errors = compilation.errors.concat(errors); + compilation.warnings = compilation.warnings.concat(warnings); + callback(); + }, callback); }); }; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index 9811f261f06..fce93d7f170 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -32,5 +32,11 @@ "opn": "4.0.2", "sockjs-client": "1.0.3", "strip-ansi": "3.0.1" + }, + "devDependencies": { + "webpack": "1.14.0" + }, + "peerDependencies": { + "webpack": "1.14.0" } } From 74705ffa9f71251b03bc9d632e4b49da79590e10 Mon Sep 17 00:00:00 2001 From: Robin Ricard Date: Thu, 8 Dec 2016 18:49:27 +0100 Subject: [PATCH 4/6] Only consider src tests --- packages/react-scripts/config/webpack.config.dev.js | 4 ++-- packages/react-scripts/config/webpack.config.prod.js | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index 7677b8b5011..f119b6e712f 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -232,8 +232,8 @@ module.exports = { // This plugin makes webpack aware of them without emitting them. // See https://github.com/facebookincubator/create-react-app/issues/1169 new WatchTestFilesPlugin([ - '**/__tests__/**', - '**/*.test.js', + 'src/**/__tests__/**', + 'src/**/*.test.js', ]), ], // Some libraries import Node modules but don't use them in the browser. diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 71509658eb7..361442f8ee1 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -16,6 +16,7 @@ var ExtractTextPlugin = require('extract-text-webpack-plugin'); var ManifestPlugin = require('webpack-manifest-plugin'); var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); var SubresourceIntegrityPlugin = require('webpack-subresource-integrity'); +var WatchTestFilesPlugin = require('react-dev-utils/WatchTestFilesPlugin'); var url = require('url'); var paths = require('./paths'); var getClientEnvironment = require('./env'); @@ -277,7 +278,14 @@ module.exports = { // Generate and inject subresources hashes in the final `index.html`. new SubresourceIntegrityPlugin({ hashFuncNames: ['sha256', 'sha384'] - }) + }), + // Tests won't have any linting unless they go through webpack. + // This plugin makes webpack aware of them without emitting them. + // See https://github.com/facebookincubator/create-react-app/issues/1169 + new WatchTestFilesPlugin([ + 'src/**/__tests__/**', + 'src/**/*.test.js', + ]) ], // 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 7489f54e0c5e03880aeaa90c3f8401809d19ca8f Mon Sep 17 00:00:00 2001 From: Robin Ricard Date: Fri, 9 Dec 2016 20:07:24 +0100 Subject: [PATCH 5/6] Ignore directories in test glob --- packages/react-dev-utils/WatchTestFilesPlugin.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-dev-utils/WatchTestFilesPlugin.js b/packages/react-dev-utils/WatchTestFilesPlugin.js index b7b25fd4713..65e16f76d44 100644 --- a/packages/react-dev-utils/WatchTestFilesPlugin.js +++ b/packages/react-dev-utils/WatchTestFilesPlugin.js @@ -18,7 +18,8 @@ function getGlobs(patterns, cwd) { return Promise.all(patterns.map(globPattern => computeGlob(globPattern, { cwd: cwd, - ignore: 'node_modules/**', + ignore: 'node_modules/**/*', + nodir: true, }) )) .then(globLists => [].concat.apply([], globLists)) From 07a556e5b0aad5779edd63d16523d6c86ce2cab7 Mon Sep 17 00:00:00 2001 From: Robin Ricard Date: Fri, 9 Dec 2016 20:53:15 +0100 Subject: [PATCH 6/6] Refine globbing --- packages/react-scripts/config/webpack.config.dev.js | 5 +++-- packages/react-scripts/config/webpack.config.prod.js | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index f119b6e712f..2937b5b78e3 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -232,8 +232,9 @@ module.exports = { // This plugin makes webpack aware of them without emitting them. // See https://github.com/facebookincubator/create-react-app/issues/1169 new WatchTestFilesPlugin([ - 'src/**/__tests__/**', - 'src/**/*.test.js', + 'src/**/__tests__/**/*', + 'src/**/*.test.*', + '__tests__/**/*', ]), ], // Some libraries import Node modules but don't use them in the browser. diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 361442f8ee1..b0426612df2 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -283,8 +283,9 @@ module.exports = { // This plugin makes webpack aware of them without emitting them. // See https://github.com/facebookincubator/create-react-app/issues/1169 new WatchTestFilesPlugin([ - 'src/**/__tests__/**', - 'src/**/*.test.js', + 'src/**/__tests__/**/*', + 'src/**/*.test.*', + '__tests__/**/*', ]) ], // Some libraries import Node modules but don't use them in the browser.