Smaller performance improvements in NormalModuleFactory

This commit is contained in:
Tobias Koppers 2019-01-05 11:19:30 +01:00
parent 526bc7a788
commit 90baf475af
3 changed files with 279 additions and 240 deletions

View File

@ -808,6 +808,12 @@ class Compilation {
}
}
if (sortedDependencies.length === 0) {
callback();
return;
}
process.nextTick(() => {
// This is nested so we need to allow one additional task
this.processDependenciesQueue.increaseParallelism();
@ -839,6 +845,7 @@ class Compilation {
return callback(err);
}
);
});
}
/**

View File

@ -566,6 +566,7 @@ class Compiler {
this.hooks.make.callAsync(compilation, err => {
if (err) return callback(err);
process.nextTick(() => {
compilation.finish(err => {
if (err) return callback(err);
@ -581,6 +582,7 @@ class Compiler {
});
});
});
});
}
/**

View File

@ -58,6 +58,14 @@ const loaderToIdent = data => {
return data.loader + "?" + JSON.stringify(data.options);
};
const stringifyLoadersAndResource = (loaders, resource) => {
let str = "";
for (const loader of loaders) {
str += loaderToIdent(loader) + "!";
}
return str + resource;
};
const identToLoaderRequest = resultString => {
const idx = resultString.indexOf("?");
if (idx >= 0) {
@ -75,6 +83,18 @@ const identToLoaderRequest = resultString => {
}
};
const needCalls = (times, callback) => {
return err => {
if (--times === 0) {
return callback(err);
}
if (err && times > 0) {
times = NaN;
return callback(err);
}
};
};
// TODO webpack 6 remove
const deprecationChangedHookMessage = name =>
`NormalModuleFactory.${name} is no longer a waterfall hook, but a bailing hook instead. ` +
@ -196,25 +216,33 @@ class NormalModuleFactory extends ModuleFactory {
const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
if (matchResourceMatch) {
matchResource = matchResourceMatch[1];
if (/^\.\.?\//.test(matchResource)) {
if (matchResource.charCodeAt(0) === 46) {
// 46 === ".", 47 === "/"
const secondChar = matchResource.charCodeAt(1);
if (
secondChar === 47 ||
(secondChar === 46 && matchResource.charCodeAt(2) === 47)
) {
// if matchResources startsWith ../ or ./
matchResource = path.join(context, matchResource);
}
}
requestWithoutMatchResource = request.substr(
matchResourceMatch[0].length
);
}
const noPreAutoLoaders = requestWithoutMatchResource.startsWith("-!");
const noAutoLoaders =
noPreAutoLoaders || requestWithoutMatchResource.startsWith("!");
const noPrePostAutoLoaders = requestWithoutMatchResource.startsWith(
"!!"
);
const firstChar = requestWithoutMatchResource.charCodeAt(0);
const secondChar = requestWithoutMatchResource.charCodeAt(1);
const noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!"
const noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!"
const noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!";
const rawElements = requestWithoutMatchResource
.replace(/^-?!+/, "")
.replace(/!!+/g, "!")
.split("!");
const resource = rawElements.pop();
.slice(
noPreAutoLoaders || noPrePostAutoLoaders ? 2 : noAutoLoaders ? 1 : 0
)
.split(/!+/);
const unresolvedResource = rawElements.pop();
const elements = rawElements.map(identToLoaderRequest);
const resolveContext = {
@ -224,58 +252,18 @@ class NormalModuleFactory extends ModuleFactory {
contextDependencies
};
asyncLib.parallel(
[
callback =>
this.resolveRequestArray(
contextInfo,
context,
elements,
loaderResolver,
resolveContext,
callback
),
callback => {
if (resource === "" || resource[0] === "?") {
return callback(null, {
resource
});
}
/** @type {string | false} */
let resource;
let resourceResolveData;
let loaders;
normalResolver.resolve(
contextInfo,
context,
resource,
resolveContext,
(err, resource, resourceResolveData) => {
const continueCallback = needCalls(2, err => {
if (err) return callback(err);
// TODO remove this when enhanced-resolve supports fileDependencies
if (resource) {
fileDependencies.add(resource);
}
callback(null, {
resourceResolveData,
resource
});
}
);
}
],
(err, results) => {
if (err) return callback(err);
let loaders = results[0];
const resourceResolveData = results[1].resourceResolveData;
const resource = results[1].resource;
// translate option idents
try {
for (const item of loaders) {
if (
typeof item.options === "string" &&
item.options[0] === "?"
) {
if (typeof item.options === "string" && item.options[0] === "?") {
const ident = item.options.substr(1);
item.options = this.ruleSet.findOptionsByIdent(ident);
item.ident = ident;
@ -299,10 +287,7 @@ class NormalModuleFactory extends ModuleFactory {
const userRequest =
(matchResource !== undefined ? `${matchResource}!=!` : "") +
loaders
.map(loaderToIdent)
.concat([resource])
.join("!");
stringifyLoadersAndResource(loaders, resource);
let resourcePath =
matchResource !== undefined ? matchResource : resource;
@ -355,48 +340,24 @@ class NormalModuleFactory extends ModuleFactory {
settings[r.type] = r.value;
}
}
asyncLib.parallel(
[
this.resolveRequestArray.bind(
this,
contextInfo,
this.context,
useLoadersPost,
loaderResolver,
resolveContext
),
this.resolveRequestArray.bind(
this,
contextInfo,
this.context,
useLoaders,
loaderResolver,
resolveContext
),
this.resolveRequestArray.bind(
this,
contextInfo,
this.context,
useLoadersPre,
loaderResolver,
resolveContext
)
],
(err, results) => {
let postLoaders, normalLoaders, preLoaders;
const continueCallback = needCalls(3, err => {
if (err) {
return callback(err);
}
loaders = results[0].concat(loaders, results[1], results[2]);
const allLoaders = postLoaders;
for (const loader of loaders) allLoaders.push(loader);
for (const loader of normalLoaders) allLoaders.push(loader);
for (const loader of preLoaders) allLoaders.push(loader);
const type = settings.type;
const resolveOptions = settings.resolve;
Object.assign(data.createData, {
request: loaders
.map(loaderToIdent)
.concat([resource])
.join("!"),
request: stringifyLoadersAndResource(allLoaders, resource),
userRequest,
rawRequest: request,
loaders,
loaders: allLoaders,
resource,
matchResource,
resourceResolveData,
@ -407,8 +368,80 @@ class NormalModuleFactory extends ModuleFactory {
resolveOptions
});
callback();
});
this.resolveRequestArray(
contextInfo,
this.context,
useLoadersPost,
loaderResolver,
resolveContext,
(err, result) => {
postLoaders = result;
continueCallback(err);
}
);
this.resolveRequestArray(
contextInfo,
this.context,
useLoaders,
loaderResolver,
resolveContext,
(err, result) => {
normalLoaders = result;
continueCallback(err);
}
);
this.resolveRequestArray(
contextInfo,
this.context,
useLoadersPre,
loaderResolver,
resolveContext,
(err, result) => {
preLoaders = result;
continueCallback(err);
}
);
});
this.resolveRequestArray(
contextInfo,
context,
elements,
loaderResolver,
resolveContext,
(err, result) => {
if (err) return continueCallback(err);
loaders = result;
continueCallback();
}
);
if (
unresolvedResource === "" ||
unresolvedResource.charCodeAt(0) === 63
) {
// 63 === "?"
resource = unresolvedResource;
return continueCallback();
}
normalResolver.resolve(
contextInfo,
context,
unresolvedResource,
resolveContext,
(err, resolvedResource, resolvedResourceResolveData) => {
if (err) return continueCallback(err);
// TODO remove this when enhanced-resolve supports fileDependencies
if (resolvedResource) {
fileDependencies.add(resolvedResource);
}
resource = resolvedResource;
resourceResolveData = resolvedResourceResolveData;
continueCallback();
}
);
}
@ -484,7 +517,7 @@ class NormalModuleFactory extends ModuleFactory {
resolveContext,
callback
) {
if (array.length === 0) return callback(null, []);
if (array.length === 0) return callback(null, array);
asyncLib.map(
array,
(item, callback) => {
@ -503,7 +536,7 @@ class NormalModuleFactory extends ModuleFactory {
contextInfo,
context,
item.loader + "-loader",
{},
resolveContext,
err2 => {
if (!err2) {
err.message =
@ -521,18 +554,15 @@ class NormalModuleFactory extends ModuleFactory {
}
if (err) return callback(err);
const optionsOnly = item.options
? {
options: item.options
}
: undefined;
const resolved = Object.assign(
{},
item,
identToLoaderRequest(result),
optionsOnly
);
const parsedResult = identToLoaderRequest(result);
const resolved = {
loader: parsedResult.loader,
options:
item.options === undefined
? parsedResult.options
: item.options,
ident: item.options === undefined ? undefined : item.ident
};
// TODO remove this when enhanced-resolve supports fileDependencies
if (resolved.loader) {