rename parsePathQueryFragment to parseResource and add caching

This commit is contained in:
Tobias Koppers 2020-07-06 17:39:52 +02:00
parent 2cc3510f55
commit 5f4c4662dd
6 changed files with 80 additions and 21 deletions

View File

@ -875,7 +875,8 @@ class Compiler {
context: this.options.context,
fs: this.inputFileSystem,
resolverFactory: this.resolverFactory,
options: this.options.module || {}
options: this.options.module || {},
associatedObjectForCache: this.root
});
this.hooks.normalModuleFactory.call(normalModuleFactory);
return normalModuleFactory;

View File

@ -8,7 +8,7 @@
const CachedConstDependency = require("./dependencies/CachedConstDependency");
const ConstDependency = require("./dependencies/ConstDependency");
const { evaluateToString } = require("./javascript/JavascriptParserHelpers");
const { parsePathQueryFragment } = require("./util/identifier");
const { parseResource } = require("./util/identifier");
/** @typedef {import("./Compiler")} Compiler */
@ -113,6 +113,7 @@ class ConstPlugin {
* @returns {void}
*/
apply(compiler) {
const cacheParseResource = parseResource.bindCache(compiler.root);
compiler.hooks.compilation.tap(
"ConstPlugin",
(compilation, { normalModuleFactory }) => {
@ -324,7 +325,7 @@ class ConstPlugin {
if (parser.scope.isAsmJs) return;
if (!parser.state.module) return;
return evaluateToString(
parsePathQueryFragment(parser.state.module.resource).query
cacheParseResource(parser.state.module.resource).query
)(expr);
});
parser.hooks.expression
@ -334,7 +335,7 @@ class ConstPlugin {
if (!parser.state.module) return;
const dep = new CachedConstDependency(
JSON.stringify(
parsePathQueryFragment(parser.state.module.resource).query
cacheParseResource(parser.state.module.resource).query
),
expr.range,
"__resourceQuery"
@ -350,7 +351,7 @@ class ConstPlugin {
if (parser.scope.isAsmJs) return;
if (!parser.state.module) return;
return evaluateToString(
parsePathQueryFragment(parser.state.module.resource).fragment
cacheParseResource(parser.state.module.resource).fragment
)(expr);
});
parser.hooks.expression
@ -360,7 +361,7 @@ class ConstPlugin {
if (!parser.state.module) return;
const dep = new CachedConstDependency(
JSON.stringify(
parsePathQueryFragment(parser.state.module.resource).fragment
cacheParseResource(parser.state.module.resource).fragment
),
expr.range,
"__resourceFragment"

View File

@ -19,7 +19,7 @@ const {
keepOriginalOrder
} = require("./util/comparators");
const { compareModulesById } = require("./util/comparators");
const { contextify, parsePathQueryFragment } = require("./util/identifier");
const { contextify, parseResource } = require("./util/identifier");
const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("webpack-sources").Source} Source */
@ -87,7 +87,7 @@ class ContextModule extends Module {
* @param {ContextModuleOptions} options options object
*/
constructor(resolveDependencies, options) {
const parsed = parsePathQueryFragment(options.resource);
const parsed = parseResource(options.resource);
const resource = parsed.path;
const resourceQuery = options.resourceQuery || parsed.query;
const resourceFragment = options.resourceFragment || parsed.fragment;

View File

@ -25,7 +25,7 @@ const LazySet = require("./util/LazySet");
const { getScheme } = require("./util/URLAbsoluteSpecifier");
const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge");
const { join } = require("./util/fs");
const { parsePathQueryFragment } = require("./util/identifier");
const { parseResource } = require("./util/identifier");
/** @typedef {import("../declarations/WebpackOptions").ModuleOptions} ModuleOptions */
/** @typedef {import("./Generator")} Generator */
@ -154,8 +154,15 @@ class NormalModuleFactory extends ModuleFactory {
* @param {InputFileSystem} param.fs file system
* @param {ResolverFactory} param.resolverFactory resolverFactory
* @param {ModuleOptions} param.options options
* @param {Object=} param.associatedObjectForCache an object to which the cache will be attached
*/
constructor({ context, fs, resolverFactory, options }) {
constructor({
context,
fs,
resolverFactory,
options,
associatedObjectForCache
}) {
super();
this.hooks = Object.freeze({
/** @type {AsyncSeriesBailHook<[ResolveData], TODO>} */
@ -207,6 +214,11 @@ class NormalModuleFactory extends ModuleFactory {
* @type {Map<string, WeakMap<Object, Generator>>}
*/
this.generatorCache = new Map();
const cacheParseResource = parseResource.bindCache(
associatedObjectForCache
);
this.hooks.factorize.tapAsync(
{
name: "NormalModuleFactory",
@ -303,7 +315,7 @@ class NormalModuleFactory extends ModuleFactory {
}
matchResourceData = {
resource: matchResource,
...parsePathQueryFragment(matchResource)
...cacheParseResource(matchResource)
};
requestWithoutMatchResource = request.substr(
matchResourceMatch[0].length
@ -529,7 +541,7 @@ class NormalModuleFactory extends ModuleFactory {
resourceData = {
resource: unresolvedResource,
data: {},
...parsePathQueryFragment(unresolvedResource)
...cacheParseResource(unresolvedResource)
};
continueCallback();
}
@ -557,7 +569,7 @@ class NormalModuleFactory extends ModuleFactory {
resourceData = {
resource: resolvedResource,
data: resolvedResourceResolveData,
...parsePathQueryFragment(resolvedResource)
...cacheParseResource(resolvedResource)
};
}
continueCallback();

View File

@ -5,7 +5,7 @@
"use strict";
const { parsePathQueryFragment } = require("../util/identifier");
const { parseResource } = require("../util/identifier");
/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
@ -59,8 +59,9 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
const valueRange = param.range;
const { context, prefix } = splitContextFromPrefix(prefixRaw);
const { path: postfix, query, fragment } = parsePathQueryFragment(
postfixRaw
const { path: postfix, query, fragment } = parseResource(
postfixRaw,
parser
);
// When there are more than two quasis, the generated RegExp can be more precise
@ -157,8 +158,9 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
param.postfix && param.postfix.isString() ? param.postfix.range : null;
const valueRange = param.range;
const { context, prefix } = splitContextFromPrefix(prefixRaw);
const { path: postfix, query, fragment } = parsePathQueryFragment(
postfixRaw
const { path: postfix, query, fragment } = parseResource(
postfixRaw,
parser
);
const regExp = new RegExp(
`^${quoteMeta(prefix)}${options.wrappedContextRegExp.source}${quoteMeta(

View File

@ -246,16 +246,59 @@ exports.absolutify = absolutify;
const PATH_QUERY_FRAGMENT_REGEXP = /^([^?#]*)(\?[^#]*)?(#.*)?$/;
/** @typedef {{ resource: string, path: string, query: string, fragment: string }} ParsedResource */
/**
* @param {string} str the path with query and fragment
* @returns {{ path: string, query: string, fragment: string }} parsed parts
* @returns {ParsedResource} parsed parts
*/
const parsePathQueryFragment = str => {
const _parseResource = str => {
const match = PATH_QUERY_FRAGMENT_REGEXP.exec(str);
return {
resource: str,
path: match[1],
query: match[2] || "",
fragment: match[3] || ""
};
};
exports.parsePathQueryFragment = parsePathQueryFragment;
exports.parseResource = (realFn => {
/** @type {WeakMap<object, Map<string, ParsedResource>>} */
const cache = new WeakMap();
const getCache = associatedObjectForCache => {
const entry = cache.get(associatedObjectForCache);
if (entry !== undefined) return entry;
/** @type {Map<string, ParsedResource>} */
const map = new Map();
cache.set(associatedObjectForCache, map);
return map;
};
/**
* @param {string} str the path with query and fragment
* @param {Object=} associatedObjectForCache an object to which the cache will be attached
* @returns {ParsedResource} parsed parts
*/
const fn = (str, associatedObjectForCache) => {
if (!associatedObjectForCache) return realFn(str);
const cache = getCache(associatedObjectForCache);
const entry = cache.get(str);
if (entry !== undefined) return entry;
const result = realFn(str);
cache.set(str, result);
return result;
};
fn.bindCache = associatedObjectForCache => {
const cache = getCache(associatedObjectForCache);
return str => {
const entry = cache.get(str);
if (entry !== undefined) return entry;
const result = realFn(str);
cache.set(str, result);
return result;
};
};
return fn;
})(_parseResource);