Skip to content

Commit 0f1df89

Browse files
authored
feat: add support for new asset query suffixes ?raw, ?url, ?inline, and ?no-inline (#21379)
1 parent 7e05eb1 commit 0f1df89

9 files changed

Lines changed: 192 additions & 28 deletions

File tree

‎.changeset/asset-query-suffixes.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"webpack": minor
3+
---
4+
5+
Add `?raw`, `?url`, `?inline` and `?no-inline` asset query suffixes under `experiments.futureDefaults`.

‎.gitattributes‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
* text=auto
22
test/statsCases/** eol=lf
33
test/hotCases/** eol=lf
4+
test/configCases/asset-modules/query-suffixes/raw.txt eol=lf
45
test/configCases/css/public-path/*.js eol=lf
56
test/configCases/defer-import/** eol=lf
67
test/configCases/html/sources/** eol=lf

‎lib/config/defaults.js‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,28 @@ const applyModuleDefaults = (
14621462
type: "asset/webmanifest"
14631463
});
14641464
}
1465+
if (futureDefaults) {
1466+
rules.push({
1467+
oneOf: [
1468+
{
1469+
resourceQuery: /(\?|&)raw(&|$)/,
1470+
type: ASSET_MODULE_TYPE_SOURCE
1471+
},
1472+
{
1473+
resourceQuery: /(\?|&)url(&|$)/,
1474+
type: ASSET_MODULE_TYPE_RESOURCE
1475+
},
1476+
{
1477+
resourceQuery: /(\?|&)no-inline(&|$)/,
1478+
type: ASSET_MODULE_TYPE_RESOURCE
1479+
},
1480+
{
1481+
resourceQuery: /(\?|&)inline(&|$)/,
1482+
type: ASSET_MODULE_TYPE_INLINE
1483+
}
1484+
]
1485+
});
1486+
}
14651487
return rules;
14661488
});
14671489
};

‎test/Defaults.unittest.js‎

Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3877,12 +3877,12 @@ describe("snapshots", () => {
38773877
+ Object {
38783878
+ "descriptionData": Object {
38793879
+ "type": "module",
3880-
+ },
3880+
@@ ... @@
38813881
+ "resolve": Object {
38823882
+ "byDependency": Object {
38833883
+ "esm": Object {
38843884
+ "fullySpecified": true,
3885-
+ },
3885+
@@ ... @@
38863886
+ },
38873887
+ },
38883888
+ "test": /\\.ts$/i,
@@ -3892,13 +3892,14 @@ describe("snapshots", () => {
38923892
+ "test": /\\.cts$/i,
38933893
+ "type": "javascript/dynamic",
38943894
+ },
3895-
+ Object {
3895+
@@ ... @@
38963896
+ "descriptionData": Object {
38973897
+ "type": "commonjs",
3898-
@@ ... @@
3898+
+ },
38993899
+ "test": /\\.ts$/i,
39003900
+ "type": "javascript/dynamic",
3901-
@@ ... @@
3901+
+ },
3902+
+ Object {
39023903
+ "mimetype": Object {
39033904
+ "or": Array [
39043905
+ "text/typescript",
@@ -3916,6 +3917,27 @@ describe("snapshots", () => {
39163917
+ },
39173918
+ Object {
39183919
@@ ... @@
3920+
+ Object {
3921+
+ "oneOf": Array [
3922+
+ Object {
3923+
+ "resourceQuery": /(\\?|&)raw(&|$)/,
3924+
+ "type": "asset/source",
3925+
+ },
3926+
+ Object {
3927+
+ "resourceQuery": /(\\?|&)url(&|$)/,
3928+
+ "type": "asset/resource",
3929+
+ },
3930+
+ Object {
3931+
+ "resourceQuery": /(\\?|&)no-inline(&|$)/,
3932+
+ "type": "asset/resource",
3933+
+ },
3934+
+ Object {
3935+
+ "resourceQuery": /(\\?|&)inline(&|$)/,
3936+
+ "type": "asset/inline",
3937+
+ },
3938+
+ ],
3939+
+ },
3940+
@@ ... @@
39193941
- "localIdentHashFunction": "md4",
39203942
+ "localIdentHashFunction": "xxhash64",
39213943
@@ ... @@
@@ -4004,15 +4026,15 @@ describe("snapshots", () => {
40044026
+ ".cjs": Array [
40054027
+ ".cjs",
40064028
+ ".cts",
4007-
+ ],
4029+
@@ ... @@
40084030
+ ".js": Array [
40094031
+ ".js",
40104032
+ ".ts",
40114033
+ ],
40124034
+ ".mjs": Array [
40134035
+ ".mjs",
40144036
+ ".mts",
4015-
@@ ... @@
4037+
+ ],
40164038
+ },
40174039
@@ ... @@
40184040
+ "tsconfig": true,
@@ -4400,17 +4422,19 @@ describe("snapshots", () => {
44004422
- "progress": false,
44014423
+ "progress": "auto",
44024424
@@ ... @@
4425+
+ },
4426+
+ },
4427+
+ Object {
44034428
+ "resolve": Object {
44044429
+ "byDependency": Object {
44054430
+ "esm": Object {
44064431
+ "fullySpecified": true,
44074432
+ },
44084433
+ },
4409-
+ },
4434+
@@ ... @@
44104435
+ "test": /\\.mts$/i,
44114436
+ "type": "javascript/esm",
4412-
+ },
4413-
+ Object {
4437+
@@ ... @@
44144438
+ "descriptionData": Object {
44154439
+ "type": "module",
44164440
+ },
@@ -4453,6 +4477,28 @@ describe("snapshots", () => {
44534477
+ },
44544478
+ Object {
44554479
@@ ... @@
4480+
+ },
4481+
+ Object {
4482+
+ "oneOf": Array [
4483+
+ Object {
4484+
+ "resourceQuery": /(\\?|&)raw(&|$)/,
4485+
+ "type": "asset/source",
4486+
+ },
4487+
+ Object {
4488+
+ "resourceQuery": /(\\?|&)url(&|$)/,
4489+
+ "type": "asset/resource",
4490+
+ },
4491+
+ Object {
4492+
+ "resourceQuery": /(\\?|&)no-inline(&|$)/,
4493+
+ "type": "asset/resource",
4494+
@@ ... @@
4495+
+ Object {
4496+
+ "resourceQuery": /(\\?|&)inline(&|$)/,
4497+
+ "type": "asset/inline",
4498+
+ },
4499+
+ ],
4500+
+ },
4501+
@@ ... @@
44564502
- "localIdentHashFunction": "md4",
44574503
+ "localIdentHashFunction": "xxhash64",
44584504
@@ ... @@
@@ -4530,7 +4576,6 @@ describe("snapshots", () => {
45304576
@@ ... @@
45314577
- ".html",
45324578
@@ ... @@
4533-
+ ],
45344579
+ "extensionAlias": Object {
45354580
+ ".cjs": Array [
45364581
+ ".cjs",
@@ -4543,7 +4588,7 @@ describe("snapshots", () => {
45434588
+ ".mjs": Array [
45444589
+ ".mjs",
45454590
+ ".mts",
4546-
@@ ... @@
4591+
+ ],
45474592
+ },
45484593
@@ ... @@
45494594
+ "tsconfig": true,
@@ -4599,12 +4644,12 @@ describe("snapshots", () => {
45994644
- "resolve": Object {
46004645
- "fullySpecified": true,
46014646
- "preferRelative": true,
4647+
- },
4648+
- "type": "css",
46024649
+ "dependency": "html-srcdoc",
46034650
+ "generator": Object {
46044651
+ "extract": "inline",
46054652
@@ ... @@
4606-
- "type": "css",
4607-
- },
46084653
- Object {
46094654
- "dependency": /css-import-local-module/,
46104655
- "exclude": /\\.module\\.\\w+$/i,
@@ -4628,12 +4673,12 @@ describe("snapshots", () => {
46284673
- "resolve": Object {
46294674
- "fullySpecified": true,
46304675
- "preferRelative": true,
4631-
- },
4632-
- "with": Object {
4633-
- "type": "css",
46344676
+ "test": /\\.mts$/i,
46354677
+ "type": "javascript/esm",
46364678
@@ ... @@
4679+
- "with": Object {
4680+
- "type": "css",
4681+
- },
46374682
- },
46384683
@@ ... @@
46394684
- "assert": Object {
@@ -4663,12 +4708,11 @@ describe("snapshots", () => {
46634708
- "resolve": Object {
46644709
- "fullySpecified": true,
46654710
- "preferRelative": true,
4711+
- },
4712+
- "type": "html",
46664713
+ "test": /\\.cts$/i,
46674714
+ "type": "javascript/dynamic",
46684715
@@ ... @@
4669-
- "type": "html",
4670-
- },
4671-
@@ ... @@
46724716
- "dependency": "html-srcdoc",
46734717
- "generator": Object {
46744718
- "extract": "inline",
@@ -4695,7 +4739,6 @@ describe("snapshots", () => {
46954739
+ "esm": Object {
46964740
@@ ... @@
46974741
- "preferRelative": true,
4698-
- },
46994742
@@ ... @@
47004743
- Object {
47014744
- "dependency": "html-style-attribute",
@@ -4706,38 +4749,61 @@ describe("snapshots", () => {
47064749
- "resolve": Object {
47074750
- "fullySpecified": true,
47084751
- "preferRelative": true,
4709-
@@ ... @@
47104752
+ "type": "javascript/esm",
47114753
@@ ... @@
4754+
- },
4755+
@@ ... @@
4756+
- ],
4757+
- "generator": Object {
47124758
- "css": Object {
47134759
- "esModule": true,
47144760
- "exportsOnly": false,
4715-
- },
4761+
+ Object {
4762+
+ "oneOf": Array [
4763+
+ Object {
4764+
+ "resourceQuery": /(\\?|&)raw(&|$)/,
4765+
+ "type": "asset/source",
4766+
@@ ... @@
47164767
- "css/auto": Object {
47174768
- "exportsConvention": "as-is",
47184769
- "localIdentHashDigest": "base64url",
47194770
- "localIdentHashDigestLength": 6,
47204771
- "localIdentHashFunction": "md4",
47214772
- "localIdentHashSalt": undefined,
47224773
- "localIdentName": "[fullhash]",
4723-
- },
4774+
+ Object {
4775+
+ "resourceQuery": /(\\?|&)url(&|$)/,
4776+
+ "type": "asset/resource",
4777+
@@ ... @@
47244778
- "css/global": Object {
47254779
- "exportsConvention": "as-is",
47264780
- "localIdentHashDigest": "base64url",
47274781
- "localIdentHashDigestLength": 6,
47284782
- "localIdentHashFunction": "md4",
47294783
- "localIdentHashSalt": undefined,
47304784
- "localIdentName": "[fullhash]",
4731-
- },
4785+
+ Object {
4786+
+ "resourceQuery": /(\\?|&)no-inline(&|$)/,
4787+
+ "type": "asset/resource",
4788+
@@ ... @@
47324789
- "css/module": Object {
47334790
- "exportsConvention": "as-is",
47344791
- "localIdentHashDigest": "base64url",
47354792
- "localIdentHashDigestLength": 6,
47364793
- "localIdentHashFunction": "md4",
47374794
- "localIdentHashSalt": undefined,
47384795
- "localIdentName": "[fullhash]",
4739-
- },
4796+
+ Object {
4797+
+ "resourceQuery": /(\\?|&)inline(&|$)/,
4798+
+ "type": "asset/inline",
4799+
+ },
4800+
+ ],
47404801
@@ ... @@
4802+
+ ],
4803+
+ "generator": Object {
4804+
@@ ... @@
4805+
- },
4806+
- },
47414807
- "css": Object {
47424808
- "import": true,
47434809
- "namedExports": true,
@@ -4750,15 +4816,15 @@ describe("snapshots", () => {
47504816
- "dashedIdents": true,
47514817
- "function": true,
47524818
- "grid": true,
4753-
- },
4819+
@@ ... @@
47544820
- "css/global": Object {
47554821
- "animation": true,
47564822
- "container": true,
47574823
- "customIdents": true,
47584824
- "dashedIdents": true,
47594825
- "function": true,
47604826
- "grid": true,
4761-
- },
4827+
@@ ... @@
47624828
- "css/module": Object {
47634829
- "animation": true,
47644830
- "container": true,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import raw from "../query-suffixes/raw.txt?raw";
2+
import fs from "fs";
3+
import path from "path";
4+
5+
it("should let a user ?raw rule override the futureDefaults default", () => {
6+
// The default maps ?raw to asset/source (a string); the user rule here
7+
// remaps it to asset/resource, so we get an emitted URL instead.
8+
expect(raw.startsWith("data:")).toBe(false);
9+
expect(raw).not.toBe("hello from raw.txt\n");
10+
const file = raw.split("?")[0];
11+
expect(fs.existsSync(path.join(__STATS__.outputPath, file))).toBe(true);
12+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"use strict";
2+
3+
/** @type {import("../../../../").Configuration} */
4+
module.exports = {
5+
mode: "development",
6+
experiments: {
7+
futureDefaults: true
8+
},
9+
module: {
10+
rules: [
11+
// A user rule for `?raw` must win over the futureDefaults default,
12+
// which would otherwise map it to `asset/source`.
13+
{
14+
resourceQuery: /(\?|&)raw(&|$)/,
15+
type: "asset/resource"
16+
}
17+
]
18+
}
19+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import raw from "./raw.txt?raw";
2+
// `file.png` is 14910 bytes (over the 8096 inline threshold).
3+
import pngUrl from "../_images/file.png?url";
4+
import pngInline from "../_images/file.png?inline";
5+
// `file.svg` is 656 bytes (under the threshold, so auto-inlined by default).
6+
import svgNoInline from "../_images/file.svg?no-inline";
7+
import fs from "fs";
8+
import path from "path";
9+
10+
it("should map ?raw to asset/source", () => {
11+
expect(raw).toBe("hello from raw.txt\n");
12+
});
13+
14+
it("should map ?url to an emitted asset/resource", () => {
15+
expect(pngUrl.startsWith("data:")).toBe(false);
16+
// The emitted filename keeps the query, so drop it to find the file.
17+
const file = pngUrl.split("?")[0];
18+
expect(fs.existsSync(path.join(__STATS__.outputPath, file))).toBe(true);
19+
});
20+
21+
it("should map ?inline to a data URI even above the inline threshold", () => {
22+
expect(pngInline.startsWith("data:image/png")).toBe(true);
23+
});
24+
25+
it("should map ?no-inline to an emitted file even below the threshold", () => {
26+
expect(svgNoInline.startsWith("data:")).toBe(false);
27+
const file = svgNoInline.split("?")[0];
28+
expect(fs.existsSync(path.join(__STATS__.outputPath, file))).toBe(true);
29+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hello from raw.txt

0 commit comments

Comments
 (0)