614 lines
13 KiB
JavaScript
614 lines
13 KiB
JavaScript
"use strict";
|
|
|
|
const path = require("path");
|
|
const { createFsFromVolume, Volume } = require("memfs");
|
|
const webpack = require("..");
|
|
|
|
const createMultiCompiler = options => {
|
|
const compiler = webpack(
|
|
Object.assign(
|
|
[
|
|
{
|
|
name: "a",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./a.js"
|
|
},
|
|
{
|
|
name: "b",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./b.js"
|
|
}
|
|
],
|
|
options
|
|
)
|
|
);
|
|
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
|
compiler.watchFileSystem = {
|
|
watch(a, b, c, d, e, f, g) {}
|
|
};
|
|
return compiler;
|
|
};
|
|
|
|
describe("MultiCompiler", function () {
|
|
jest.setTimeout(20000);
|
|
|
|
it("should trigger 'run' for each child compiler", done => {
|
|
const compiler = createMultiCompiler();
|
|
let called = 0;
|
|
|
|
compiler.hooks.run.tap("MultiCompiler test", () => called++);
|
|
compiler.run(err => {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
expect(called).toBe(2);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("should trigger 'watchRun' for each child compiler", done => {
|
|
const compiler = createMultiCompiler();
|
|
let called = 0;
|
|
|
|
compiler.hooks.watchRun.tap("MultiCompiler test", () => called++);
|
|
const watcher = compiler.watch(1000, err => {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
watcher.close();
|
|
expect(called).toBe(2);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("should not be running twice at a time (run)", done => {
|
|
const compiler = createMultiCompiler();
|
|
compiler.run((err, stats) => {
|
|
if (err) return done(err);
|
|
});
|
|
compiler.run((err, stats) => {
|
|
if (err) return done();
|
|
});
|
|
});
|
|
it("should not be running twice at a time (watch)", done => {
|
|
const compiler = createMultiCompiler();
|
|
const watcher = compiler.watch({}, (err, stats) => {
|
|
if (err) return done(err);
|
|
});
|
|
compiler.watch({}, (err, stats) => {
|
|
if (err) return watcher.close(done);
|
|
});
|
|
});
|
|
it("should not be running twice at a time (run - watch)", done => {
|
|
const compiler = createMultiCompiler();
|
|
compiler.run((err, stats) => {
|
|
if (err) return done(err);
|
|
});
|
|
compiler.watch({}, (err, stats) => {
|
|
if (err) return done();
|
|
});
|
|
});
|
|
it("should not be running twice at a time (watch - run)", done => {
|
|
const compiler = createMultiCompiler();
|
|
let watcher;
|
|
watcher = compiler.watch({}, (err, stats) => {
|
|
if (err) return done(err);
|
|
});
|
|
compiler.run((err, stats) => {
|
|
if (err) return watcher.close(done);
|
|
});
|
|
});
|
|
it("should not be running twice at a time (instance cb)", done => {
|
|
const compiler = webpack(
|
|
{
|
|
context: __dirname,
|
|
mode: "production",
|
|
entry: "./c",
|
|
output: {
|
|
path: "/",
|
|
filename: "bundle.js"
|
|
}
|
|
},
|
|
() => {}
|
|
);
|
|
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
|
compiler.run((err, stats) => {
|
|
if (err) return done();
|
|
});
|
|
});
|
|
it("should run again correctly after first compilation", done => {
|
|
const compiler = createMultiCompiler();
|
|
compiler.run((err, stats) => {
|
|
if (err) return done(err);
|
|
|
|
compiler.run((err, stats) => {
|
|
if (err) return done(err);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
it("should watch again correctly after first compilation", done => {
|
|
const compiler = createMultiCompiler();
|
|
compiler.run((err, stats) => {
|
|
if (err) return done(err);
|
|
|
|
let watcher;
|
|
watcher = compiler.watch({}, (err, stats) => {
|
|
if (err) return done(err);
|
|
watcher.close(done);
|
|
});
|
|
});
|
|
});
|
|
it("should run again correctly after first closed watch", done => {
|
|
const compiler = createMultiCompiler();
|
|
const watching = compiler.watch({}, (err, stats) => {
|
|
if (err) return done(err);
|
|
});
|
|
watching.close(() => {
|
|
compiler.run((err, stats) => {
|
|
if (err) return done(err);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
it("should watch again correctly after first closed watch", done => {
|
|
const compiler = createMultiCompiler();
|
|
const watching = compiler.watch({}, (err, stats) => {
|
|
if (err) return done(err);
|
|
});
|
|
watching.close(() => {
|
|
let watcher;
|
|
watcher = compiler.watch({}, (err, stats) => {
|
|
if (err) return done(err);
|
|
watcher.close(done);
|
|
});
|
|
});
|
|
});
|
|
it("should respect parallelism and dependencies for running", done => {
|
|
const compiler = createMultiCompiler({
|
|
parallelism: 1,
|
|
2: {
|
|
name: "c",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./a.js",
|
|
dependencies: ["d", "e"]
|
|
},
|
|
3: {
|
|
name: "d",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./a.js"
|
|
},
|
|
4: {
|
|
name: "e",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./a.js"
|
|
}
|
|
});
|
|
const events = [];
|
|
compiler.compilers.forEach(c => {
|
|
c.hooks.run.tap("test", () => {
|
|
events.push(`${c.name} run`);
|
|
});
|
|
c.hooks.done.tap("test", () => {
|
|
events.push(`${c.name} done`);
|
|
});
|
|
});
|
|
compiler.run((err, stats) => {
|
|
expect(events.join(" ")).toBe(
|
|
"a run a done b run b done d run d done e run e done c run c done"
|
|
);
|
|
done();
|
|
});
|
|
});
|
|
it("should respect parallelism and dependencies for watching", done => {
|
|
const compiler = webpack(
|
|
Object.assign(
|
|
[
|
|
{
|
|
name: "a",
|
|
mode: "development",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./a.js",
|
|
dependencies: ["b", "c"]
|
|
},
|
|
{
|
|
name: "b",
|
|
mode: "development",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./b.js"
|
|
},
|
|
{
|
|
name: "c",
|
|
mode: "development",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./a.js"
|
|
}
|
|
],
|
|
{ parallelism: 1 }
|
|
)
|
|
);
|
|
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
|
const watchCallbacks = [];
|
|
const watchCallbacksUndelayed = [];
|
|
compiler.watchFileSystem = {
|
|
watch(
|
|
files,
|
|
directories,
|
|
missing,
|
|
startTime,
|
|
options,
|
|
callback,
|
|
callbackUndelayed
|
|
) {
|
|
watchCallbacks.push(callback);
|
|
watchCallbacksUndelayed.push(callbackUndelayed);
|
|
}
|
|
};
|
|
const events = [];
|
|
compiler.compilers.forEach(c => {
|
|
c.hooks.invalid.tap("test", () => {
|
|
events.push(`${c.name} invalid`);
|
|
});
|
|
c.hooks.watchRun.tap("test", () => {
|
|
events.push(`${c.name} run`);
|
|
});
|
|
c.hooks.done.tap("test", () => {
|
|
events.push(`${c.name} done`);
|
|
});
|
|
});
|
|
|
|
let update = 0;
|
|
const watching = compiler.watch({}, (err, stats) => {
|
|
if (err) return done(err);
|
|
const info = () => stats.toString({ preset: "summary", version: false });
|
|
switch (update++) {
|
|
case 0:
|
|
expect(info()).toMatchInlineSnapshot(`
|
|
"a:
|
|
a compiled successfully
|
|
|
|
b:
|
|
b compiled successfully
|
|
|
|
c:
|
|
c compiled successfully"
|
|
`);
|
|
expect(compiler.compilers[0].modifiedFiles).toBe(undefined);
|
|
expect(compiler.compilers[0].removedFiles).toBe(undefined);
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"b run",
|
|
"b done",
|
|
"c run",
|
|
"c done",
|
|
"a run",
|
|
"a done",
|
|
]
|
|
`);
|
|
events.length = 0;
|
|
// wait until watching begins
|
|
setTimeout(() => {
|
|
watchCallbacksUndelayed[0]();
|
|
watchCallbacks[0](null, new Map(), new Map(), new Set(), new Set());
|
|
}, 100);
|
|
break;
|
|
case 1:
|
|
expect(info()).toMatchInlineSnapshot(`
|
|
"a:
|
|
a compiled successfully
|
|
|
|
b:
|
|
b compiled successfully"
|
|
`);
|
|
expect(compiler.compilers[1].modifiedFiles).toEqual(new Set());
|
|
expect(compiler.compilers[1].removedFiles).toEqual(new Set());
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"b invalid",
|
|
"b run",
|
|
"b done",
|
|
"a invalid",
|
|
"a run",
|
|
"a done",
|
|
]
|
|
`);
|
|
watchCallbacksUndelayed[2]();
|
|
watchCallbacks[2](null, new Map(), new Map(), new Set(), new Set());
|
|
break;
|
|
case 2:
|
|
expect(info()).toMatchInlineSnapshot(`
|
|
"a:
|
|
a compiled successfully"
|
|
`);
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"b invalid",
|
|
"b run",
|
|
"b done",
|
|
"a invalid",
|
|
"a run",
|
|
"a done",
|
|
"a invalid",
|
|
"a run",
|
|
"a done",
|
|
]
|
|
`);
|
|
events.length = 0;
|
|
watchCallbacksUndelayed[0]();
|
|
watchCallbacksUndelayed[1]();
|
|
watchCallbacks[0](null, new Map(), new Map(), new Set(), new Set());
|
|
watchCallbacks[1](null, new Map(), new Map(), new Set(), new Set());
|
|
break;
|
|
case 3:
|
|
expect(info()).toMatchInlineSnapshot(`
|
|
"a:
|
|
a compiled successfully
|
|
|
|
b:
|
|
b compiled successfully
|
|
|
|
c:
|
|
c compiled successfully"
|
|
`);
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"b invalid",
|
|
"c invalid",
|
|
"b run",
|
|
"b done",
|
|
"c run",
|
|
"c done",
|
|
"a invalid",
|
|
"a run",
|
|
"a done",
|
|
]
|
|
`);
|
|
events.length = 0;
|
|
watching.close(err => {
|
|
if (err) return done(err);
|
|
compiler.close(done);
|
|
});
|
|
break;
|
|
default:
|
|
done(new Error("unexpected"));
|
|
}
|
|
});
|
|
});
|
|
|
|
it("should respect parallelism when using invalidate", done => {
|
|
const configs = [
|
|
{
|
|
name: "a",
|
|
mode: "development",
|
|
entry: { a: "./a.js" },
|
|
context: path.join(__dirname, "fixtures")
|
|
},
|
|
{
|
|
name: "b",
|
|
mode: "development",
|
|
entry: { b: "./b.js" },
|
|
context: path.join(__dirname, "fixtures")
|
|
}
|
|
];
|
|
configs.parallelism = 1;
|
|
const compiler = webpack(configs);
|
|
|
|
const events = [];
|
|
compiler.compilers.forEach(c => {
|
|
c.hooks.invalid.tap("test", () => {
|
|
events.push(`${c.name} invalid`);
|
|
});
|
|
c.hooks.watchRun.tap("test", () => {
|
|
events.push(`${c.name} run`);
|
|
});
|
|
c.hooks.done.tap("test", () => {
|
|
events.push(`${c.name} done`);
|
|
});
|
|
});
|
|
|
|
compiler.watchFileSystem = { watch() {} };
|
|
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
|
|
|
let state = 0;
|
|
const watching = compiler.watch({}, error => {
|
|
if (error) {
|
|
done(error);
|
|
return;
|
|
}
|
|
if (state !== 0) return;
|
|
state++;
|
|
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"a run",
|
|
"a done",
|
|
"b run",
|
|
"b done",
|
|
]
|
|
`);
|
|
events.length = 0;
|
|
|
|
watching.invalidate(err => {
|
|
try {
|
|
if (err) return done(err);
|
|
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"a invalid",
|
|
"b invalid",
|
|
"a run",
|
|
"a done",
|
|
"b run",
|
|
"b done",
|
|
]
|
|
`);
|
|
events.length = 0;
|
|
expect(state).toBe(1);
|
|
setTimeout(done, 1000);
|
|
} catch (e) {
|
|
console.error(e);
|
|
done(e);
|
|
}
|
|
});
|
|
});
|
|
}, 2000);
|
|
|
|
it("should respect dependencies when using invalidate", done => {
|
|
const compiler = webpack([
|
|
{
|
|
name: "a",
|
|
mode: "development",
|
|
entry: { a: "./a.js" },
|
|
context: path.join(__dirname, "fixtures"),
|
|
dependencies: ["b"]
|
|
},
|
|
{
|
|
name: "b",
|
|
mode: "development",
|
|
entry: { b: "./b.js" },
|
|
context: path.join(__dirname, "fixtures")
|
|
}
|
|
]);
|
|
|
|
const events = [];
|
|
compiler.compilers.forEach(c => {
|
|
c.hooks.invalid.tap("test", () => {
|
|
events.push(`${c.name} invalid`);
|
|
});
|
|
c.hooks.watchRun.tap("test", () => {
|
|
events.push(`${c.name} run`);
|
|
});
|
|
c.hooks.done.tap("test", () => {
|
|
events.push(`${c.name} done`);
|
|
});
|
|
});
|
|
|
|
compiler.watchFileSystem = { watch() {} };
|
|
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
|
|
|
let state = 0;
|
|
const watching = compiler.watch({}, error => {
|
|
if (error) {
|
|
done(error);
|
|
return;
|
|
}
|
|
if (state !== 0) return;
|
|
state++;
|
|
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"b run",
|
|
"b done",
|
|
"a run",
|
|
"a done",
|
|
]
|
|
`);
|
|
events.length = 0;
|
|
|
|
watching.invalidate(err => {
|
|
try {
|
|
if (err) return done(err);
|
|
|
|
expect(events).toMatchInlineSnapshot(`
|
|
Array [
|
|
"a invalid",
|
|
"b invalid",
|
|
"b run",
|
|
"b done",
|
|
"a run",
|
|
"a done",
|
|
]
|
|
`);
|
|
events.length = 0;
|
|
expect(state).toBe(1);
|
|
setTimeout(done, 1000);
|
|
} catch (e) {
|
|
console.error(e);
|
|
done(e);
|
|
}
|
|
});
|
|
});
|
|
}, 2000);
|
|
|
|
it("shouldn't hang when invalidating watchers", done => {
|
|
const entriesA = { a: "./a.js" };
|
|
const entriesB = { b: "./b.js" };
|
|
const compiler = webpack([
|
|
{
|
|
name: "a",
|
|
mode: "development",
|
|
entry: () => entriesA,
|
|
context: path.join(__dirname, "fixtures")
|
|
},
|
|
{
|
|
name: "b",
|
|
mode: "development",
|
|
entry: () => entriesB,
|
|
context: path.join(__dirname, "fixtures")
|
|
}
|
|
]);
|
|
|
|
compiler.watchFileSystem = { watch() {} };
|
|
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
|
|
|
const watching = compiler.watch({}, error => {
|
|
if (error) {
|
|
done(error);
|
|
return;
|
|
}
|
|
|
|
entriesA.b = "./b.js";
|
|
entriesB.a = "./a.js";
|
|
|
|
watching.invalidate(done);
|
|
});
|
|
}, 2000);
|
|
|
|
it("shouldn't hang when invalidating during build", done => {
|
|
const compiler = webpack(
|
|
Object.assign([
|
|
{
|
|
name: "a",
|
|
mode: "development",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./a.js"
|
|
},
|
|
{
|
|
name: "b",
|
|
mode: "development",
|
|
context: path.join(__dirname, "fixtures"),
|
|
entry: "./b.js",
|
|
dependencies: ["a"]
|
|
}
|
|
])
|
|
);
|
|
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
|
const watchCallbacks = [];
|
|
const watchCallbacksUndelayed = [];
|
|
let firstRun = true;
|
|
compiler.watchFileSystem = {
|
|
watch(
|
|
files,
|
|
directories,
|
|
missing,
|
|
startTime,
|
|
options,
|
|
callback,
|
|
callbackUndelayed
|
|
) {
|
|
watchCallbacks.push(callback);
|
|
watchCallbacksUndelayed.push(callbackUndelayed);
|
|
if (firstRun && files.has(path.join(__dirname, "fixtures", "a.js"))) {
|
|
process.nextTick(() => {
|
|
callback(null, new Map(), new Map(), new Set(), new Set());
|
|
});
|
|
firstRun = false;
|
|
}
|
|
}
|
|
};
|
|
compiler.watch({}, (err, stats) => {
|
|
done(err);
|
|
});
|
|
});
|
|
});
|