Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance improvements #13448

Merged
merged 5 commits into from May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/EntryPlugin.js
Expand Up @@ -41,10 +41,10 @@ class EntryPlugin {
}
);

compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback) => {
const { entry, options, context } = this;
const { entry, options, context } = this;
const dep = EntryPlugin.createDependency(entry, options);

const dep = EntryPlugin.createDependency(entry, options);
compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback) => {
compilation.addEntry(context, dep, options, err => {
callback(err);
});
Expand Down
32 changes: 19 additions & 13 deletions lib/ExportsInfo.js
Expand Up @@ -137,18 +137,21 @@ class ExportsInfo {

_sortExportsMap(exports) {
if (exports.size > 1) {
const entriesInOrder = Array.from(exports.values());
if (
entriesInOrder.length !== 2 ||
entriesInOrder[0].name > entriesInOrder[1].name
) {
entriesInOrder.sort((a, b) => {
return a.name < b.name ? -1 : 1;
});
exports.clear();
for (const entry of entriesInOrder) {
exports.set(entry.name, entry);
}
const namesInOrder = [];
for (const entry of exports.values()) {
namesInOrder.push(entry.name);
}
namesInOrder.sort();
let i = 0;
for (const entry of exports.values()) {
const name = namesInOrder[i];
if (entry.name !== name) break;
}
Comment on lines +146 to +149
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing an increment to i somewhere

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes. Do you want to send a PR

for (; i < namesInOrder.length; i++) {
const name = namesInOrder[i];
const correctEntry = exports.get(name);
exports.delete(name);
exports.set(name, correctEntry);
}
}
}
Expand Down Expand Up @@ -722,7 +725,7 @@ class ExportsInfo {
const otherCanMangleProvide = this._otherExportsInfo.canMangleProvide;
const otherTerminalBinding = this._otherExportsInfo.terminalBinding;
const exports = [];
for (const exportInfo of this._exports.values()) {
for (const exportInfo of this.orderedExports) {
if (
exportInfo.provided !== otherProvided ||
exportInfo.canMangleProvide !== otherCanMangleProvide ||
Expand Down Expand Up @@ -754,7 +757,9 @@ class ExportsInfo {
otherTerminalBinding,
exports
}) {
let wasEmpty = true;
for (const exportInfo of this._exports.values()) {
wasEmpty = false;
exportInfo.provided = otherProvided;
exportInfo.canMangleProvide = otherCanMangleProvide;
exportInfo.terminalBinding = otherTerminalBinding;
Expand All @@ -772,6 +777,7 @@ class ExportsInfo {
exportsInfo.restoreProvided(exp.exportsInfo);
}
}
if (wasEmpty) this._exportsAreOrdered = true;
}
}

Expand Down
9 changes: 7 additions & 2 deletions lib/config/target.js
Expand Up @@ -5,14 +5,18 @@

"use strict";

const browserslistTargetHandler = require("./browserslistTargetHandler");
const memoize = require("../util/memoize");

const getBrowserslistTargetHandler = memoize(() =>
require("./browserslistTargetHandler")
);

/**
* @param {string} context the context directory
* @returns {string} default target
*/
const getDefaultTarget = context => {
const browsers = browserslistTargetHandler.load(null, context);
const browsers = getBrowserslistTargetHandler().load(null, context);
return browsers ? "browserslist" : "web";
};

Expand Down Expand Up @@ -78,6 +82,7 @@ const TARGETS = [
"Resolve features from browserslist. Will resolve browserslist config automatically. Only browser or node queries are supported (electron is not supported). Examples: 'browserslist:modern' to use 'modern' environment from browserslist config",
/^browserslist(?::(.+))?$/,
(rest, context) => {
const browserslistTargetHandler = getBrowserslistTargetHandler();
const browsers = browserslistTargetHandler.load(
rest ? rest.trim() : null,
context
Expand Down
3 changes: 3 additions & 0 deletions lib/serialization/BinaryMiddleware.js
Expand Up @@ -100,6 +100,9 @@ const F64_SIZE = 8;
const MEASURE_START_OPERATION = Symbol("MEASURE_START_OPERATION");
const MEASURE_END_OPERATION = Symbol("MEASURE_END_OPERATION");

/** @typedef {typeof MEASURE_START_OPERATION} MEASURE_START_OPERATION_TYPE */
/** @typedef {typeof MEASURE_END_OPERATION} MEASURE_END_OPERATION_TYPE */

const identifyNumber = n => {
if (n === (n | 0)) {
if (n <= 127 && n >= -128) return 0;
Expand Down
9 changes: 5 additions & 4 deletions lib/stats/DefaultStatsFactoryPlugin.js
Expand Up @@ -10,7 +10,6 @@ const ModuleDependency = require("../dependencies/ModuleDependency");
const formatLocation = require("../formatLocation");
const { LogType } = require("../logging/Logger");
const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin");
const ConcatenatedModule = require("../optimize/ConcatenatedModule");
const SizeLimitsPlugin = require("../performance/SizeLimitsPlugin");
const { countIterable } = require("../util/IterableHelpers");
const {
Expand Down Expand Up @@ -1227,11 +1226,13 @@ const SIMPLE_EXTRACTORS = {
},
nestedModules: (object, module, context, options, factory) => {
const { type } = context;
if (module instanceof ConcatenatedModule) {
const modules = module.modules;
const innerModules = /** @type {Module & { modules?: Module[] }} */ (
module
).modules;
if (Array.isArray(innerModules)) {
const groupedModules = factory.create(
`${type.slice(0, -8)}.modules`,
modules,
innerModules,
context
);
const limited = spaceLimited(
Expand Down
9 changes: 5 additions & 4 deletions lib/util/createHash.js
Expand Up @@ -67,25 +67,26 @@ class BulkUpdateDecorator extends Hash {
*/
digest(encoding) {
let digestCache;
const buffer = this.buffer;
if (this.hash === undefined) {
// short data for hash, we can use caching
const cacheKey = `${this.hashKey}-${encoding}`;
digestCache = digestCaches[cacheKey];
if (digestCache === undefined) {
digestCache = digestCaches[cacheKey] = new Map();
}
const cacheEntry = digestCache.get(this.buffer);
const cacheEntry = digestCache.get(buffer);
if (cacheEntry !== undefined) return cacheEntry;
this.hash = this.hashFactory();
}
if (this.buffer.length > 0) {
this.hash.update(this.buffer);
if (buffer.length > 0) {
this.hash.update(buffer);
}
const digestResult = this.hash.digest(encoding);
const result =
typeof digestResult === "string" ? digestResult : digestResult.toString();
if (digestCache !== undefined) {
digestCache.set(this.buffer, result);
digestCache.set(buffer, result);
}
return result;
}
Expand Down
167 changes: 108 additions & 59 deletions lib/util/serialization.js
Expand Up @@ -4,72 +4,121 @@

"use strict";

const BinaryMiddleware = require("../serialization/BinaryMiddleware");
const FileMiddleware = require("../serialization/FileMiddleware");
const ObjectMiddleware = require("../serialization/ObjectMiddleware");
const Serializer = require("../serialization/Serializer");
const SerializerMiddleware = require("../serialization/SerializerMiddleware");
const SingleItemMiddleware = require("../serialization/SingleItemMiddleware");
const internalSerializables = require("./internalSerializables");
const memoize = require("./memoize");

/** @typedef {import("../serialization/BinaryMiddleware").MEASURE_END_OPERATION_TYPE} MEASURE_END_OPERATION */
/** @typedef {import("../serialization/BinaryMiddleware").MEASURE_START_OPERATION_TYPE} MEASURE_START_OPERATION */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {import("../serialization/Serializer")} Serializer */

const { register, registerLoader, registerNotSerializable } = ObjectMiddleware;
const getBinaryMiddleware = memoize(() =>
require("../serialization/BinaryMiddleware")
);
const getObjectMiddleware = memoize(() =>
require("../serialization/ObjectMiddleware")
);
const getSingleItemMiddleware = memoize(() =>
require("../serialization/SingleItemMiddleware")
);
const getSerializer = memoize(() => require("../serialization/Serializer"));
const getSerializerMiddleware = memoize(() =>
require("../serialization/SerializerMiddleware")
);

const binaryMiddleware = new BinaryMiddleware();
const getBinaryMiddlewareInstance = memoize(
() => new (getBinaryMiddleware())()
);

// Expose serialization API
exports.register = register;
exports.registerLoader = registerLoader;
exports.registerNotSerializable = registerNotSerializable;
exports.NOT_SERIALIZABLE = ObjectMiddleware.NOT_SERIALIZABLE;
exports.MEASURE_START_OPERATION = BinaryMiddleware.MEASURE_START_OPERATION;
exports.MEASURE_END_OPERATION = BinaryMiddleware.MEASURE_END_OPERATION;
exports.buffersSerializer = new Serializer([
new SingleItemMiddleware(),
new ObjectMiddleware(context => {
if (context.write) {
context.writeLazy = value => {
context.write(SerializerMiddleware.createLazy(value, binaryMiddleware));
};
const registerSerializers = memoize(() => {
require("./registerExternalSerializer");

// Load internal paths with a relative require
// This allows bundling all internal serializers
const internalSerializables = require("./internalSerializables");
getObjectMiddleware().registerLoader(/^webpack\/lib\//, req => {
const loader = internalSerializables[req.slice("webpack/lib/".length)];
if (loader) {
loader();
} else {
console.warn(`${req} not found in internalSerializables`);
}
}),
binaryMiddleware
]);
exports.createFileSerializer = fs => {
const fileMiddleware = new FileMiddleware(fs);
return new Serializer([
new SingleItemMiddleware(),
new ObjectMiddleware(context => {
if (context.write) {
context.writeLazy = value => {
context.write(
SerializerMiddleware.createLazy(value, binaryMiddleware)
);
};
context.writeSeparate = (value, options) => {
context.write(
SerializerMiddleware.createLazy(value, fileMiddleware, options)
);
};
}
}),
binaryMiddleware,
fileMiddleware
]);
};
return true;
});
});

require("./registerExternalSerializer");
/** @type {Serializer} */
let buffersSerializer;

// Load internal paths with a relative require
// This allows bundling all internal serializers
registerLoader(/^webpack\/lib\//, req => {
const loader = internalSerializables[req.slice("webpack/lib/".length)];
if (loader) {
loader();
} else {
console.warn(`${req} not found in internalSerializables`);
// Expose serialization API
module.exports = {
get register() {
return getObjectMiddleware().register;
},
get registerLoader() {
return getObjectMiddleware().registerLoader;
},
get registerNotSerializable() {
return getObjectMiddleware().registerNotSerializable;
},
get NOT_SERIALIZABLE() {
return getObjectMiddleware().NOT_SERIALIZABLE;
},
/** @type {MEASURE_START_OPERATION} */
get MEASURE_START_OPERATION() {
return getBinaryMiddleware().MEASURE_START_OPERATION;
},
/** @type {MEASURE_END_OPERATION} */
get MEASURE_END_OPERATION() {
return getBinaryMiddleware().MEASURE_END_OPERATION;
},
get buffersSerializer() {
if (buffersSerializer !== undefined) return buffersSerializer;
registerSerializers();
const Serializer = getSerializer();
const binaryMiddleware = getBinaryMiddlewareInstance();
const SerializerMiddleware = getSerializerMiddleware();
const SingleItemMiddleware = getSingleItemMiddleware();
return (buffersSerializer = new Serializer([
new SingleItemMiddleware(),
new (getObjectMiddleware())(context => {
if (context.write) {
context.writeLazy = value => {
context.write(
SerializerMiddleware.createLazy(value, binaryMiddleware)
);
};
}
}),
binaryMiddleware
]));
},
createFileSerializer: fs => {
registerSerializers();
const Serializer = getSerializer();
const FileMiddleware = require("../serialization/FileMiddleware");
const fileMiddleware = new FileMiddleware(fs);
const binaryMiddleware = getBinaryMiddlewareInstance();
const SerializerMiddleware = getSerializerMiddleware();
const SingleItemMiddleware = getSingleItemMiddleware();
return new Serializer([
new SingleItemMiddleware(),
new (getObjectMiddleware())(context => {
if (context.write) {
context.writeLazy = value => {
context.write(
SerializerMiddleware.createLazy(value, binaryMiddleware)
);
};
context.writeSeparate = (value, options) => {
context.write(
SerializerMiddleware.createLazy(value, fileMiddleware, options)
);
};
}
}),
binaryMiddleware,
fileMiddleware
]);
}
return true;
});
};
10 changes: 5 additions & 5 deletions types.d.ts
Expand Up @@ -12099,19 +12099,19 @@ declare namespace exports {
) => 0 | 1 | -1;
}
export namespace serialization {
export let register: (
export const register: (
Constructor: Constructor,
request: string,
name: string,
serializer: ObjectSerializer
) => void;
export let registerLoader: (
export const registerLoader: (
regExp: RegExp,
loader: (arg0: string) => boolean
) => void;
export let registerNotSerializable: (Constructor: Constructor) => void;
export let NOT_SERIALIZABLE: object;
export let buffersSerializer: Serializer;
export const registerNotSerializable: (Constructor: Constructor) => void;
export const NOT_SERIALIZABLE: object;
export const buffersSerializer: Serializer;
export let createFileSerializer: (fs?: any) => Serializer;
export { MEASURE_START_OPERATION, MEASURE_END_OPERATION };
}
Expand Down