fix: no extra runtime for external asset modules in CSS

This commit is contained in:
Alexander Akait 2024-10-23 22:03:15 +03:00 committed by GitHub
commit abe931a19b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 156 additions and 14 deletions

View File

@ -55,8 +55,9 @@ const { register } = require("./util/serialization");
/** @typedef {{ attributes?: ImportAttributes, externalType: "import" | "module" | undefined }} ImportDependencyMeta */
/** @typedef {{ layer?: string, supports?: string, media?: string }} CssImportDependencyMeta */
/** @typedef {{ sourceType: "css-url" }} AssetDependencyMeta */
/** @typedef {ImportDependencyMeta | CssImportDependencyMeta} DependencyMeta */
/** @typedef {ImportDependencyMeta | CssImportDependencyMeta | AssetDependencyMeta} DependencyMeta */
/**
* @typedef {object} SourceData
@ -69,6 +70,7 @@ const { register } = require("./util/serialization");
const TYPES = new Set(["javascript"]);
const CSS_TYPES = new Set(["css-import"]);
const CSS_URL_TYPES = new Set(["css-url"]);
const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]);
const RUNTIME_REQUIREMENTS_FOR_SCRIPT = new Set([RuntimeGlobals.loadScript]);
const RUNTIME_REQUIREMENTS_FOR_MODULE = new Set([
@ -500,7 +502,18 @@ class ExternalModule extends Module {
* @returns {SourceTypes} types available (do not mutate)
*/
getSourceTypes() {
return this.externalType === "css-import" ? CSS_TYPES : TYPES;
if (
this.externalType === "asset" &&
this.dependencyMeta &&
/** @type {AssetDependencyMeta} */
(this.dependencyMeta).sourceType === "css-url"
) {
return CSS_URL_TYPES;
} else if (this.externalType === "css-import") {
return CSS_TYPES;
}
return TYPES;
}
/**
@ -674,12 +687,24 @@ class ExternalModule extends Module {
if (externalType === "module-import") {
if (
this.dependencyMeta &&
/** @type {ImportDependencyMeta} */ (this.dependencyMeta).externalType
/** @type {ImportDependencyMeta} */
(this.dependencyMeta).externalType
) {
return /** @type {ImportDependencyMeta} */ (this.dependencyMeta)
.externalType;
}
return "module";
} else if (externalType === "asset") {
if (
this.dependencyMeta &&
/** @type {AssetDependencyMeta} */
(this.dependencyMeta).sourceType
) {
return /** @type {AssetDependencyMeta} */ (this.dependencyMeta)
.sourceType;
}
return "asset";
}
return externalType;
@ -816,10 +841,13 @@ class ExternalModule extends Module {
new RawSource(`module.exports = ${JSON.stringify(request)};`)
);
const data = new Map();
data.set("url", {
javascript: request,
"css-url": request
});
data.set("url", { javascript: request });
return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data };
}
case "css-url": {
const sources = new Map();
const data = new Map();
data.set("url", { "css-url": request });
return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data };
}
case "css-import": {

View File

@ -9,6 +9,7 @@ const util = require("util");
const ExternalModule = require("./ExternalModule");
const ContextElementDependency = require("./dependencies/ContextElementDependency");
const CssImportDependency = require("./dependencies/CssImportDependency");
const CssUrlDependency = require("./dependencies/CssUrlDependency");
const HarmonyImportDependency = require("./dependencies/HarmonyImportDependency");
const ImportDependency = require("./dependencies/ImportDependency");
const { resolveByProperty, cachedSetProperty } = require("./util/cleverMerge");
@ -117,6 +118,8 @@ class ExternalModuleFactoryPlugin {
}
}
const resolvedType = /** @type {string} */ (type || globalType);
// TODO make it pluggable/add hooks to `ExternalModule` to allow output modules own externals?
/** @type {DependencyMeta | undefined} */
let dependencyMeta;
@ -145,12 +148,18 @@ class ExternalModuleFactoryPlugin {
};
}
if (
resolvedType === "asset" &&
dependency instanceof CssUrlDependency
) {
dependencyMeta = { sourceType: "css-url" };
}
callback(
null,
new ExternalModule(
externalConfig,
/** @type {string} */
(type || globalType),
resolvedType,
dependency.request,
dependencyMeta
)

View File

@ -4921,7 +4921,7 @@ Array [
background:
url(img.png),
url(img.png),
url(data:image/png;base64,AAA);
url(d4da020aedcd249a7a41.png);
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=),
url(resource.png),
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=),
@ -4929,6 +4929,22 @@ Array [
url(https://example.com/img.png);
}
.class-2 {
background: url(shared.png);
}
.class-3 {
background: url(shared-external.png);
}
.class-4 {
background: url(cde81354a9a8ce8d5f51.gif);
}
.class-5 {
background: url(5649e83cc54c4b57bc28.png);
}
head{--webpack-main:&\\\\.\\\\/style\\\\.css;}",
]
`;

View File

@ -4921,7 +4921,7 @@ Array [
background:
url(img.png),
url(img.png),
url(data:image/png;base64,AAA);
url(d4da020aedcd249a7a41.png);
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=),
url(resource.png),
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=),
@ -4929,6 +4929,22 @@ Array [
url(https://example.com/img.png);
}
.class-2 {
background: url(shared.png);
}
.class-3 {
background: url(shared-external.png);
}
.class-4 {
background: url(cde81354a9a8ce8d5f51.gif);
}
.class-5 {
background: url(5649e83cc54c4b57bc28.png);
}
head{--webpack-main:&\\\\.\\\\/style\\\\.css;}",
]
`;

View File

@ -10,5 +10,38 @@ it("should compile", () => {
}
expect(css).toMatchSnapshot();
expect(Object.keys(__webpack_modules__).length).toBe(3)
expect(Object.keys(__webpack_modules__).length).toBe(7);
expect(__webpack_modules__['./index.js']).toBeDefined();
expect(__webpack_modules__['./shared-external.png']).toBeDefined();
expect(__webpack_modules__['./shared.png']).toBeDefined();
expect(__webpack_modules__['data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAABNJREFUCB1jZGBg+A/EDEwgAgQADigBA//q6GsAAAAASUVORK5CYII%3D']).toBeDefined();
expect(__webpack_modules__['data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MDAgNjAwIj48dGl0bGU+aWNvbi1zcXVhcmUtc21hbGw8L3RpdGxlPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0zMDAgLjFMNTY1IDE1MHYyOTkuOUwzMDAgNTk5LjggMzUgNDQ5LjlWMTUweiIvPjxwYXRoIGZpbGw9IiM4RUQ2RkIiIGQ9Ik01MTcuNyA0MzkuNUwzMDguOCA1NTcuOHYtOTJMNDM5IDM5NC4xbDc4LjcgNDUuNHptMTQuMy0xMi45VjE3OS40bC03Ni40IDQ0LjF2MTU5bDc2LjQgNDQuMXpNODEuNSA0MzkuNWwyMDguOSAxMTguMnYtOTJsLTEzMC4yLTcxLjYtNzguNyA0NS40em0tMTQuMy0xMi45VjE3OS40bDc2LjQgNDQuMXYxNTlsLTc2LjQgNDQuMXptOC45LTI2My4yTDI5MC40IDQyLjJ2ODlsLTEzNy4zIDc1LjUtMS4xLjYtNzUuOS00My45em00NDYuOSAwTDMwOC44IDQyLjJ2ODlMNDQ2IDIwNi44bDEuMS42IDc1LjktNDR6Ii8+PHBhdGggZmlsbD0iIzFDNzhDMCIgZD0iTTI5MC40IDQ0NC44TDE2MiAzNzQuMVYyMzQuMmwxMjguNCA3NC4xdjEzNi41em0xOC40IDBsMTI4LjQtNzAuNnYtMTQwbC0xMjguNCA3NC4xdjEzNi41ek0yOTkuNiAzMDN6bS0xMjktODVsMTI5LTcwLjlMNDI4LjUgMjE4bC0xMjguOSA3NC40LTEyOS03NC40eiIvPjwvc3ZnPgo=']).toBeDefined();
expect(__webpack_modules__['https://example.com/only-external.png']).toBeDefined();
expect(__webpack_modules__['./style.css']).toBeDefined();
});
it("should work with shared asset module", () => {
const img = new URL("./shared.png", import.meta.url);
expect(img.href.endsWith("shared.png")).toBe(true);
});
it("should work with shared external asset module", () => {
const img = new URL("./shared-external.png", import.meta.url);
expect(img.href.endsWith("shared-external.png")).toBe(true);
});
it("should work with external asset module", () => {
const img = new URL("https://example.com/only-external.png", import.meta.url);
expect(img.href.endsWith("only-external.png")).toBe(true);
});
it("should work and extract DataURI", () => {
const img = new URL("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MDAgNjAwIj48dGl0bGU+aWNvbi1zcXVhcmUtc21hbGw8L3RpdGxlPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0zMDAgLjFMNTY1IDE1MHYyOTkuOUwzMDAgNTk5LjggMzUgNDQ5LjlWMTUweiIvPjxwYXRoIGZpbGw9IiM4RUQ2RkIiIGQ9Ik01MTcuNyA0MzkuNUwzMDguOCA1NTcuOHYtOTJMNDM5IDM5NC4xbDc4LjcgNDUuNHptMTQuMy0xMi45VjE3OS40bC03Ni40IDQ0LjF2MTU5bDc2LjQgNDQuMXpNODEuNSA0MzkuNWwyMDguOSAxMTguMnYtOTJsLTEzMC4yLTcxLjYtNzguNyA0NS40em0tMTQuMy0xMi45VjE3OS40bDc2LjQgNDQuMXYxNTlsLTc2LjQgNDQuMXptOC45LTI2My4yTDI5MC40IDQyLjJ2ODlsLTEzNy4zIDc1LjUtMS4xLjYtNzUuOS00My45em00NDYuOSAwTDMwOC44IDQyLjJ2ODlMNDQ2IDIwNi44bDEuMS42IDc1LjktNDR6Ii8+PHBhdGggZmlsbD0iIzFDNzhDMCIgZD0iTTI5MC40IDQ0NC44TDE2MiAzNzQuMVYyMzQuMmwxMjguNCA3NC4xdjEzNi41em0xOC40IDBsMTI4LjQtNzAuNnYtMTQwbC0xMjguNCA3NC4xdjEzNi41ek0yOTkuNiAzMDN6bS0xMjktODVsMTI5LTcwLjlMNDI4LjUgMjE4bC0xMjguOSA3NC40LTEyOS03NC40eiIvPjwvc3ZnPgo=", import.meta.url);
expect(img.href.endsWith(".svg")).toBe(true);
});
it("should work and extract shared DataURI", () => {
const img = new URL("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAABNJREFUCB1jZGBg+A/EDEwgAgQADigBA//q6GsAAAAASUVORK5CYII%3D", import.meta.url);
expect(img.href.endsWith(".png")).toBe(true);
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -10,3 +10,19 @@
url('data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'),
url('https://example.com/img.png');
}
.class-2 {
background: url("./shared.png");
}
.class-3 {
background: url("./shared-external.png");
}
.class-4 {
background: url("data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=");
}
.class-5 {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAABNJREFUCB1jZGBg+A/EDEwgAgQADigBA//q6GsAAAAASUVORK5CYII%3D");
}

View File

@ -23,10 +23,25 @@ module.exports = {
{
mimetype: "text/html",
type: "asset/resource"
},
{
mimetype: "image/svg",
type: "asset/resource"
},
{
mimetype: "image/gif",
type: "asset/resource"
},
{
mimetype: "image/png",
type: "asset/resource"
}
]
},
output: {
assetModuleFilename: "[name][ext]"
},
externals: {
"shared-external.png": "asset shared-external.png"
}
};

13
types.d.ts vendored
View File

@ -275,6 +275,9 @@ declare interface Asset {
*/
info: AssetInfo;
}
declare interface AssetDependencyMeta {
sourceType: "css-url";
}
declare interface AssetEmittedInfo {
content: Buffer;
source: Source;
@ -4588,12 +4591,18 @@ declare class ExternalModule extends Module {
request: string | string[] | RequestRecord,
type: string,
userRequest: string,
dependencyMeta?: ImportDependencyMeta | CssImportDependencyMeta
dependencyMeta?:
| ImportDependencyMeta
| CssImportDependencyMeta
| AssetDependencyMeta
);
request: string | string[] | Record<string, string | string[]>;
externalType: string;
userRequest: string;
dependencyMeta?: ImportDependencyMeta | CssImportDependencyMeta;
dependencyMeta?:
| ImportDependencyMeta
| CssImportDependencyMeta
| AssetDependencyMeta;
/**
* restore unsafe cache data