Skip to content

Commit

Permalink
handle several resources in ContextModule
Browse files Browse the repository at this point in the history
  • Loading branch information
vankop committed Feb 8, 2022
1 parent afbf602 commit 9951d9d
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 50 deletions.
101 changes: 77 additions & 24 deletions lib/ContextModule.js
Expand Up @@ -61,7 +61,7 @@ const makeSerializable = require("./util/makeSerializable");

/**
* @typedef {Object} ContextModuleOptionsExtras
* @property {string} resource
* @property {string|string[]} resource
* @property {string=} resourceQuery
* @property {string=} resourceFragment
* @property {TODO} resolveOptions
Expand Down Expand Up @@ -92,23 +92,34 @@ 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 (typeof options.resource !== "string") {
super("javascript/dynamic");
/** @type {ContextModuleOptions} */
this.options = {
...options,
resource: options.resource,
resourceQuery: options.resourceQuery || "",
resourceFragment: options.resourceFragment || ""
};
} else {
const parsed = parseResource(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
};
}

// 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 +166,11 @@ class ContextModule extends Module {
}

_createIdentifier() {
let identifier = this.context;
let identifier =
this.context ||
(typeof this.options.resource === "string"
? this.options.resource
: this.options.resource.join("|"));
if (this.options.resourceQuery) {
identifier += `|${this.options.resourceQuery}`;
}
Expand Down Expand Up @@ -220,7 +235,16 @@ 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") {
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 +294,30 @@ 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 {
const arr = [];
for (const res of this.options.resource) {
arr.push(
contextify(options.context, res, options.associatedObjectForCache)
);
}
identifier = arr.join("|");
}

if (this.layer) identifier = `(${this.layer})/${identifier}`;
if (this.options.mode) {
identifier += ` ${this.options.mode}`;
Expand Down Expand Up @@ -442,7 +485,11 @@ class ContextModule extends Module {
compilation.fileSystemInfo.createSnapshot(
startTime,
null,
[this.context],
this.context
? [this.context]
: typeof this.options.resource === "string"
? [this.options.resource]
: this.options.resource,
null,
SNAPSHOT_OPTIONS,
(err, snapshot) => {
Expand All @@ -466,7 +513,13 @@ 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 {
for (const res of this.options.resource) contextDependencies.add(res);
}
}

/**
Expand Down
75 changes: 56 additions & 19 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,14 +217,17 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
contextDependencies
});
}

const [contextResult, loaderResult] = result;
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),
...beforeResolveResult
},
Expand Down Expand Up @@ -278,26 +285,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) => {
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 Down Expand Up @@ -330,10 +339,9 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
(!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 +352,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 +393,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, 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);
});
}
}
};
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -14,7 +14,7 @@
"acorn-import-assertions": "^1.7.6",
"browserslist": "^4.14.5",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.8.3",
"enhanced-resolve": "^5.9.0",
"es-module-lexer": "^0.9.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
Expand Down
18 changes: 18 additions & 0 deletions test/configCases/resolve/issue-11335-context-module/index.js
@@ -0,0 +1,18 @@
import a from "app/widgets/a";
import b from "app/widgets/b";
import c from "app/widgets/c";


it("static imports order", () => {
expect(a).toBe("main/widgets/a");
expect(b).toBe("main/widgets/b");
expect(c).toBe("foo/widgets/c");
});

const load = id => import(/* webpackMode: "eager" */ `app/widgets/${id}?query#hash`);

it("dynamic imports order", async () => {
expect((await load("a")).default).toBe("main/widgets/a");
expect((await load("b")).default).toBe("main/widgets/b");
expect((await load("c")).default).toBe("foo/widgets/c");
});
@@ -0,0 +1 @@
export default "foo/widgets/b";
@@ -0,0 +1 @@
export default "foo/widgets/c";
@@ -0,0 +1 @@
export default "main/widgets/a";
@@ -0,0 +1 @@
export default "main/widgets/b";
@@ -0,0 +1,10 @@
const path = require("path");

/** @type {import("../../../../").Configuration} */
module.exports = {
resolve: {
alias: {
app: [path.join(__dirname, "src/main"), path.join(__dirname, "src/foo")]
}
}
};
9 changes: 7 additions & 2 deletions types.d.ts
Expand Up @@ -2519,7 +2519,7 @@ declare interface ContextModuleOptions {
* exports referenced from modules (won't be mangled)
*/
referencedExports?: string[][];
resource: string;
resource: string | string[];
resourceQuery?: string;
resourceFragment?: string;
resolveOptions: any;
Expand Down Expand Up @@ -9389,6 +9389,11 @@ declare interface ResolveContext {
* log function
*/
log?: (arg0: string) => void;

/**
* yield result, if provided plugins can return several results
*/
yield?: (arg0: ResolveRequest) => void;
}
declare interface ResolveData {
contextInfo: ModuleFactoryCreateDataContextInfo;
Expand Down Expand Up @@ -11835,7 +11840,7 @@ declare interface UserResolveOptions {
restrictions?: (string | RegExp)[];

/**
* Use only the sync constiants of the file system calls
* Use only the sync constraints of the file system calls
*/
useSyncFileSystemCalls?: boolean;

Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Expand Up @@ -2256,10 +2256,10 @@ enhanced-resolve@^4.0.0:
memory-fs "^0.5.0"
tapable "^1.0.0"

enhanced-resolve@^5.8.3:
version "5.8.3"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0"
integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==
enhanced-resolve@^5.9.0:
version "5.9.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.0.tgz#49ac24953ac8452ed8fed2ef1340fc8e043667ee"
integrity sha512-weDYmzbBygL7HzGGS26M3hGQx68vehdEg6VUmqSOaFzXExFqlnKuSvsEJCVGQHScS8CQMbrAqftT+AzzHNt/YA==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
Expand Down

0 comments on commit 9951d9d

Please sign in to comment.