Skip to content

Commit

Permalink
cli: handle multiple input sources in watch mode (#14281)
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung committed Feb 21, 2022
1 parent 300e477 commit c4dc52e
Show file tree
Hide file tree
Showing 18 changed files with 152 additions and 35 deletions.
84 changes: 60 additions & 24 deletions packages/babel-cli/src/babel/dir.ts
Expand Up @@ -177,34 +177,70 @@ export default async function ({
// This, alongside with debounce, allows us to only log
// when we are sure that all the files have been compiled.
let processing = 0;
const { filenames } = cliOptions;
let getBase;
if (filenames.length === 1) {
// fast path: If there is only one filenames, we know it must be the base
const base = filenames[0];
const absoluteBase = path.resolve(base);
getBase = filename => {
return filename === absoluteBase ? path.dirname(base) : base;
};
} else {
// A map from absolute compiled file path to its base, from which
// the output destination will be determined
const filenameToBaseMap: Map<string, string> = new Map(
filenames.map(filename => {
const absoluteFilename = path.resolve(filename);
return [absoluteFilename, path.dirname(filename)];
}),
);

const absoluteFilenames: Map<string, string> = new Map(
filenames.map(filename => {
const absoluteFilename = path.resolve(filename);
return [absoluteFilename, filename];
}),
);

const { sep } = path;
// determine base from the absolute file path
getBase = filename => {
const base = filenameToBaseMap.get(filename);
if (base !== undefined) {
return base;
}
for (const [absoluteFilenameOrDir, relative] of absoluteFilenames) {
if (filename.startsWith(absoluteFilenameOrDir + sep)) {
filenameToBaseMap.set(filename, relative);
return relative;
}
}
// Can't determine the base, probably external deps
return "";
};
}

cliOptions.filenames.forEach(filenameOrDir => {
filenames.forEach(filenameOrDir => {
watcher.watch(filenameOrDir);
});

watcher.onFilesChange(async filenames => {
processing++;
if (startTime === null) startTime = process.hrtime();

try {
const written = await Promise.all(
filenames.map(filename =>
handleFile(
filename,
filename === filenameOrDir
? path.dirname(filenameOrDir)
: filenameOrDir,
),
),
);

compiledFiles += written.filter(Boolean).length;
} catch (err) {
console.error(err);
}
watcher.onFilesChange(async filenames => {
processing++;
if (startTime === null) startTime = process.hrtime();

processing--;
if (processing === 0 && !cliOptions.quiet) logSuccess();
});
try {
const written = await Promise.all(
filenames.map(filename => handleFile(filename, getBase(filename))),
);

compiledFiles += written.filter(Boolean).length;
} catch (err) {
console.error(err);
}

processing--;
if (processing === 0 && !cliOptions.quiet) logSuccess();
});
}
}
Expand Up @@ -4,15 +4,16 @@ const assert = require("assert");
// For Node.js <= 10
if (!assert.match) assert.match = (val, re) => assert(re.test(val));

const run = (function* () {
const run = (async 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/);
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!");

files = [yield, yield].sort();
Expand All @@ -29,7 +30,7 @@ run.next();
const batchedStrings = [];
let batchId = 0;

process.stdin.on("data", function listener(chunk) {
process.stdin.on("data", async function listener(chunk) {
const str = String(chunk).trim();
if (!str) return;

Expand All @@ -50,7 +51,7 @@ process.stdin.on("data", function listener(chunk) {
console.log(str);
}

if (run.next(str).done) {
if ((await run.next(str)).done) {
process.exit(0);
}
});
Expand Down
Expand Up @@ -2,5 +2,5 @@
"args": ["src", "--out-dir", "lib", "--watch", "--verbose"],
"noBabelrc": true,
"noDefaultPlugins": true,
"minNodeVersion": 8
"minNodeVersion": 10
}
@@ -0,0 +1,37 @@
const fs = require("fs");
const assert = require("assert");

// For Node.js <= 10
if (!assert.match) assert.match = (val, re) => assert(re.test(val));

const run = (async 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",
`let str = REPLACE_ME + REPLACE_ME;`
);

assert.match(yield, /Successfully compiled 1 file with Babel \(\d+ms\)\./);
})();

run.next();

process.stdin.on("data", async function listener(chunk) {
const str = String(chunk).trim();
if (!str) return;

console.log(str);

if ((await run.next(str)).done) {
process.exit(0);
}
});

setTimeout(() => {
console.error("EXECUTOR TIMEOUT");
process.exit(1);
}, 5000);
@@ -0,0 +1,25 @@
const fs = require("fs");
const path = require("path");

function inlinePlugin(api, { filename }) {
const { types: t } = api;

const contents = api.cache.using(() => fs.readFileSync(filename, "utf8"));
api.addExternalDependency(filename);

return {
visitor: {
Identifier(path) {
if (path.node.name === "REPLACE_ME") {
path.replaceWith(t.stringLiteral(contents));
}
},
},
};
}

module.exports = {
plugins: [
[inlinePlugin, { filename: path.resolve(__dirname, "./file.txt") }],
],
};
@@ -0,0 +1 @@
Hi :)
@@ -0,0 +1 @@
let str = REPLACE_ME;
@@ -0,0 +1 @@
console.log(REPLACE_ME);
@@ -0,0 +1 @@
let str = REPLACE_ME;
@@ -0,0 +1 @@
console.log(REPLACE_ME);
@@ -0,0 +1,6 @@
{
"args": ["*/src", "--out-dir", "../lib", "--relative", "--watch"],
"noBabelrc": true,
"noDefaultPlugins": true,
"minNodeVersion": 10
}
@@ -0,0 +1 @@
let str = "Hi :)" + "Hi :)";
@@ -0,0 +1 @@
console.log("Hi :)");
@@ -0,0 +1 @@
let str = "Hi :)";
@@ -0,0 +1 @@
console.log("Hi :)");
@@ -0,0 +1,2 @@
Successfully compiled 4 files with Babel (123ms).
Successfully compiled 1 file with Babel (123ms).
Expand Up @@ -4,29 +4,30 @@ const assert = require("assert");
// For Node.js <= 10
if (!assert.match) assert.match = (val, re) => assert(re.test(val));

const run = function* () {
const run = (async 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\)\./);

logFile("lib/index.js");
logFile("lib/main.js");
}();
})();

run.next();

process.stdin.on("data", function listener(chunk) {
process.stdin.on("data", async function listener(chunk) {
const str = String(chunk).trim();
if (!str) return;

console.log(str);

if (run.next(str).done) {
if ((await run.next(str)).done) {
process.exit(0);
}
});
Expand Down
Expand Up @@ -2,5 +2,5 @@
"args": ["src", "--out-dir", "lib", "--watch"],
"noBabelrc": true,
"noDefaultPlugins": true,
"minNodeVersion": 8
"minNodeVersion": 10
}

0 comments on commit c4dc52e

Please sign in to comment.