Skip to content

Commit 3ff741f

Browse files
fix: match urlHints rules written as logical conditions
1 parent d16b388 commit 3ff741f

7 files changed

Lines changed: 84 additions & 10 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"webpack": patch
3+
---
4+
5+
Match `urlHints` rules written with `and`, `or` and `not` conditions.

‎lib/prefetch/ResourceHintPlugin.js‎

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"use strict";
66

77
const { RawSource } = require("webpack-sources");
8-
const ModuleFilenameHelpers = require("../devtool/ModuleFilenameHelpers");
98
const isDependencyKind = require("../graph/isDependencyKind");
109
const {
1110
ASSET_URL_TYPE,
@@ -54,12 +53,13 @@ const parseResourceHintOptions = require("./parseResourceHintOptions");
5453
* @import {
5554
* ResourceHintsInitial as ResourceHintsConfig,
5655
* ResourceHintsOptions,
56+
* RuleSetCondition,
57+
* RuleSetLogicalConditions,
5758
* UrlHintRule
5859
* } from "../../declarations/WebpackOptions"
5960
*/
6061
/** @import { HtmlResourceHint } from "../dependencies/html/HtmlEntryDependency" */
6162
/** @import { ResourceHintOptions } from "./parseResourceHintOptions" */
62-
/** @import { MatchObject } from "../devtool/ModuleFilenameHelpers" */
6363

6464
/**
6565
* @typedef {object} ResolvedResourceHints
@@ -198,6 +198,38 @@ function* iterateHintedUrlAssets(compilation, chunks) {
198198
}
199199
}
200200

201+
/** @type {WeakMap<UrlHintRule, (request: string) => boolean>} */
202+
const urlHintMatchers = new WeakMap();
203+
204+
/**
205+
* A rule's `test`, `include` and `exclude` as one predicate, read as `module.rules`
206+
* reads a condition, so `and`/`or`/`not`/`glob` work too. Compiled once per rule.
207+
* @param {UrlHintRule} rule rule setting at least one of the three
208+
* @returns {(request: string) => boolean} whether the rule applies to a request
209+
*/
210+
const getUrlHintMatcher = (rule) => {
211+
let matcher = urlHintMatchers.get(rule);
212+
if (matcher === undefined) {
213+
/** @type {RuleSetCondition[]} */
214+
const all = [];
215+
if (rule.test !== undefined) all.push(rule.test);
216+
if (rule.include !== undefined) all.push(rule.include);
217+
/** @type {RuleSetLogicalConditions} */
218+
const condition = {};
219+
if (all.length > 0) condition.and = all;
220+
if (rule.exclude !== undefined) condition.not = rule.exclude;
221+
222+
const RuleSetCompiler = require("../rules/RuleSetCompiler");
223+
224+
matcher = new RuleSetCompiler([]).compileCondition(
225+
"urlHints",
226+
condition
227+
).fn;
228+
urlHintMatchers.set(rule, matcher);
229+
}
230+
return matcher;
231+
};
232+
201233
/**
202234
* Merge the matching `UrlHintRule`s for a request. Rules match by
203235
* `test`/`include`/`exclude` (omit all three → matches everything); later
@@ -216,14 +248,7 @@ const matchUrlHints = (rules, request) => {
216248
(rule.test !== undefined ||
217249
rule.include !== undefined ||
218250
rule.exclude !== undefined) &&
219-
!ModuleFilenameHelpers.matchObject(
220-
/** @type {MatchObject} */ ({
221-
test: rule.test,
222-
include: rule.include,
223-
exclude: rule.exclude
224-
}),
225-
request
226-
)
251+
!getUrlHintMatcher(rule)(request)
227252
) {
228253
continue;
229254
}

‎test/configCases/asset-modules/url-hints-logical-conditions/a.png‎

Loading

‎test/configCases/asset-modules/url-hints-logical-conditions/b.png‎

Loading

‎test/configCases/asset-modules/url-hints-logical-conditions/font.woff2‎

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"use strict";
2+
3+
const a = new URL("./a.png", import.meta.url);
4+
const b = new URL("./b.png", import.meta.url);
5+
const font = new URL("./font.woff2", import.meta.url);
6+
7+
const findLink = (name) =>
8+
document.head._children.find(
9+
(el) => el._type === "link" && el.href.endsWith(`/${name}`)
10+
);
11+
12+
it("should match urlHints rules written as logical conditions", () => {
13+
expect(a.href).toContain("a.png");
14+
expect(b.href).toContain("b.png");
15+
expect(font.href).toContain("font.woff2");
16+
expect(findLink("a.png").rel).toBe("preload");
17+
expect(findLink("b.png").rel).toBe("prefetch");
18+
expect(findLink("font.woff2").rel).toBe("prefetch");
19+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"use strict";
2+
3+
/** @type {import("../../../../").Configuration} */
4+
module.exports = {
5+
mode: "development",
6+
target: "web",
7+
output: {
8+
assetModuleFilename: "[name][ext]",
9+
publicPath: "https://example.com/public/",
10+
resourceHints: {
11+
urlHints: [
12+
{
13+
test: { and: [/\.png$/, { not: /b\.png$/ }] },
14+
preload: true,
15+
as: "image"
16+
},
17+
{ test: [{ not: /\.png$/ }], prefetch: true },
18+
{ include: { or: [/b\.png$/] }, prefetch: true }
19+
]
20+
}
21+
},
22+
module: {
23+
rules: [{ test: /\.(png|woff2)$/, type: "asset/resource" }]
24+
}
25+
};

0 commit comments

Comments
 (0)