mirror of https://github.com/webpack/webpack.git
fix: property handle external modules for CSS (#19917)
This commit is contained in:
parent
3ac31e24e3
commit
8e94386ee4
|
|
@ -110,35 +110,96 @@ class WebpackOptionsApply extends OptionsApply {
|
||||||
const NodeTargetPlugin = require("./node/NodeTargetPlugin");
|
const NodeTargetPlugin = require("./node/NodeTargetPlugin");
|
||||||
|
|
||||||
new NodeTargetPlugin().apply(compiler);
|
new NodeTargetPlugin().apply(compiler);
|
||||||
}
|
|
||||||
if (options.externalsPresets.electronMain) {
|
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
|
||||||
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
|
||||||
|
|
||||||
new ElectronTargetPlugin("main").apply(compiler);
|
// Handle external CSS `@import` and `url()`
|
||||||
}
|
if (options.experiments.css) {
|
||||||
if (options.externalsPresets.electronPreload) {
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
const ExternalsPlugin = require("./ExternalsPlugin");
|
||||||
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
|
||||||
|
|
||||||
new ElectronTargetPlugin("preload").apply(compiler);
|
new ExternalsPlugin(
|
||||||
}
|
"module",
|
||||||
if (options.externalsPresets.electronRenderer) {
|
({ request, dependencyType, contextInfo }, callback) => {
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
if (
|
||||||
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
contextInfo &&
|
||||||
|
/\.css(\?|$)/.test(contextInfo.issuer) &&
|
||||||
|
/^(\/\/|https?:\/\/|#)/.test(/** @type {string} */ (request))
|
||||||
|
) {
|
||||||
|
if (dependencyType === "url") {
|
||||||
|
return callback(null, `asset ${request}`);
|
||||||
|
} else if (
|
||||||
|
dependencyType === "css-import" &&
|
||||||
|
options.experiments.css
|
||||||
|
) {
|
||||||
|
return callback(null, `css-import ${request}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
new ElectronTargetPlugin("renderer").apply(compiler);
|
callback();
|
||||||
|
}
|
||||||
|
).apply(compiler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (options.externalsPresets.webAsync || options.externalsPresets.web) {
|
||||||
options.externalsPresets.electron &&
|
const type = options.externalsPresets.webAsync ? "import" : "module";
|
||||||
!options.externalsPresets.electronMain &&
|
|
||||||
!options.externalsPresets.electronPreload &&
|
|
||||||
!options.externalsPresets.electronRenderer
|
|
||||||
) {
|
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
|
||||||
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
|
||||||
|
|
||||||
new ElectronTargetPlugin().apply(compiler);
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
||||||
|
const ExternalsPlugin = require("./ExternalsPlugin");
|
||||||
|
|
||||||
|
new ExternalsPlugin(type, ({ request, dependencyType }, callback) => {
|
||||||
|
if (
|
||||||
|
/^(\/\/|https?:\/\/|#|std:|jsr:|npm:)/.test(
|
||||||
|
/** @type {string} */ (request)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (dependencyType === "url") {
|
||||||
|
return callback(null, `asset ${request}`);
|
||||||
|
} else if (
|
||||||
|
dependencyType === "css-import" &&
|
||||||
|
options.experiments.css
|
||||||
|
) {
|
||||||
|
return callback(null, `css-import ${request}`);
|
||||||
|
} else if (
|
||||||
|
/^(\/\/|https?:\/\/|std:|jsr:|npm:)/.test(
|
||||||
|
/** @type {string} */
|
||||||
|
(request)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return callback(null, `${type} ${request}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}).apply(compiler);
|
||||||
|
}
|
||||||
|
if (options.externalsPresets.electron) {
|
||||||
|
if (options.externalsPresets.electronMain) {
|
||||||
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
||||||
|
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
||||||
|
|
||||||
|
new ElectronTargetPlugin("main").apply(compiler);
|
||||||
|
}
|
||||||
|
if (options.externalsPresets.electronPreload) {
|
||||||
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
||||||
|
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
||||||
|
|
||||||
|
new ElectronTargetPlugin("preload").apply(compiler);
|
||||||
|
}
|
||||||
|
if (options.externalsPresets.electronRenderer) {
|
||||||
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
||||||
|
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
||||||
|
|
||||||
|
new ElectronTargetPlugin("renderer").apply(compiler);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!options.externalsPresets.electronMain &&
|
||||||
|
!options.externalsPresets.electronPreload &&
|
||||||
|
!options.externalsPresets.electronRenderer
|
||||||
|
) {
|
||||||
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
||||||
|
const ElectronTargetPlugin = require("./electron/ElectronTargetPlugin");
|
||||||
|
|
||||||
|
new ElectronTargetPlugin().apply(compiler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (options.externalsPresets.nwjs) {
|
if (options.externalsPresets.nwjs) {
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
||||||
|
|
@ -146,80 +207,6 @@ class WebpackOptionsApply extends OptionsApply {
|
||||||
|
|
||||||
new ExternalsPlugin("node-commonjs", "nw.gui").apply(compiler);
|
new ExternalsPlugin("node-commonjs", "nw.gui").apply(compiler);
|
||||||
}
|
}
|
||||||
if (options.externalsPresets.webAsync) {
|
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
|
||||||
const ExternalsPlugin = require("./ExternalsPlugin");
|
|
||||||
|
|
||||||
new ExternalsPlugin("import", ({ request, dependencyType }, callback) => {
|
|
||||||
if (dependencyType === "url") {
|
|
||||||
if (/^(\/\/|https?:\/\/|#)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `asset ${request}`);
|
|
||||||
}
|
|
||||||
} else if (options.experiments.css && dependencyType === "css-import") {
|
|
||||||
if (/^(\/\/|https?:\/\/|#)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `css-import ${request}`);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
options.experiments.css &&
|
|
||||||
/^(\/\/|https?:\/\/|std:)/.test(/** @type {string} */ (request))
|
|
||||||
) {
|
|
||||||
if (/^\.css(\?|$)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `css-import ${request}`);
|
|
||||||
}
|
|
||||||
return callback(null, `import ${request}`);
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
}).apply(compiler);
|
|
||||||
} else if (options.externalsPresets.web) {
|
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
|
||||||
const ExternalsPlugin = require("./ExternalsPlugin");
|
|
||||||
|
|
||||||
new ExternalsPlugin("module", ({ request, dependencyType }, callback) => {
|
|
||||||
if (dependencyType === "url") {
|
|
||||||
if (/^(\/\/|https?:\/\/|#)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `asset ${request}`);
|
|
||||||
}
|
|
||||||
} else if (options.experiments.css && dependencyType === "css-import") {
|
|
||||||
if (/^(\/\/|https?:\/\/|#)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `css-import ${request}`);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
/^(\/\/|https?:\/\/|std:)/.test(/** @type {string} */ (request))
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
options.experiments.css &&
|
|
||||||
/^\.css((\?)|$)/.test(/** @type {string} */ (request))
|
|
||||||
) {
|
|
||||||
return callback(null, `css-import ${request}`);
|
|
||||||
}
|
|
||||||
return callback(null, `module ${request}`);
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
}).apply(compiler);
|
|
||||||
} else if (options.externalsPresets.node && options.experiments.css) {
|
|
||||||
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
|
|
||||||
const ExternalsPlugin = require("./ExternalsPlugin");
|
|
||||||
|
|
||||||
new ExternalsPlugin("module", ({ request, dependencyType }, callback) => {
|
|
||||||
if (dependencyType === "url") {
|
|
||||||
if (/^(\/\/|https?:\/\/|#)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `asset ${request}`);
|
|
||||||
}
|
|
||||||
} else if (dependencyType === "css-import") {
|
|
||||||
if (/^(\/\/|https?:\/\/|#)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `css-import ${request}`);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
/^(\/\/|https?:\/\/|std:)/.test(/** @type {string} */ (request))
|
|
||||||
) {
|
|
||||||
if (/^\.css(\?|$)/.test(/** @type {string} */ (request))) {
|
|
||||||
return callback(null, `css-import ${request}`);
|
|
||||||
}
|
|
||||||
return callback(null, `module ${request}`);
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
}).apply(compiler);
|
|
||||||
}
|
|
||||||
|
|
||||||
new ChunkPrefetchPreloadPlugin().apply(compiler);
|
new ChunkPrefetchPreloadPlugin().apply(compiler);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import "style2.modules.css";
|
||||||
|
@import "https://test.cases/path/../../../../configCases/css/external-in-web/dynamic-external.css";
|
||||||
|
|
||||||
|
.other {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
[
|
||||||
|
/UnhandledSchemeError: Reading from "https:\/\/test\.cases\/url-external\.css"/
|
||||||
|
],
|
||||||
|
[/UnhandledSchemeError: Reading from "https:\/\/test\.cases\/external\.css"/],
|
||||||
|
[
|
||||||
|
/UnhandledSchemeError: Reading from "https:\/\/test\.cases\/url-external\.css"/
|
||||||
|
],
|
||||||
|
[/UnhandledSchemeError: Reading from "https:\/\/test\.cases\/external\.css"/]
|
||||||
|
];
|
||||||
|
|
@ -1,6 +1,27 @@
|
||||||
it("should import an external css", done => {
|
import * as style from "./style.module.css";
|
||||||
import("../external/style.css").then(x => {
|
import * as style1 from "https://test.cases/external.css";
|
||||||
expect(x).toEqual({});
|
|
||||||
|
it("should import an external CSS inside CSS", () => {
|
||||||
|
expect(style).toEqual(
|
||||||
|
nsObj({
|
||||||
|
class: "_external-in-node_style_module_css-class"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should work with an external URL", () => {
|
||||||
|
const url = new URL("https://test.cases/url-external.css", import.meta.url);
|
||||||
|
|
||||||
|
expect(url.toString().endsWith("url-external.css")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should import an external css dynamically", done => {
|
||||||
|
import("./dynamic.modules.css").then(x => {
|
||||||
|
expect(x).toEqual(
|
||||||
|
nsObj({
|
||||||
|
other: "_external-in-node_dynamic_modules_css-other"
|
||||||
|
})
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
}, done);
|
}, done);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = (options) => {
|
||||||
|
if (options[0].cache && options[0].cache.type === "filesystem") {
|
||||||
|
return [
|
||||||
|
/Pack got invalid because of write to/,
|
||||||
|
/Pack got invalid because of write to/
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import "https://test.cases/path/../../../../configCases/css/external-in-web/external.css";
|
||||||
|
|
||||||
|
.class {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
@ -3,11 +3,30 @@
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
/** @type {import("../../../../").Configuration} */
|
/** @type {import("../../../../").Configuration} */
|
||||||
module.exports = {
|
module.exports = [
|
||||||
context: path.join(__dirname, "../external"),
|
{
|
||||||
entry: "../external-in-node/index.js",
|
context: path.join(__dirname, "../external"),
|
||||||
target: "node",
|
entry: "../external-in-node/index.js",
|
||||||
experiments: {
|
target: "node",
|
||||||
css: true
|
optimization: {
|
||||||
|
chunkIds: "named",
|
||||||
|
moduleIds: "named"
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
css: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: path.join(__dirname, "../external"),
|
||||||
|
entry: "../external-in-node/index.js",
|
||||||
|
target: "node",
|
||||||
|
optimization: {
|
||||||
|
chunkIds: "named",
|
||||||
|
moduleIds: "named"
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
css: true,
|
||||||
|
outputModule: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
@import "style2.css";
|
@import "style2.css";
|
||||||
@import "https://test.cases/path/../../../../configCases/css/external/external.css";
|
@import "https://test.cases/path/../../../../configCases/css/external-in-web/dynamic-external.css";
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import * as style from "./style.css";
|
||||||
|
|
||||||
|
it("should import an external CSS inside CSS", () => {
|
||||||
|
const bodyStyle = getComputedStyle(document.body);
|
||||||
|
|
||||||
|
expect(bodyStyle.getPropertyValue("color")).toBe(" green");
|
||||||
|
expect(bodyStyle.getPropertyValue("padding")).toBe(" 10px");
|
||||||
|
});
|
||||||
|
|
||||||
|
// import * as style1 from "http://test.com/import.css";
|
||||||
|
|
||||||
|
it("should work with an external URL", () => {
|
||||||
|
const url = new URL("https://test.cases/url-external.css", import.meta.url);
|
||||||
|
|
||||||
|
expect(url.toString().endsWith("url-external.css")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should import an external css dynamically", done => {
|
||||||
|
import("./dynamic.css").then(x => {
|
||||||
|
expect(x).toEqual({});
|
||||||
|
const bodyStyle = getComputedStyle(document.body);
|
||||||
|
expect(bodyStyle.getPropertyValue("color")).toBe(" red");
|
||||||
|
expect(bodyStyle.getPropertyValue("background")).toBe(
|
||||||
|
" url(//example.com/image.png) url(https://example.com/image.png)"
|
||||||
|
);
|
||||||
|
expect(bodyStyle.getPropertyValue("background-image")).toBe(
|
||||||
|
" url(http://example.com/image.png)"
|
||||||
|
);
|
||||||
|
done();
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import "https://test.cases/path/../../../../configCases/css/external-in-web/external.css";
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
body {
|
||||||
|
background: url(//example.com/image.png) url(https://example.com/image.png);
|
||||||
|
background-image: url(http://example.com/image.png);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
moduleScope(scope, stats) {
|
||||||
|
const link = scope.window.document.createElement("link");
|
||||||
|
link.rel = "stylesheet";
|
||||||
|
link.href = stats.experiments.outputModule ? "bundle1.css" : "bundle0.css";
|
||||||
|
scope.window.document.head.appendChild(link);
|
||||||
|
},
|
||||||
|
findBundle(i) {
|
||||||
|
return i === 0 ? ["dynamic_css.bundle0.js", "bundle0.js"] : ["bundle1.mjs"];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
border: 10px red solid;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/** @type {import("../../../../").Configuration} */
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
target: "web",
|
||||||
|
optimization: {
|
||||||
|
chunkIds: "named"
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
css: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: "web",
|
||||||
|
optimization: {
|
||||||
|
chunkIds: "named"
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
css: true,
|
||||||
|
outputModule: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
it("should import an external css", done => {
|
|
||||||
import("./style.css").then(x => {
|
|
||||||
expect(x).toEqual({});
|
|
||||||
const style = getComputedStyle(document.body);
|
|
||||||
expect(style.getPropertyValue("color")).toBe(" green");
|
|
||||||
expect(style.getPropertyValue("background")).toBe(
|
|
||||||
" url(//example.com/image.png) url(https://example.com/image.png)"
|
|
||||||
);
|
|
||||||
expect(style.getPropertyValue("background-image")).toBe(
|
|
||||||
" url(http://example.com/image.png)"
|
|
||||||
);
|
|
||||||
done();
|
|
||||||
}, done);
|
|
||||||
});
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
findBundle() {
|
|
||||||
return ["125.bundle0.js", "bundle0.js"];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/** @type {import("../../../../").Configuration} */
|
|
||||||
module.exports = {
|
|
||||||
target: "web",
|
|
||||||
experiments: {
|
|
||||||
css: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Loading…
Reference in New Issue