Skip to content

Commit fe3ca80

Browse files
authored
Merge pull request webpack#7462 from webpack/feature/match-resource
Add matchResource feature (for loaders)
2 parents 2491f5d + 530e1fb commit fe3ca80

10 files changed

+140
-26
lines changed

lib/NormalModule.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,18 @@ const contextify = (context, request) => {
4343
.split("!")
4444
.map(r => {
4545
const splitPath = r.split("?");
46-
splitPath[0] = path.relative(context, splitPath[0]);
47-
if (path.sep === "\\") splitPath[0] = splitPath[0].replace(/\\/g, "/");
48-
if (splitPath[0].indexOf("../") !== 0) splitPath[0] = "./" + splitPath[0];
46+
if (/^[a-zA-Z]:\\/.test(splitPath[0])) {
47+
splitPath[0] = path.win32.relative(context, splitPath[0]);
48+
if (!/^[a-zA-Z]:\\/.test(splitPath[0])) {
49+
splitPath[0] = splitPath[0].replace(/\\/g, "/");
50+
}
51+
}
52+
if (/^\//.test(splitPath[0])) {
53+
splitPath[0] = path.posix.relative(context, splitPath[0]);
54+
}
55+
if (!/^(\.\.\/|\/|[a-zA-Z]:\\)/.test(splitPath[0])) {
56+
splitPath[0] = "./" + splitPath[0];
57+
}
4958
return splitPath.join("?");
5059
})
5160
.join("!");
@@ -76,6 +85,7 @@ class NormalModule extends Module {
7685
rawRequest,
7786
loaders,
7887
resource,
88+
matchResource,
7989
parser,
8090
generator,
8191
resolveOptions
@@ -90,6 +100,7 @@ class NormalModule extends Module {
90100
this.parser = parser;
91101
this.generator = generator;
92102
this.resource = resource;
103+
this.matchResource = matchResource;
93104
this.loaders = loaders;
94105
if (resolveOptions !== undefined) this.resolveOptions = resolveOptions;
95106

@@ -123,16 +134,21 @@ class NormalModule extends Module {
123134
}
124135

125136
nameForCondition() {
126-
const idx = this.resource.indexOf("?");
127-
if (idx >= 0) return this.resource.substr(0, idx);
128-
return this.resource;
137+
const resource = this.matchResource || this.resource;
138+
const idx = resource.indexOf("?");
139+
if (idx >= 0) return resource.substr(0, idx);
140+
return resource;
129141
}
130142

131143
updateCacheModule(module) {
144+
this.type = module.type;
145+
this.request = module.request;
132146
this.userRequest = module.userRequest;
147+
this.rawRequest = module.rawRequest;
133148
this.parser = module.parser;
134149
this.generator = module.generator;
135150
this.resource = module.resource;
151+
this.matchResource = module.matchResource;
136152
this.loaders = module.loaders;
137153
this.resolveOptions = module.resolveOptions;
138154
}

lib/NormalModuleFactory.js

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
"use strict";
66

7+
const path = require("path");
78
const asyncLib = require("neo-async");
89
const {
910
Tapable,
@@ -20,6 +21,8 @@ const cachedMerge = require("./util/cachedMerge");
2021

2122
const EMPTY_RESOLVE_OPTIONS = {};
2223

24+
const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
25+
2326
const loaderToIdent = data => {
2427
if (!data.options) {
2528
return data.loader;
@@ -158,19 +161,33 @@ class NormalModuleFactory extends Tapable {
158161
const context = data.context;
159162
const request = data.request;
160163

161-
const noPreAutoLoaders = request.startsWith("-!");
162-
const noAutoLoaders = noPreAutoLoaders || request.startsWith("!");
163-
const noPrePostAutoLoaders = request.startsWith("!!");
164-
let elements = request
164+
const loaderResolver = this.getResolver("loader");
165+
const normalResolver = this.getResolver("normal", data.resolveOptions);
166+
167+
let matchResource = undefined;
168+
let requestWithoutMatchResource = request;
169+
const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
170+
if (matchResourceMatch) {
171+
matchResource = matchResourceMatch[1];
172+
if (/^\.\.?\//.test(matchResource)) {
173+
matchResource = path.join(context, matchResource);
174+
}
175+
requestWithoutMatchResource = request.substr(
176+
matchResourceMatch[0].length
177+
);
178+
}
179+
180+
const noPreAutoLoaders = requestWithoutMatchResource.startsWith("-!");
181+
const noAutoLoaders =
182+
noPreAutoLoaders || requestWithoutMatchResource.startsWith("!");
183+
const noPrePostAutoLoaders = requestWithoutMatchResource.startsWith("!!");
184+
let elements = requestWithoutMatchResource
165185
.replace(/^-?!+/, "")
166186
.replace(/!!+/g, "!")
167187
.split("!");
168188
let resource = elements.pop();
169189
elements = elements.map(identToLoaderRequest);
170190

171-
const loaderResolver = this.getResolver("loader");
172-
const normalResolver = this.getResolver("normal", data.resolveOptions);
173-
174191
asyncLib.parallel(
175192
[
176193
callback =>
@@ -234,12 +251,15 @@ class NormalModuleFactory extends Tapable {
234251
);
235252
}
236253

237-
const userRequest = loaders
238-
.map(loaderToIdent)
239-
.concat([resource])
240-
.join("!");
254+
const userRequest =
255+
(matchResource !== undefined ? `${matchResource}!=!` : "") +
256+
loaders
257+
.map(loaderToIdent)
258+
.concat([resource])
259+
.join("!");
241260

242-
let resourcePath = resource;
261+
let resourcePath =
262+
matchResource !== undefined ? matchResource : resource;
243263
let resourceQuery = "";
244264
const queryIndex = resourcePath.indexOf("?");
245265
if (queryIndex >= 0) {
@@ -249,6 +269,10 @@ class NormalModuleFactory extends Tapable {
249269

250270
const result = this.ruleSet.exec({
251271
resource: resourcePath,
272+
realResource:
273+
matchResource !== undefined
274+
? resource.replace(/\?.*/, "")
275+
: resourcePath,
252276
resourceQuery,
253277
issuer: contextInfo.issuer,
254278
compiler: contextInfo.compiler
@@ -326,6 +350,7 @@ class NormalModuleFactory extends Tapable {
326350
rawRequest: request,
327351
loaders,
328352
resource,
353+
matchResource,
329354
resourceResolveData,
330355
settings,
331356
type,

lib/RequestShortener.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const PATH_CHARS_REGEXP = /[-[\]{}()*+?.,\\^$|#\s]/g;
1010
const SEPARATOR_REGEXP = /[/\\]$/;
1111
const FRONT_OR_BACK_BANG_REGEXP = /^!|!$/g;
1212
const INDEX_JS_REGEXP = /\/index.js(!|\?|\(query\))/g;
13+
const MATCH_RESOURCE_REGEXP = /!=!/;
1314

1415
const normalizeBackSlashDirection = request => {
1516
return request.replace(NORMALIZE_SLASH_DIRECTION_REGEXP, "/");
@@ -73,6 +74,7 @@ class RequestShortener {
7374
}
7475
result = result.replace(INDEX_JS_REGEXP, "$1");
7576
result = result.replace(FRONT_OR_BACK_BANG_REGEXP, "");
77+
result = result.replace(MATCH_RESOURCE_REGEXP, " = ");
7678
this.cache.set(request, result);
7779
return result;
7880
}

lib/RuleSet.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ module.exports = class RuleSet {
203203
}
204204
}
205205

206+
if (rule.realResource) {
207+
try {
208+
newRule.realResource = RuleSet.normalizeCondition(rule.realResource);
209+
} catch (error) {
210+
throw new Error(RuleSet.buildErrorMessage(rule.realResource, error));
211+
}
212+
}
213+
206214
if (rule.resourceQuery) {
207215
try {
208216
newRule.resourceQuery = RuleSet.normalizeCondition(rule.resourceQuery);
@@ -477,10 +485,13 @@ module.exports = class RuleSet {
477485
_run(data, rule, result) {
478486
// test conditions
479487
if (rule.resource && !data.resource) return false;
488+
if (rule.realResource && !data.realResource) return false;
480489
if (rule.resourceQuery && !data.resourceQuery) return false;
481490
if (rule.compiler && !data.compiler) return false;
482491
if (rule.issuer && !data.issuer) return false;
483492
if (rule.resource && !rule.resource(data.resource)) return false;
493+
if (rule.realResource && !rule.realResource(data.realResource))
494+
return false;
484495
if (data.issuer && rule.issuer && !rule.issuer(data.issuer)) return false;
485496
if (
486497
data.resourceQuery &&
@@ -497,6 +508,7 @@ module.exports = class RuleSet {
497508
const keys = Object.keys(rule).filter(key => {
498509
return ![
499510
"resource",
511+
"realResource",
500512
"resourceQuery",
501513
"compiler",
502514
"issuer",

test/NormalModule.unittest.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ describe("NormalModule", () => {
1616
let resource;
1717
let parser;
1818
beforeEach(() => {
19-
request = "some/request";
20-
userRequest = "some/userRequest";
19+
request = "/some/request";
20+
userRequest = "/some/userRequest";
2121
rawRequest = "some/rawRequest";
2222
loaders = [];
23-
resource = "some/resource";
23+
resource = "/some/resource";
2424
parser = {
2525
parse() {}
2626
};
@@ -66,14 +66,14 @@ describe("NormalModule", () => {
6666
it("contextifies the userRequest of the module", () => {
6767
expect(
6868
normalModule.libIdent({
69-
context: "some/context"
69+
context: "/some/context"
7070
})
7171
).toBe("../userRequest");
7272
});
7373
describe("given a userRequest containing loaders", () => {
7474
beforeEach(() => {
7575
userRequest =
76-
"some/userRequest!some/other/userRequest!some/thing/is/off/here";
76+
"/some/userRequest!/some/other/userRequest!/some/thing/is/off/here";
7777
normalModule = new NormalModule({
7878
type: "javascript/auto",
7979
request,
@@ -87,15 +87,15 @@ describe("NormalModule", () => {
8787
it("contextifies every path in the userRequest", () => {
8888
expect(
8989
normalModule.libIdent({
90-
context: "some/context"
90+
context: "/some/context"
9191
})
9292
).toBe("../userRequest!../other/userRequest!../thing/is/off/here");
9393
});
9494
});
9595
describe("given a userRequest containing query parameters", () => {
9696
it("ignores paths in query parameters", () => {
9797
userRequest =
98-
"some/context/loader?query=foo\\bar&otherPath=testpath/other";
98+
"F:\\some\\context\\loader?query=foo\\bar&otherPath=testpath/other";
9999
normalModule = new NormalModule({
100100
type: "javascript/auto",
101101
request,
@@ -107,7 +107,7 @@ describe("NormalModule", () => {
107107
});
108108
expect(
109109
normalModule.libIdent({
110-
context: "some/context"
110+
context: "F:\\some\\context"
111111
})
112112
).toBe("./loader?query=foo\\bar&otherPath=testpath/other");
113113
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
it("should be able to create two modules from loader", function() {
2+
return import("./wrapper-loader!./src/wasm.dat").then(function(wasm) {
3+
expect(wasm.getString()).toEqual("Hello World");
4+
});
5+
});
6+
7+
it("should be able to create two modules from loader with remaining request", function() {
8+
return import("./wrapper-loader2!./src/wasm.dat?2").then(function(wasm) {
9+
expect(wasm.getString()).toEqual("Hello World");
10+
});
11+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
(module
2+
(memory (export "memory") 1)
3+
(data (i32.const 16) "Hello World\00")
4+
(func (export "getString") (result i32)
5+
(i32.const 16)
6+
)
7+
)
8+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var supportsWebAssembly = require("../../../helpers/supportsWebAssembly");
2+
3+
module.exports = function(config) {
4+
return supportsWebAssembly();
5+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const stringifyRequest = require("loader-utils").stringifyRequest;
2+
3+
module.exports.pitch = function(remainingRequest) {
4+
return `
5+
import { getString as _getString, memory } from ${stringifyRequest(this,
6+
`${this.resourcePath}.wat!=!${remainingRequest}`
7+
)};
8+
9+
export function getString() {
10+
const strBuf = new Uint8Array(memory.buffer, _getString());
11+
const idx = strBuf.indexOf(0);
12+
const strBuf2 = strBuf.slice(0, idx);
13+
const str = Buffer.from(strBuf2).toString("utf-8");
14+
return str;
15+
};
16+
`;
17+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const stringifyRequest = require("loader-utils").stringifyRequest;
2+
3+
module.exports.pitch = function(remainingRequest) {
4+
return `
5+
import { getString as _getString, memory } from ${stringifyRequest(
6+
this,
7+
`${this.resourcePath}.wasm!=!wast-loader!${remainingRequest}`
8+
)};
9+
10+
export function getString() {
11+
const strBuf = new Uint8Array(memory.buffer, _getString());
12+
const idx = strBuf.indexOf(0);
13+
const strBuf2 = strBuf.slice(0, idx);
14+
const str = Buffer.from(strBuf2).toString("utf-8");
15+
return str;
16+
};
17+
`;
18+
};

0 commit comments

Comments
 (0)