diff --git a/packages/babel-cli/src/babel/dir.ts b/packages/babel-cli/src/babel/dir.ts index c65536a3e93f..69fb12b993ff 100644 --- a/packages/babel-cli/src/babel/dir.ts +++ b/packages/babel-cli/src/babel/dir.ts @@ -149,31 +149,32 @@ export default async function ({ startTime = null; }, 100); - if (cliOptions.watch) watcher.enable({ enableGlobbing: true }); - - if (!cliOptions.skipInitialBuild) { - if (cliOptions.deleteDirOnStart) { - util.deleteDir(cliOptions.outDir); - } + const initialBuild = async () => { + if (!cliOptions.skipInitialBuild) { + if (cliOptions.deleteDirOnStart) { + util.deleteDir(cliOptions.outDir); + } - fs.mkdirSync(cliOptions.outDir, { recursive: true }); + fs.mkdirSync(cliOptions.outDir, { recursive: true }); - startTime = process.hrtime(); + startTime = process.hrtime(); - for (const filename of cliOptions.filenames) { - // compiledFiles is just incremented without reading its value, so we - // don't risk race conditions. - // eslint-disable-next-line require-atomic-updates - compiledFiles += await handle(filename); - } + for (const filename of cliOptions.filenames) { + // compiledFiles is just incremented without reading its value, so we + // don't risk race conditions. + // eslint-disable-next-line require-atomic-updates + compiledFiles += await handle(filename); + } - if (!cliOptions.quiet) { - logSuccess(); - logSuccess.flush(); + if (!cliOptions.quiet) { + logSuccess(); + logSuccess.flush(); + } } - } + }; if (cliOptions.watch) { + watcher.enable({ enableGlobbing: true }); // This, alongside with debounce, allows us to only log // when we are sure that all the files have been compiled. let processing = 0; @@ -242,5 +243,9 @@ export default async function ({ processing--; if (processing === 0 && !cliOptions.quiet) logSuccess(); }); + + watcher.onReady(initialBuild); + } else { + await initialBuild(); } } diff --git a/packages/babel-cli/src/babel/file.ts b/packages/babel-cli/src/babel/file.ts index ac80c9caba42..2b4e0c42818f 100644 --- a/packages/babel-cli/src/babel/file.ts +++ b/packages/babel-cli/src/babel/file.ts @@ -191,15 +191,13 @@ export default async function ({ } async function files(filenames: Array): Promise { + const initialBuild = async () => { + if (!cliOptions.skipInitialBuild) { + await walk(filenames); + } + }; if (cliOptions.watch) { watcher.enable({ enableGlobbing: false }); - } - - if (!cliOptions.skipInitialBuild) { - await walk(filenames); - } - - if (cliOptions.watch) { filenames.forEach(watcher.watch); watcher.onFilesChange((changes, event, cause) => { @@ -218,6 +216,10 @@ export default async function ({ console.error(err); }); }); + + watcher.onReady(initialBuild); + } else { + await initialBuild(); } } diff --git a/packages/babel-cli/src/babel/watcher.ts b/packages/babel-cli/src/babel/watcher.ts index 0c1d3756984e..02d69f61c587 100644 --- a/packages/babel-cli/src/babel/watcher.ts +++ b/packages/babel-cli/src/babel/watcher.ts @@ -51,16 +51,30 @@ export function onFilesChange( ); } - watcher.on("all", (event, filename) => { - if (event !== "change" && event !== "add") return; - + const listenerFactory = event => filename => { const absoluteFile = path.resolve(filename); callback( [absoluteFile, ...(depToFiles.get(absoluteFile) ?? [])], event, absoluteFile, ); - }); + }; + + watcher.on("add", listenerFactory("add")); + watcher.on("change", listenerFactory("change")); +} + +/** + * Call @param callback when watcher is ready for changes. + */ +export function onReady(callback: () => void): void { + if (!isWatchMode) { + throw new Error( + "Internal Babel error: .onReady called when not in watch mode.", + ); + } + + watcher.on("ready", callback); } export function updateExternalDependencies( diff --git a/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch --verbose with external dependencies/executor.js b/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch --verbose with external dependencies/executor.js index fcf460a0347b..13e64114e2be 100644 --- a/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch --verbose with external dependencies/executor.js +++ b/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch --verbose with external dependencies/executor.js @@ -4,7 +4,7 @@ const assert = require("assert"); // For Node.js <= 10 if (!assert.match) assert.match = (val, re) => assert(re.test(val)); -const run = (async function* () { +const run = (function* () { let files = [yield, yield].sort(); assert.match(files[0], /src[\\/]index.js -> lib[\\/]index.js/); assert.match(files[1], /src[\\/]main.js -> lib[\\/]main.js/); @@ -12,8 +12,6 @@ const run = (async function* () { logFile("lib/index.js"); logFile("lib/main.js"); - // wait 200ms for watcher setup - await new Promise(resolve => setTimeout(resolve, 200)); fs.writeFileSync("./file.txt", "Updated!"); files = [yield, yield].sort(); @@ -30,7 +28,7 @@ run.next(); const batchedStrings = []; let batchId = 0; -process.stdin.on("data", async function listener(chunk) { +process.stdin.on("data", function listener(chunk) { const str = String(chunk).trim(); if (!str) return; @@ -51,7 +49,7 @@ process.stdin.on("data", async function listener(chunk) { console.log(str); } - if ((await run.next(str)).done) { + if (run.next(str).done) { process.exit(0); } }); diff --git a/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch multiple dir/executor.js b/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch multiple dir/executor.js index 1d480afb2637..ddd810e3aa90 100644 --- a/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch multiple dir/executor.js +++ b/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch multiple dir/executor.js @@ -4,11 +4,9 @@ const assert = require("assert"); // For Node.js <= 10 if (!assert.match) assert.match = (val, re) => assert(re.test(val)); -const run = (async function* () { +const run = (function* () { assert.match(yield, /Successfully compiled 4 files with Babel \(\d+ms\)\./); - // wait 200ms for watcher setup - await new Promise(resolve => setTimeout(resolve, 200)); // update ./module1/src/index.js fs.writeFileSync( "./module1/src/index.js", @@ -20,13 +18,13 @@ const run = (async function* () { run.next(); -process.stdin.on("data", async function listener(chunk) { +process.stdin.on("data", function listener(chunk) { const str = String(chunk).trim(); if (!str) return; console.log(str); - if ((await run.next(str)).done) { + if (run.next(str).done) { process.exit(0); } }); diff --git a/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch with external dependencies/executor.js b/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch with external dependencies/executor.js index 29730dc333e3..e22bb7e8e46f 100644 --- a/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch with external dependencies/executor.js +++ b/packages/babel-cli/test/fixtures/babel/dir --out-dir --watch with external dependencies/executor.js @@ -4,13 +4,11 @@ const assert = require("assert"); // For Node.js <= 10 if (!assert.match) assert.match = (val, re) => assert(re.test(val)); -const run = (async function* () { +const run = (function* () { assert.match(yield, /Successfully compiled 2 files with Babel \(\d+ms\)\./); logFile("lib/index.js"); logFile("lib/main.js"); - // wait 200ms for watcher setup - await new Promise(resolve => setTimeout(resolve, 200)); fs.writeFileSync("./file.txt", "Updated!"); assert.match(yield, /Successfully compiled 2 files with Babel \(\d+ms\)\./); @@ -21,13 +19,13 @@ const run = (async function* () { run.next(); -process.stdin.on("data", async function listener(chunk) { +process.stdin.on("data", function listener(chunk) { const str = String(chunk).trim(); if (!str) return; console.log(str); - if ((await run.next(str)).done) { + if (run.next(str).done) { process.exit(0); } });