Skip to content

Commit 870fcad

Browse files
authored
Merge pull request #15423 from webpack/fix/issue-15409
Fix resolving with yield
2 parents cbfea76 + 0fe4470 commit 870fcad

File tree

30 files changed

+490
-222
lines changed

30 files changed

+490
-222
lines changed

lib/ContextModule.js

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const makeSerializable = require("./util/makeSerializable");
6161

6262
/**
6363
* @typedef {Object} ContextModuleOptionsExtras
64-
* @property {string} resource
64+
* @property {false|string|string[]} resource
6565
* @property {string=} resourceQuery
6666
* @property {string=} resourceFragment
6767
* @property {TODO} resolveOptions
@@ -92,23 +92,36 @@ class ContextModule extends Module {
9292
* @param {ContextModuleOptions} options options object
9393
*/
9494
constructor(resolveDependencies, options) {
95-
const parsed = parseResource(options ? options.resource : "");
96-
const resource = parsed.path;
97-
const resourceQuery = (options && options.resourceQuery) || parsed.query;
98-
const resourceFragment =
99-
(options && options.resourceFragment) || parsed.fragment;
100-
101-
super("javascript/dynamic", resource);
95+
if (!options || typeof options.resource === "string") {
96+
const parsed = parseResource(
97+
options ? /** @type {string} */ (options.resource) : ""
98+
);
99+
const resource = parsed.path;
100+
const resourceQuery = (options && options.resourceQuery) || parsed.query;
101+
const resourceFragment =
102+
(options && options.resourceFragment) || parsed.fragment;
103+
104+
super("javascript/dynamic", resource);
105+
/** @type {ContextModuleOptions} */
106+
this.options = {
107+
...options,
108+
resource,
109+
resourceQuery,
110+
resourceFragment
111+
};
112+
} else {
113+
super("javascript/dynamic");
114+
/** @type {ContextModuleOptions} */
115+
this.options = {
116+
...options,
117+
resource: options.resource,
118+
resourceQuery: options.resourceQuery || "",
119+
resourceFragment: options.resourceFragment || ""
120+
};
121+
}
102122

103123
// Info from Factory
104124
this.resolveDependencies = resolveDependencies;
105-
/** @type {ContextModuleOptions} */
106-
this.options = {
107-
...options,
108-
resource,
109-
resourceQuery,
110-
resourceFragment
111-
};
112125
if (options && options.resolveOptions !== undefined) {
113126
this.resolveOptions = options.resolveOptions;
114127
}
@@ -155,7 +168,12 @@ class ContextModule extends Module {
155168
}
156169

157170
_createIdentifier() {
158-
let identifier = this.context;
171+
let identifier =
172+
this.context ||
173+
(typeof this.options.resource === "string" ||
174+
this.options.resource === false
175+
? `${this.options.resource}`
176+
: this.options.resource.join("|"));
159177
if (this.options.resourceQuery) {
160178
identifier += `|${this.options.resourceQuery}`;
161179
}
@@ -220,7 +238,19 @@ class ContextModule extends Module {
220238
* @returns {string} a user readable identifier of the module
221239
*/
222240
readableIdentifier(requestShortener) {
223-
let identifier = requestShortener.shorten(this.context) + "/";
241+
let identifier;
242+
if (this.context) {
243+
identifier = requestShortener.shorten(this.context) + "/";
244+
} else if (
245+
typeof this.options.resource === "string" ||
246+
this.options.resource === false
247+
) {
248+
identifier = requestShortener.shorten(`${this.options.resource}`) + "/";
249+
} else {
250+
identifier = this.options.resource
251+
.map(r => requestShortener.shorten(r) + "/")
252+
.join(" ");
253+
}
224254
if (this.options.resourceQuery) {
225255
identifier += ` ${this.options.resourceQuery}`;
226256
}
@@ -270,11 +300,30 @@ class ContextModule extends Module {
270300
* @returns {string | null} an identifier for library inclusion
271301
*/
272302
libIdent(options) {
273-
let identifier = contextify(
274-
options.context,
275-
this.context,
276-
options.associatedObjectForCache
277-
);
303+
let identifier;
304+
305+
if (this.context) {
306+
identifier = contextify(
307+
options.context,
308+
this.context,
309+
options.associatedObjectForCache
310+
);
311+
} else if (typeof this.options.resource === "string") {
312+
identifier = contextify(
313+
options.context,
314+
this.options.resource,
315+
options.associatedObjectForCache
316+
);
317+
} else if (this.options.resource === false) {
318+
identifier = "false";
319+
} else {
320+
identifier = this.options.resource
321+
.map(res =>
322+
contextify(options.context, res, options.associatedObjectForCache)
323+
)
324+
.join(" ");
325+
}
326+
278327
if (this.layer) identifier = `(${this.layer})/${identifier}`;
279328
if (this.options.mode) {
280329
identifier += ` ${this.options.mode}`;
@@ -323,8 +372,9 @@ class ContextModule extends Module {
323372
// build if enforced
324373
if (this._forceBuild) return callback(null, true);
325374

326-
// always build when we have no snapshot
327-
if (!this.buildInfo.snapshot) return callback(null, true);
375+
// always build when we have no snapshot and context
376+
if (!this.buildInfo.snapshot)
377+
return callback(null, Boolean(this.context || this.options.resource));
328378

329379
fileSystemInfo.checkSnapshotValid(this.buildInfo.snapshot, (err, valid) => {
330380
callback(err, !valid);
@@ -439,10 +489,16 @@ class ContextModule extends Module {
439489
);
440490
return;
441491
}
492+
if (!this.context && !this.options.resource) return callback();
493+
442494
compilation.fileSystemInfo.createSnapshot(
443495
startTime,
444496
null,
445-
[this.context],
497+
this.context
498+
? [this.context]
499+
: typeof this.options.resource === "string"
500+
? [this.options.resource]
501+
: /** @type {string[]} */ (this.options.resource),
446502
null,
447503
SNAPSHOT_OPTIONS,
448504
(err, snapshot) => {
@@ -466,7 +522,15 @@ class ContextModule extends Module {
466522
missingDependencies,
467523
buildDependencies
468524
) {
469-
contextDependencies.add(this.context);
525+
if (this.context) {
526+
contextDependencies.add(this.context);
527+
} else if (typeof this.options.resource === "string") {
528+
contextDependencies.add(this.options.resource);
529+
} else if (this.options.resource === false) {
530+
return;
531+
} else {
532+
for (const res of this.options.resource) contextDependencies.add(res);
533+
}
470534
}
471535

472536
/**

lib/ContextModuleFactory.js

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,22 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
167167
asyncLib.parallel(
168168
[
169169
callback => {
170+
const results = [];
171+
const yield_ = obj => results.push(obj);
172+
170173
contextResolver.resolve(
171174
{},
172175
context,
173176
resource,
174177
{
175178
fileDependencies,
176179
missingDependencies,
177-
contextDependencies
180+
contextDependencies,
181+
yield: yield_
178182
},
179-
(err, result) => {
183+
err => {
180184
if (err) return callback(err);
181-
callback(null, result);
185+
callback(null, results);
182186
}
183187
);
184188
},
@@ -213,15 +217,25 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
213217
contextDependencies
214218
});
215219
}
216-
220+
let [contextResult, loaderResult] = result;
221+
if (contextResult.length > 1) {
222+
const first = contextResult[0];
223+
contextResult = contextResult.filter(r => r.path);
224+
if (contextResult.length === 0) contextResult.push(first);
225+
}
217226
this.hooks.afterResolve.callAsync(
218227
{
219228
addon:
220229
loadersPrefix +
221-
result[1].join("!") +
222-
(result[1].length > 0 ? "!" : ""),
223-
resource: result[0],
230+
loaderResult.join("!") +
231+
(loaderResult.length > 0 ? "!" : ""),
232+
resource:
233+
contextResult.length > 1
234+
? contextResult.map(r => r.path)
235+
: contextResult[0].path,
224236
resolveDependencies: this.resolveDependencies.bind(this),
237+
resourceQuery: contextResult[0].query,
238+
resourceFragment: contextResult[0].fragment,
225239
...beforeResolveResult
226240
},
227241
(err, result) => {
@@ -278,26 +292,28 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
278292
} = options;
279293
if (!regExp || !resource) return callback(null, []);
280294

281-
const addDirectoryChecked = (directory, visited, callback) => {
295+
let severalContexts = false;
296+
const addDirectoryChecked = (ctx, directory, visited, callback) => {
282297
fs.realpath(directory, (err, realPath) => {
283298
if (err) return callback(err);
284299
if (visited.has(realPath)) return callback(null, []);
285300
let recursionStack;
286301
addDirectory(
302+
ctx,
287303
directory,
288-
(dir, callback) => {
304+
(_, dir, callback) => {
289305
if (recursionStack === undefined) {
290306
recursionStack = new Set(visited);
291307
recursionStack.add(realPath);
292308
}
293-
addDirectoryChecked(dir, recursionStack, callback);
309+
addDirectoryChecked(ctx, dir, recursionStack, callback);
294310
},
295311
callback
296312
);
297313
});
298314
};
299315

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

325341
if (stat.isDirectory()) {
326342
if (!recursive) return callback();
327-
addSubDirectory(subResource, callback);
343+
addSubDirectory(ctx, subResource, callback);
328344
} else if (
329345
stat.isFile() &&
330346
(!include || subResource.match(include))
331347
) {
332348
const obj = {
333-
context: resource,
349+
context: ctx,
334350
request:
335-
"." +
336-
subResource.substr(resource.length).replace(/\\/g, "/")
351+
"." + subResource.substr(ctx.length).replace(/\\/g, "/")
337352
};
338353

339354
this.hooks.alternativeRequests.callAsync(
@@ -344,8 +359,11 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
344359
alternatives = alternatives
345360
.filter(obj => regExp.test(obj.request))
346361
.map(obj => {
362+
const request = severalContexts
363+
? join(fs, obj.context, obj.request)
364+
: obj.request;
347365
const dep = new ContextElementDependency(
348-
obj.request + resourceQuery + resourceFragment,
366+
request + resourceQuery + resourceFragment,
349367
obj.request,
350368
typePrefix,
351369
category,
@@ -382,12 +400,38 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
382400
});
383401
};
384402

385-
if (typeof fs.realpath === "function") {
386-
addDirectoryChecked(resource, new Set(), callback);
403+
const addSubDirectory = (ctx, dir, callback) =>
404+
addDirectory(ctx, dir, addSubDirectory, callback);
405+
406+
const visitResource = (resource, callback) => {
407+
if (typeof fs.realpath === "function") {
408+
addDirectoryChecked(resource, resource, new Set(), callback);
409+
} else {
410+
addDirectory(resource, resource, addSubDirectory, callback);
411+
}
412+
};
413+
414+
if (typeof resource === "string") {
415+
visitResource(resource, callback);
387416
} else {
388-
const addSubDirectory = (dir, callback) =>
389-
addDirectory(dir, addSubDirectory, callback);
390-
addDirectory(resource, addSubDirectory, callback);
417+
severalContexts = true;
418+
asyncLib.map(resource, visitResource, (err, result) => {
419+
if (err) return callback(err);
420+
421+
// result dependencies should have unique userRequest
422+
// ordered by resolve result
423+
const temp = new Set();
424+
const res = [];
425+
for (let i = 0; i < result.length; i++) {
426+
const inner = result[i];
427+
for (const el of inner) {
428+
if (temp.has(el.userRequest)) continue;
429+
res.push(el);
430+
temp.add(el.userRequest);
431+
}
432+
}
433+
callback(null, res);
434+
});
391435
}
392436
}
393437
};

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy