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

Fix resolving with yield #15423

Merged
merged 6 commits into from Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
113 changes: 89 additions & 24 deletions lib/ContextModule.js
Expand Up @@ -61,7 +61,7 @@ const makeSerializable = require("./util/makeSerializable");

/**
* @typedef {Object} ContextModuleOptionsExtras
* @property {string} resource
* @property {false|string|string[]} resource
* @property {string=} resourceQuery
* @property {string=} resourceFragment
* @property {TODO} resolveOptions
Expand Down Expand Up @@ -92,23 +92,36 @@ class ContextModule extends Module {
* @param {ContextModuleOptions} options options object
*/
constructor(resolveDependencies, options) {
const parsed = parseResource(options ? options.resource : "");
const resource = parsed.path;
const resourceQuery = (options && options.resourceQuery) || parsed.query;
const resourceFragment =
(options && options.resourceFragment) || parsed.fragment;

super("javascript/dynamic", resource);
if (!options || typeof options.resource === "string") {
const parsed = parseResource(
options ? /** @type {string} */ (options.resource) : ""
);
const resource = parsed.path;
const resourceQuery = (options && options.resourceQuery) || parsed.query;
const resourceFragment =
(options && options.resourceFragment) || parsed.fragment;

super("javascript/dynamic", resource);
/** @type {ContextModuleOptions} */
this.options = {
...options,
resource,
resourceQuery,
resourceFragment
};
} else {
super("javascript/dynamic");
/** @type {ContextModuleOptions} */
this.options = {
...options,
resource: options.resource,
resourceQuery: options.resourceQuery || "",
resourceFragment: options.resourceFragment || ""
};
}

// Info from Factory
this.resolveDependencies = resolveDependencies;
/** @type {ContextModuleOptions} */
this.options = {
...options,
resource,
resourceQuery,
resourceFragment
};
if (options && options.resolveOptions !== undefined) {
this.resolveOptions = options.resolveOptions;
}
Expand Down Expand Up @@ -155,7 +168,12 @@ class ContextModule extends Module {
}

_createIdentifier() {
let identifier = this.context;
let identifier =
this.context ||
(typeof this.options.resource === "string" ||
this.options.resource === false
? `${this.options.resource}`
: this.options.resource.join("|"));
if (this.options.resourceQuery) {
identifier += `|${this.options.resourceQuery}`;
}
Expand Down Expand Up @@ -220,7 +238,19 @@ class ContextModule extends Module {
* @returns {string} a user readable identifier of the module
*/
readableIdentifier(requestShortener) {
let identifier = requestShortener.shorten(this.context) + "/";
let identifier;
if (this.context) {
identifier = requestShortener.shorten(this.context) + "/";
} else if (
typeof this.options.resource === "string" ||
this.options.resource === false
) {
identifier = requestShortener.shorten(`${this.options.resource}`) + "/";
} else {
identifier = this.options.resource
.map(r => requestShortener.shorten(r) + "/")
.join(" ");
}
if (this.options.resourceQuery) {
identifier += ` ${this.options.resourceQuery}`;
}
Expand Down Expand Up @@ -270,11 +300,32 @@ class ContextModule extends Module {
* @returns {string | null} an identifier for library inclusion
*/
libIdent(options) {
let identifier = contextify(
options.context,
this.context,
options.associatedObjectForCache
);
let identifier;

if (this.context) {
identifier = contextify(
options.context,
this.context,
options.associatedObjectForCache
);
} else if (typeof this.options.resource === "string") {
identifier = contextify(
options.context,
this.options.resource,
options.associatedObjectForCache
);
} else if (this.options.resource === false) {
identifier = "false";
} else {
const arr = [];
for (const res of this.options.resource) {
arr.push(
contextify(options.context, res, options.associatedObjectForCache)
);
}
identifier = arr.join(" ");
vankop marked this conversation as resolved.
Show resolved Hide resolved
}

if (this.layer) identifier = `(${this.layer})/${identifier}`;
if (this.options.mode) {
identifier += ` ${this.options.mode}`;
Expand Down Expand Up @@ -439,10 +490,16 @@ class ContextModule extends Module {
);
return;
}
if (!this.context || !this.options.resource) return callback();

compilation.fileSystemInfo.createSnapshot(
startTime,
null,
[this.context],
this.context
? [this.context]
: typeof this.options.resource === "string"
? [this.options.resource]
: /** @type {string[]} */ (this.options.resource),
null,
SNAPSHOT_OPTIONS,
(err, snapshot) => {
Expand All @@ -466,7 +523,15 @@ class ContextModule extends Module {
missingDependencies,
buildDependencies
) {
contextDependencies.add(this.context);
if (this.context) {
contextDependencies.add(this.context);
} else if (typeof this.options.resource === "string") {
contextDependencies.add(this.options.resource);
} else if (this.options.resource === false) {
return;
} else {
for (const res of this.options.resource) contextDependencies.add(res);
}
}

/**
Expand Down
86 changes: 65 additions & 21 deletions lib/ContextModuleFactory.js
Expand Up @@ -167,18 +167,22 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
asyncLib.parallel(
[
callback => {
const results = [];
const yield_ = obj => results.push(obj);

contextResolver.resolve(
{},
context,
resource,
{
fileDependencies,
missingDependencies,
contextDependencies
contextDependencies,
yield: yield_
},
(err, result) => {
err => {
if (err) return callback(err);
callback(null, result);
callback(null, results);
}
);
},
Expand Down Expand Up @@ -213,15 +217,25 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
contextDependencies
});
}

let [contextResult, loaderResult] = result;
if (contextResult.length > 1) {
const first = contextResult[0];
contextResult = contextResult.filter(r => r.path);
if (contextResult.length === 0) contextResult.push(first);
}
this.hooks.afterResolve.callAsync(
{
addon:
loadersPrefix +
result[1].join("!") +
(result[1].length > 0 ? "!" : ""),
resource: result[0],
loaderResult.join("!") +
(loaderResult.length > 0 ? "!" : ""),
resource:
contextResult.length > 1
? contextResult.map(r => r.path)
: contextResult[0].path,
resolveDependencies: this.resolveDependencies.bind(this),
resourceQuery: contextResult[0].query,
resourceFragment: contextResult[0].fragment,
...beforeResolveResult
},
(err, result) => {
Expand Down Expand Up @@ -278,26 +292,28 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
} = options;
if (!regExp || !resource) return callback(null, []);

const addDirectoryChecked = (directory, visited, callback) => {
let severalContexts = false;
const addDirectoryChecked = (ctx, directory, visited, callback) => {
fs.realpath(directory, (err, realPath) => {
if (err) return callback(err);
if (visited.has(realPath)) return callback(null, []);
let recursionStack;
addDirectory(
ctx,
directory,
(dir, callback) => {
(_, dir, callback) => {
if (recursionStack === undefined) {
recursionStack = new Set(visited);
recursionStack.add(realPath);
}
addDirectoryChecked(dir, recursionStack, callback);
addDirectoryChecked(ctx, dir, recursionStack, callback);
},
callback
);
});
};

const addDirectory = (directory, addSubDirectory, callback) => {
const addDirectory = (ctx, directory, addSubDirectory, callback) => {
fs.readdir(directory, (err, files) => {
if (err) return callback(err);
const processedFiles = cmf.hooks.contextModuleFiles.call(
Expand All @@ -324,16 +340,15 @@ module.exports = class ContextModuleFactory extends ModuleFactory {

if (stat.isDirectory()) {
if (!recursive) return callback();
addSubDirectory(subResource, callback);
addSubDirectory(ctx, subResource, callback);
} else if (
stat.isFile() &&
(!include || subResource.match(include))
) {
const obj = {
context: resource,
context: ctx,
request:
"." +
subResource.substr(resource.length).replace(/\\/g, "/")
"." + subResource.substr(ctx.length).replace(/\\/g, "/")
};

this.hooks.alternativeRequests.callAsync(
Expand All @@ -344,8 +359,11 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
alternatives = alternatives
.filter(obj => regExp.test(obj.request))
.map(obj => {
const request = severalContexts
? join(fs, obj.context, obj.request)
: obj.request;
const dep = new ContextElementDependency(
obj.request + resourceQuery + resourceFragment,
request + resourceQuery + resourceFragment,
obj.request,
typePrefix,
category,
Expand Down Expand Up @@ -382,12 +400,38 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
});
};

if (typeof fs.realpath === "function") {
addDirectoryChecked(resource, new Set(), callback);
const addSubDirectory = (ctx, dir, callback) =>
addDirectory(ctx, dir, addSubDirectory, callback);

const visitResource = (resource, callback) => {
if (typeof fs.realpath === "function") {
addDirectoryChecked(resource, resource, new Set(), callback);
} else {
addDirectory(resource, resource, addSubDirectory, callback);
}
};

if (typeof resource === "string") {
visitResource(resource, callback);
} else {
const addSubDirectory = (dir, callback) =>
addDirectory(dir, addSubDirectory, callback);
addDirectory(resource, addSubDirectory, callback);
severalContexts = true;
asyncLib.map(resource, visitResource, (err, result) => {
if (err) return callback(err);

// result dependencies should have unique userRequest
// ordered by resolve result
const temp = new Set();
const res = [];
for (let i = 0; i < result.length; i++) {
const inner = result[i];
for (const el of inner) {
if (temp.has(el.userRequest)) continue;
res.push(el);
temp.add(el.userRequest);
}
}
callback(null, res);
});
}
}
};