Skip to content

Commit f672f33

Browse files
committed
Make webpack benchmark synchronous
1 parent 07c1c4d commit f672f33

File tree

8 files changed

+140
-21
lines changed

8 files changed

+140
-21
lines changed

jest.config.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
// Copyright 2017 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
15
const path = require("path");
26

37
module.exports = {
4-
watchPathIgnorePatterns: [
8+
rootDir: path.resolve(__dirname, "src"),
9+
transformIgnorePatterns: [
10+
"/node_modules/",
511
path.resolve(__dirname, "build")
612
]
7-
}
13+
};

src/mocks/clear-immediate.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright 2017 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
const eventLoop = require("./event-loop");
6+
7+
module.exports = task => {
8+
eventLoop.cancel(task);
9+
};

src/mocks/event-loop.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2017 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// This is a very simple event loop implementation. It does not cover the exact behavior
6+
// in node, especially not the differences between process.nextTick and setImmediate.
7+
// It is, however, sufficient for the benchmark.
8+
const tasks = [];
9+
10+
module.exports = {
11+
schedule(task) {
12+
tasks.push(task);
13+
},
14+
cancel(task) {
15+
const i = tasks.indexOf(task);
16+
17+
if (i > -1) {
18+
tasks.splice(i, 1);
19+
}
20+
},
21+
run() {
22+
let task;
23+
while ((task = tasks.shift())) {
24+
task();
25+
}
26+
}
27+
};

src/mocks/process.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2017 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
const eventLoop = require("./event-loop");
6+
7+
exports.nextTick = function(fn) {
8+
const args = Array.prototype.slice.call(arguments, 1);
9+
eventLoop.schedule(() => {
10+
fn.apply(null, args);
11+
});
12+
};
13+
14+
exports.platform = exports.arch = exports.execPath = exports.title = "browser";
15+
exports.pid = 1;
16+
exports.browser = true;
17+
exports.env = {};
18+
exports.argv = [];
19+
exports.cwd = () => "/";
20+
exports.binding = name => {
21+
throw new Error("No such module. (Possibly not yet loaded)");
22+
};
23+
exports.exit = exports.kill = exports.umask = exports.dlopen = exports.uptime = exports.memoryUsage = exports.uvCounters = () => {};
24+
exports.features = {};

src/mocks/set-immediate.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
const eventLoop = require("./event-loop");
6+
7+
module.exports = function(fn) {
8+
const args = Array.prototype.slice.call(arguments, 1);
9+
const task = () => {
10+
fn.apply(null, args);
11+
};
12+
eventLoop.schedule(task);
13+
return task;
14+
};

src/webpack-benchmark.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
const webpack = require("webpack");
6+
const eventLoop = require("./mocks/event-loop");
67

78
const payloads = [
89
{
@@ -22,16 +23,27 @@ const payloads = [
2223

2324
module.exports = {
2425
name: "webpack",
25-
defer: true,
26-
fn(deferred) {
27-
return Promise.all(
28-
payloads.map(
29-
config =>
30-
new Promise((resolve, reject) => {
31-
const compiler = webpack(config);
32-
compiler.run((err, stats) => void (err ? reject(err) : resolve()));
33-
})
34-
)
35-
).then(() => deferred.resolve());
26+
fn() {
27+
payloads.forEach(config => {
28+
let finished = false;
29+
30+
eventLoop.schedule(() => {
31+
const compiler = webpack(config);
32+
compiler.run((err, stats) => {
33+
if (err) {
34+
throw err;
35+
}
36+
if (stats.hasErrors()) {
37+
throw stats.compilation.errors[0];
38+
}
39+
finished = true;
40+
});
41+
});
42+
eventLoop.run();
43+
44+
if (finished !== true) {
45+
throw new Error("Webpack did not finish synchronously");
46+
}
47+
});
3648
}
3749
};

src/webpack-benchmark.test.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ beforeAll(
1919
new Promise((resolve, reject) => {
2020
const baseConfig = webpackConfig[0];
2121
const config = Object.assign({}, baseConfig, {
22-
entry: require.resolve("./webpack-benchmark.js"),
23-
bail: true
22+
entry: require.resolve("./webpack-benchmark.js")
2423
});
2524
config.output = Object.assign({}, baseConfig.output, {
2625
libraryTarget: "commonjs2",
@@ -39,7 +38,4 @@ beforeAll(
3938
})
4039
);
4140

42-
it("webpack runs to completion", () =>
43-
new Promise(resolve => {
44-
webpackBenchmark.fn({ resolve });
45-
}));
41+
it("webpack runs to completion", () => void webpackBenchmark.fn());

webpack.config.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,26 @@ module.exports = [
2222
"graceful-fs": require.resolve("./src/vfs"),
2323
module: require.resolve("./src/mocks/dummy"),
2424
chokidar: require.resolve("./src/mocks/chokidar"),
25-
"uglify-js": require.resolve("./src/mocks/dummy")
25+
"uglify-js": require.resolve("./src/mocks/dummy"),
26+
// These modules are used by virtualfs to fake async fs calls
27+
"core-js/library/fn/set-immediate": require.resolve(
28+
"./src/mocks/set-immediate"
29+
),
30+
"core-js/library/fn/clear-immediate": require.resolve(
31+
"./src/mocks/clear-immediate"
32+
)
2633
}
2734
},
35+
node: {
36+
setImmediate: false, // this disables also clearImmediate
37+
process: false
38+
},
2839
plugins: [
40+
new webpack.ProvidePlugin({
41+
setImmediate: require.resolve("./src/mocks/set-immediate"),
42+
clearImmediate: require.resolve("./src/mocks/clear-immediate"),
43+
process: require.resolve("./src/mocks/process")
44+
}),
2945
new webpack.BannerPlugin({
3046
banner:
3147
"// Required for JavaScript engine shells.\n" +
@@ -52,10 +68,25 @@ module.exports = [
5268
"graceful-fs": require.resolve("./src/vfs"),
5369
module: require.resolve("./src/mocks/dummy"),
5470
chokidar: require.resolve("./src/mocks/chokidar"),
55-
"uglify-js": require.resolve("./src/mocks/dummy")
71+
"uglify-js": require.resolve("./src/mocks/dummy"),
72+
"core-js/library/fn/set-immediate": require.resolve(
73+
"./src/mocks/set-immediate"
74+
),
75+
"core-js/library/fn/clear-immediate": require.resolve(
76+
"./src/mocks/clear-immediate"
77+
)
5678
}
5779
},
80+
node: {
81+
setImmediate: false,
82+
process: false
83+
},
5884
plugins: [
85+
new webpack.ProvidePlugin({
86+
setImmediate: require.resolve("./src/mocks/set-immediate"),
87+
clearImmediate: require.resolve("./src/mocks/clear-immediate"),
88+
process: require.resolve("./src/mocks/process")
89+
}),
5990
new CopyWebpackPlugin([{ from: "style.css" }, { from: "Logo.png" }]),
6091
new webpack.BannerPlugin({
6192
banner:

0 commit comments

Comments
 (0)