From af4cd330e91197fd88d826fd17440452f64e5c8a Mon Sep 17 00:00:00 2001 From: Jasper De Moor Date: Mon, 21 May 2018 21:16:09 +0200 Subject: [PATCH] Put filewatcher in a worker, for better stability and performance (#1368) --- package.json | 2 +- src/Bundler.js | 4 ++ src/Watcher.js | 23 +++++------- test/hmr.js | 52 ++++++++++++++++++++++++++ test/watcher.js | 3 ++ yarn.lock | 99 ++++++++++++++++++++++++++----------------------- 6 files changed, 123 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index a0693ec0357..15f0a1ddae3 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "babylon-walk": "^1.0.2", "browserslist": "^3.2.6", "chalk": "^2.1.0", - "chokidar": "^2.0.3", "command-exists": "^1.2.6", "commander": "^2.11.0", "cross-spawn": "^6.0.4", @@ -31,6 +30,7 @@ "deasync": "^0.1.13", "dotenv": "^5.0.0", "filesize": "^3.6.0", + "fswatcher-child": "^1.0.3", "get-port": "^3.2.0", "glob": "^7.1.2", "grapheme-breaker": "^0.3.2", diff --git a/src/Bundler.js b/src/Bundler.js index b1789be5b81..1e0a14ddf32 100644 --- a/src/Bundler.js +++ b/src/Bundler.js @@ -324,6 +324,10 @@ class Bundler extends EventEmitter { if (this.options.watch) { this.watcher = new Watcher(); + // Wait for ready event for reliable testing on watcher + if (process.env.NODE_ENV === 'test' && !this.watcher.ready) { + await new Promise(resolve => this.watcher.once('ready', resolve)); + } this.watcher.on('change', this.onChange.bind(this)); } diff --git a/src/Watcher.js b/src/Watcher.js index e6b68c8bc8c..49d673fd32b 100644 --- a/src/Watcher.js +++ b/src/Watcher.js @@ -1,4 +1,4 @@ -const {FSWatcher} = require('chokidar'); +const FSWatcher = require('fswatcher-child'); const Path = require('path'); /** @@ -13,20 +13,12 @@ class Watcher { this.watcher = new FSWatcher({ useFsEvents: this.shouldWatchDirs, ignoreInitial: true, + ignorePermissionErrors: true, ignored: /\.cache|\.git/ }); this.watchedDirectories = new Map(); - - // Only close the watcher after the ready event is emitted - this.ready = false; this.stopped = false; - this.watcher.once('ready', () => { - this.ready = true; - if (this.stopped) { - this.watcher.close(); - } - }); } /** @@ -124,14 +116,19 @@ class Watcher { this.watcher.on(event, callback); } + /** + * Add an event handler + */ + once(event, callback) { + this.watcher.once(event, callback); + } + /** * Stop watching all paths */ stop() { this.stopped = true; - if (this.ready) { - this.watcher.close(); - } + this.watcher.close(); } } diff --git a/test/hmr.js b/test/hmr.js index c4bd53ad343..15601d56b11 100644 --- a/test/hmr.js +++ b/test/hmr.js @@ -54,6 +54,10 @@ describe('hmr', function() { const buildEnd = nextEvent(b, 'buildEnd'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'exports.a = 5;\nexports.b = 5;' @@ -99,6 +103,10 @@ describe('hmr', function() { const buildEnd = nextEvent(b, 'buildEnd'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'exports.a = 5; exports.b = 5;' @@ -123,6 +131,10 @@ describe('hmr', function() { const buildEnd = nextEvent(b, 'buildEnd'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'require("fs"); exports.a = 5; exports.b = 5;' @@ -145,6 +157,10 @@ describe('hmr', function() { const buildEnd = nextEvent(b, 'buildEnd'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'require("fs"; exports.a = 5; exports.b = 5;' @@ -173,6 +189,10 @@ describe('hmr', function() { b = bundler(__dirname + '/input/index.js', {watch: true, hmr: true}); await b.bundle(); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'require("fs"; exports.a = 5; exports.b = 5;' @@ -195,6 +215,10 @@ describe('hmr', function() { const firstBuildEnd = nextEvent(b, 'buildEnd'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'require("fs"; exports.a = 5; exports.b = 5;' @@ -233,6 +257,10 @@ describe('hmr', function() { assert.deepEqual(outputs, [3]); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'exports.a = 5; exports.b = 5;' @@ -261,6 +289,10 @@ describe('hmr', function() { assert.deepEqual(outputs, [3]); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'exports.a = 5; exports.b = 5;' @@ -292,6 +324,10 @@ describe('hmr', function() { await sleep(50); assert.deepEqual(outputs, [3]); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'exports.a = 5; exports.b = 5;' @@ -324,6 +360,10 @@ describe('hmr', function() { let spy = sinon.spy(ctx.document.body, 'appendChild'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'require("fs"; exports.a = 5; exports.b = 5;' @@ -362,6 +402,10 @@ describe('hmr', function() { let appendSpy = sinon.spy(ctx.document.body, 'appendChild'); let removeSpy = sinon.spy(ctx.document.getElementById('tmp'), 'remove'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'require("fs"; exports.a = 5; exports.b = 5;' @@ -401,6 +445,10 @@ describe('hmr', function() { const buildEnd = nextEvent(b, 'buildEnd'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'exports.a = 5;\nexports.b = 5;' @@ -434,6 +482,10 @@ describe('hmr', function() { const buildEnd = nextEvent(b, 'buildEnd'); + if (process.platform === 'win32') { + await sleep(100); + } + fs.writeFileSync( __dirname + '/input/local.js', 'exports.a = 5;\nexports.b = 5;' diff --git a/test/watcher.js b/test/watcher.js index beef708c431..c6986720ed2 100644 --- a/test/watcher.js +++ b/test/watcher.js @@ -239,6 +239,9 @@ describe('watcher', function() { fs.readFileSync(__dirname + '/input/.babelrc', 'utf8') ); babelrc.presets[0][1].targets.browsers.push('IE >= 11'); + + await sleep(100); + fs.writeFileSync(__dirname + '/input/.babelrc', JSON.stringify(babelrc)); await nextBundle(b); diff --git a/yarn.lock b/yarn.lock index f69d7348bb7..f16688065b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -294,7 +294,7 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" -atob@^2.0.0: +atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" @@ -2495,6 +2495,12 @@ fstream@^1.0.0, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" +fswatcher-child@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fswatcher-child/-/fswatcher-child-1.0.3.tgz#c89076126a3004909f6f68c0ea5c9d9143b237fd" + dependencies: + chokidar "^2.0.3" + function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -2751,8 +2757,8 @@ grapheme-breaker@^0.3.2: unicode-trie "^0.3.1" graphql-tag@^2.6.0: - version "2.9.1" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.9.1.tgz#1ab090ef7d3518b06d8c97d1393672145fe91587" + version "2.9.2" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.9.2.tgz#2f60a5a981375f430bf1e6e95992427dc18af686" graphql@^0.11.7: version "0.11.7" @@ -2990,10 +2996,10 @@ iconv-lite@0.4.19: resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" iconv-lite@^0.4.17, iconv-lite@^0.4.4: - version "0.4.21" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: - safer-buffer "^2.1.0" + safer-buffer ">= 2.1.2 < 3" icss-replace-symbols@1.1.0, icss-replace-symbols@^1.1.0: version "1.1.0" @@ -3763,8 +3769,8 @@ left-pad@^1.2.0: resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" less@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/less/-/less-3.0.2.tgz#1bcb9813bb6090c884ac142f02c633bd42931844" + version "3.0.4" + resolved "https://registry.yarnpkg.com/less/-/less-3.0.4.tgz#d27dcedbac96031c9e7b76f1da1e4b7d83760814" optionalDependencies: errno "^0.1.1" graceful-fs "^4.1.2" @@ -3773,7 +3779,7 @@ less@^3.0.1: mkdirp "^0.5.0" promise "^7.1.1" request "^2.83.0" - source-map "^0.5.3" + source-map "~0.6.0" leven@^2.1.0: version "2.1.0" @@ -3787,8 +3793,8 @@ levn@^0.3.0, levn@~0.3.0: type-check "~0.3.2" lint-staged@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.0.5.tgz#1ed04c4bb2013579a3d4df4dfe0f2ea1cd988fad" + version "7.1.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.1.0.tgz#1514a5b71b8d9492ca0c3d2a44769cbcbc8bcc79" dependencies: app-root-path "^2.0.1" chalk "^2.3.1" @@ -3799,6 +3805,7 @@ lint-staged@^7.0.5: execa "^0.9.0" find-parent-dir "^0.3.0" is-glob "^4.0.0" + is-windows "^1.0.2" jest-validate "^22.4.0" listr "^0.13.0" lodash "^4.17.5" @@ -4130,8 +4137,8 @@ log-update@^1.0.2: cli-cursor "^1.0.2" lolex@^2.2.0, lolex@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.3.2.tgz#85f9450425103bf9e7a60668ea25dc43274ca807" + version "2.5.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.5.0.tgz#69d6a667607738564daf108f63240ae8cbd28fb4" longest@^1.0.1: version "1.0.1" @@ -4157,8 +4164,8 @@ lru-cache@^3.2.0: pseudomap "^1.0.1" lru-cache@^4.0.1, lru-cache@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" dependencies: pseudomap "^1.0.2" yallist "^2.1.2" @@ -4245,7 +4252,7 @@ merge-source-map@1.0.4: dependencies: source-map "^0.5.6" -merge-source-map@^1.0.2, merge-source-map@^1.1.0: +merge-source-map@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" dependencies: @@ -4269,7 +4276,7 @@ micromatch@^2.1.5, micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.0.4, micromatch@^3.1.4, micromatch@^3.1.8: +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" dependencies: @@ -4343,8 +4350,8 @@ minimist@~0.0.1: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" minipass@^2.2.1, minipass@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.4.tgz#03c824d84551ec38a8d1bb5bc350a5a30a354a40" + version "2.3.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.0.tgz#2e11b1c46df7fe7f1afbe9a490280add21ffe384" dependencies: safe-buffer "^5.1.1" yallist "^3.0.0" @@ -4646,8 +4653,8 @@ nwmatcher@^1.4.3: resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" nyc@^11.1.0: - version "11.7.1" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-11.7.1.tgz#7cb0a422e501b88ff2c1634341dec2560299d67b" + version "11.7.3" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-11.7.3.tgz#164f4cfad84dee6d8f353824231d9dd683aa14ea" dependencies: archy "^1.0.0" arrify "^1.0.1" @@ -4666,11 +4673,11 @@ nyc@^11.1.0: istanbul-lib-source-maps "^1.2.3" istanbul-reports "^1.4.0" md5-hex "^1.2.0" - merge-source-map "^1.0.2" - micromatch "^2.3.11" + merge-source-map "^1.1.0" + micromatch "^3.1.10" mkdirp "^0.5.0" resolve-from "^2.0.0" - rimraf "^2.5.4" + rimraf "^2.6.2" signal-exit "^3.0.1" spawn-wrap "^1.4.2" test-exclude "^4.2.0" @@ -5321,8 +5328,8 @@ posthtml-parser@^0.4.0: object-assign "^4.1.1" posthtml-render@^1.1.0, posthtml-render@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-1.1.3.tgz#53e91c3debd0e7443704efa299329e1e10867f0e" + version "1.1.4" + resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-1.1.4.tgz#95dac09892f4f183fad5ac823f08f42c0256551e" posthtml@^0.11.2, posthtml@^0.11.3: version "0.11.3" @@ -5513,8 +5520,8 @@ qs@~6.3.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" qs@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" query-string@^4.1.0: version "4.3.4" @@ -5596,7 +5603,7 @@ read-pkg@^1.0.0: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@~2.3.3: +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -5639,8 +5646,8 @@ reduce-function-call@^1.0.1: balanced-match "^0.4.2" regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" regenerator-runtime@^0.10.5: version "0.10.5" @@ -5854,7 +5861,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@^2.2.8, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -5899,7 +5906,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -safer-buffer@^2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -6047,8 +6054,8 @@ signal-exit@^3.0.0, signal-exit@^3.0.1, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" sinon@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-5.0.1.tgz#e399e00b30df53abf816f16cfc8f3aa0a480ada2" + version "5.0.7" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-5.0.7.tgz#3bded6a73613ccc9e512e20246ced69a27c27dab" dependencies: "@sinonjs/formatio" "^2.0.0" diff "^3.1.0" @@ -6122,10 +6129,10 @@ sort-keys@^1.0.0: is-plain-obj "^1.0.0" source-map-resolve@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" dependencies: - atob "^2.0.0" + atob "^2.1.1" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" @@ -6138,8 +6145,8 @@ source-map-support@^0.4.15: source-map "^0.5.6" source-map-support@^0.5.0: - version "0.5.5" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.5.tgz#0d4af9e00493e855402e8ec36ebed2d266fceb90" + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -6158,7 +6165,7 @@ source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, sourc version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -6260,8 +6267,8 @@ static-extend@^0.1.1: object-copy "^0.1.0" static-module@^2.2.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/static-module/-/static-module-2.2.4.tgz#25a3ffbe6e1fdaf7e64e5bc21edcd77fc7708dac" + version "2.2.5" + resolved "https://registry.yarnpkg.com/static-module/-/static-module-2.2.5.tgz#bd40abceae33da6b7afb84a0e4329ff8852bfbbf" dependencies: concat-stream "~1.6.0" convert-source-map "^1.5.1" @@ -6304,12 +6311,12 @@ stream-browserify@^2.0.1: readable-stream "^2.0.2" stream-http@^2.7.2: - version "2.8.1" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.1.tgz#d0441be1a457a73a733a8a7b53570bebd9ef66a4" + version "2.8.2" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.2.tgz#4126e8c6b107004465918aa2fc35549e77402c87" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" - readable-stream "^2.3.3" + readable-stream "^2.3.6" to-arraybuffer "^1.0.0" xtend "^4.0.0"