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,7 +110,68 @@ class WebpackOptionsApply extends OptionsApply { | |||
| 			const NodeTargetPlugin = require("./node/NodeTargetPlugin"); | ||||
| 
 | ||||
| 			new NodeTargetPlugin().apply(compiler); | ||||
| 
 | ||||
| 			// Handle external CSS `@import` and `url()`
 | ||||
| 			if (options.experiments.css) { | ||||
| 				// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
 | ||||
| 				const ExternalsPlugin = require("./ExternalsPlugin"); | ||||
| 
 | ||||
| 				new ExternalsPlugin( | ||||
| 					"module", | ||||
| 					({ request, dependencyType, contextInfo }, callback) => { | ||||
| 						if ( | ||||
| 							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}`); | ||||
| 							} | ||||
| 						} | ||||
| 
 | ||||
| 						callback(); | ||||
| 					} | ||||
| 				).apply(compiler); | ||||
| 			} | ||||
| 		} | ||||
| 		if (options.externalsPresets.webAsync || options.externalsPresets.web) { | ||||
| 			const type = options.externalsPresets.webAsync ? "import" : "module"; | ||||
| 
 | ||||
| 			// @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"); | ||||
|  | @ -130,7 +191,6 @@ class WebpackOptionsApply extends OptionsApply { | |||
| 				new ElectronTargetPlugin("renderer").apply(compiler); | ||||
| 			} | ||||
| 			if ( | ||||
| 			options.externalsPresets.electron && | ||||
| 				!options.externalsPresets.electronMain && | ||||
| 				!options.externalsPresets.electronPreload && | ||||
| 				!options.externalsPresets.electronRenderer | ||||
|  | @ -140,86 +200,13 @@ class WebpackOptionsApply extends OptionsApply { | |||
| 
 | ||||
| 				new ElectronTargetPlugin().apply(compiler); | ||||
| 			} | ||||
| 		} | ||||
| 		if (options.externalsPresets.nwjs) { | ||||
| 			// @ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
 | ||||
| 			const ExternalsPlugin = require("./ExternalsPlugin"); | ||||
| 
 | ||||
| 			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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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("../external/style.css").then(x => { | ||||
| 		expect(x).toEqual({}); | ||||
| import * as style from "./style.module.css"; | ||||
| import * as style1 from "https://test.cases/external.css"; | ||||
| 
 | ||||
| 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); | ||||
| }); | ||||
|  |  | |||
|  | @ -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"); | ||||
| 
 | ||||
| /** @type {import("../../../../").Configuration} */ | ||||
| module.exports = { | ||||
| module.exports = [ | ||||
| 	{ | ||||
| 		context: path.join(__dirname, "../external"), | ||||
| 		entry: "../external-in-node/index.js", | ||||
| 		target: "node", | ||||
| 		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 "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