diff --git a/lib/config/defaults.js b/lib/config/defaults.js index f264730144a..ae92bdfb0fe 100644 --- a/lib/config/defaults.js +++ b/lib/config/defaults.js @@ -1084,7 +1084,7 @@ const applyOutputDefaults = ( D(output, "assetModuleFilename", "[hash][ext][query]"); D(output, "webassemblyModuleFilename", "[hash].module.wasm"); D(output, "compareBeforeEmit", true); - D(output, "charset", true); + D(output, "charset", !futureDefaults); const uniqueNameId = Template.toIdentifier( /** @type {NonNullable} */ (output.uniqueName) ); diff --git a/lib/css/CssLoadingRuntimeModule.js b/lib/css/CssLoadingRuntimeModule.js index a06d329d189..1c46eebe552 100644 --- a/lib/css/CssLoadingRuntimeModule.js +++ b/lib/css/CssLoadingRuntimeModule.js @@ -74,7 +74,8 @@ class CssLoadingRuntimeModule extends RuntimeModule { outputOptions: { crossOriginLoading, uniqueName, - chunkLoadTimeout: loadTimeout + chunkLoadTimeout: loadTimeout, + charset } } = compilation; const fn = RuntimeGlobals.ensureChunkHandlers; @@ -138,6 +139,7 @@ class CssLoadingRuntimeModule extends RuntimeModule { const code = Template.asString([ "link = document.createElement('link');", + charset ? "link.charset = 'utf-8';" : "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent( `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});` @@ -351,6 +353,7 @@ class CssLoadingRuntimeModule extends RuntimeModule { linkPrefetch.call( Template.asString([ "var link = document.createElement('link');", + charset ? "link.charset = 'utf-8';" : "", crossOriginLoading ? `link.crossOrigin = ${JSON.stringify( crossOriginLoading @@ -390,7 +393,7 @@ class CssLoadingRuntimeModule extends RuntimeModule { linkPreload.call( Template.asString([ "var link = document.createElement('link');", - "link.charset = 'utf-8';", + charset ? "link.charset = 'utf-8';" : "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent( `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});` diff --git a/lib/esm/ModuleChunkLoadingRuntimeModule.js b/lib/esm/ModuleChunkLoadingRuntimeModule.js index 69dd231f97f..1d35178ecfd 100644 --- a/lib/esm/ModuleChunkLoadingRuntimeModule.js +++ b/lib/esm/ModuleChunkLoadingRuntimeModule.js @@ -93,7 +93,7 @@ class ModuleChunkLoadingRuntimeModule extends RuntimeModule { (compilation.outputOptions.environment); const { runtimeTemplate, - outputOptions: { importFunctionName, crossOriginLoading } + outputOptions: { importFunctionName, crossOriginLoading, charset } } = compilation; const fn = RuntimeGlobals.ensureChunkHandlers; const withBaseURI = this._runtimeRequirements.has(RuntimeGlobals.baseURI); @@ -261,6 +261,7 @@ class ModuleChunkLoadingRuntimeModule extends RuntimeModule { linkPrefetch.call( Template.asString([ "var link = document.createElement('link');", + charset ? "link.charset = 'utf-8';" : "", crossOriginLoading ? `link.crossOrigin = ${JSON.stringify( crossOriginLoading @@ -300,7 +301,7 @@ class ModuleChunkLoadingRuntimeModule extends RuntimeModule { linkPreload.call( Template.asString([ "var link = document.createElement('link');", - "link.charset = 'utf-8';", + charset ? "link.charset = 'utf-8';" : "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent( `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});` diff --git a/lib/web/JsonpChunkLoadingRuntimeModule.js b/lib/web/JsonpChunkLoadingRuntimeModule.js index efc4ac0e463..0b9cebd8407 100644 --- a/lib/web/JsonpChunkLoadingRuntimeModule.js +++ b/lib/web/JsonpChunkLoadingRuntimeModule.js @@ -80,7 +80,8 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule { chunkLoadingGlobal, hotUpdateGlobal, crossOriginLoading, - scriptType + scriptType, + charset } } = compilation; const globalObject = runtimeTemplate.globalObject; @@ -229,6 +230,7 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule { linkPrefetch.call( Template.asString([ "var link = document.createElement('link');", + charset ? "link.charset = 'utf-8';" : "", crossOriginLoading ? `link.crossOrigin = ${JSON.stringify( crossOriginLoading @@ -268,7 +270,7 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule { scriptType && scriptType !== "module" ? `link.type = ${JSON.stringify(scriptType)};` : "", - "link.charset = 'utf-8';", + charset ? "link.charset = 'utf-8';" : "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent( `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});` diff --git a/test/Defaults.unittest.js b/test/Defaults.unittest.js index c151f6da6fd..255e80da3e5 100644 --- a/test/Defaults.unittest.js +++ b/test/Defaults.unittest.js @@ -2331,8 +2331,9 @@ describe("snapshots", () => { + "resolve": Object { + "fullySpecified": true, + "preferRelative": true, - + }, + @@ ... @@ + "type": "css", + + }, @@ ... @@ - "generator": Object {}, + "generator": Object { @@ -2354,11 +2355,12 @@ describe("snapshots", () => { + }, + }, @@ ... @@ + + }, + @@ ... @@ + "css": Object { + "import": true, + "namedExports": true, + "url": true, - + }, @@ ... @@ + "exportsPresence": "error", @@ ... @@ @@ -2371,6 +2373,9 @@ describe("snapshots", () => { @@ ... @@ + "css", @@ ... @@ + - "charset": true, + + "charset": false, + @@ ... @@ - "hashDigestLength": 20, - "hashFunction": "md4", + "hashDigestLength": 16, @@ -2425,9 +2430,10 @@ describe("snapshots", () => { + "css": false, + "futureDefaults": true, @@ ... @@ + + }, + Object { + "rules": Array [ - @@ ... @@ + + Object { + "descriptionData": Object { + "type": "module", + }, @@ -2438,8 +2444,7 @@ describe("snapshots", () => { + ], + "test": /\\.wasm$/i, + "type": "webassembly/async", - + }, - + Object { + @@ ... @@ + "mimetype": "application/wasm", + "rules": Array [ + Object { @@ -2464,6 +2469,9 @@ describe("snapshots", () => { + "__filename": "warn-mock", + "global": "warn", @@ ... @@ + - "charset": true, + + "charset": false, + @@ ... @@ - "hashDigestLength": 20, - "hashFunction": "md4", + "hashDigestLength": 16, diff --git a/test/configCases/output/charset/chunk1.css b/test/configCases/output/charset/chunk1.css new file mode 100644 index 00000000000..195b6bcf6d2 --- /dev/null +++ b/test/configCases/output/charset/chunk1.css @@ -0,0 +1,3 @@ +a { + color: red; +} diff --git a/test/configCases/output/charset/index.js b/test/configCases/output/charset/index.js index 6d724414b85..4f383a623ff 100644 --- a/test/configCases/output/charset/index.js +++ b/test/configCases/output/charset/index.js @@ -1,16 +1,27 @@ -__webpack_public_path__ = "https://example.com/public/path/"; -const doImport = () => import(/* webpackChunkName: "chunk1" */ "./chunk1"); -it("should not add charset attribute", () => { - const promise = doImport(); - expect(document.head._children).toHaveLength(1); +__webpack_public_path__ = "https://test.cases/path/"; - const script = document.head._children[0]; +const doJsImport = () => import(/* webpackChunkName: "chunk1" */ "./chunk1.js"); +const doCssImport = () => import( /* webpackChunkName: "chunk1" */ "./chunk1.css" ); + +it("should not add charset attribute", async () => { + const promise = doJsImport(); + expect(document.head._children).toHaveLength(3); + + const link = document.head._children[0]; + + expect(link._type).toBe("link"); + expect(link.href).toBe("https://test.cases/path/chunk1.css"); + expect(link.rel).toBe("stylesheet"); + expect(link.getAttribute("charset")).toBeUndefined(); + + const script = document.head._children[document.head._children.length - 1]; __non_webpack_require__("./chunk1.js"); script.onload(); expect(script._type).toBe("script"); - expect(script.src).toBe("https://example.com/public/path/chunk1.js"); + expect(script.src).toBe("https://test.cases/path/chunk1.js"); expect(script.getAttribute("charset")).toBeUndefined(); - return promise; + + return promise.then(() => doCssImport); }); diff --git a/test/configCases/output/charset/test.config.js b/test/configCases/output/charset/test.config.js new file mode 100644 index 00000000000..ea656968b0e --- /dev/null +++ b/test/configCases/output/charset/test.config.js @@ -0,0 +1,8 @@ +module.exports = { + moduleScope(scope, options) { + const link = scope.window.document.createElement("link"); + link.rel = "stylesheet"; + link.href = "chunk1.css"; + scope.window.document.head.appendChild(link); + } +}; diff --git a/test/configCases/output/charset/webpack.config.js b/test/configCases/output/charset/webpack.config.js index 578069cd09a..15df7b6faf5 100644 --- a/test/configCases/output/charset/webpack.config.js +++ b/test/configCases/output/charset/webpack.config.js @@ -8,6 +8,9 @@ module.exports = { performance: { hints: false }, + experiments: { + css: true + }, optimization: { chunkIds: "named", minimize: false diff --git a/test/configCases/web/prefetch-preload-module/index.mjs b/test/configCases/web/prefetch-preload-module/index.mjs index 459d566229e..7b92f910731 100644 --- a/test/configCases/web/prefetch-preload-module/index.mjs +++ b/test/configCases/web/prefetch-preload-module/index.mjs @@ -13,12 +13,14 @@ it("should prefetch and preload child chunks on chunk load", () => { expect(link.rel).toBe("prefetch"); expect(link.as).toBe("script"); expect(link.href).toBe("https://example.com/public/path/chunk1.mjs"); + expect(link.charset).toBe("utf-8"); link = document.head._children[1]; expect(link._type).toBe("link"); expect(link.rel).toBe("prefetch"); expect(link.as).toBe("style"); expect(link.href).toBe("https://example.com/public/path/chunk2-css.css"); + expect(link.charset).toBe("utf-8"); link = document.head._children[2]; expect(link._type).toBe("link"); @@ -38,6 +40,7 @@ it("should prefetch and preload child chunks on chunk load", () => { expect(link.rel).toBe("preload"); expect(link.as).toBe("style"); expect(link.href).toBe("https://example.com/public/path/chunk1-a-css.css"); + expect(link.charset).toBe("utf-8"); expect(link.getAttribute("nonce")).toBe("nonce"); expect(link.crossOrigin).toBe("anonymous"); diff --git a/test/configCases/web/prefetch-preload/index.js b/test/configCases/web/prefetch-preload/index.js index a1a04163b7f..f35faee42f9 100644 --- a/test/configCases/web/prefetch-preload/index.js +++ b/test/configCases/web/prefetch-preload/index.js @@ -12,6 +12,7 @@ it("should prefetch and preload child chunks on chunk load", () => { expect(link._type).toBe("link"); expect(link.rel).toBe("prefetch"); expect(link.as).toBe("script"); + expect(link.charset).toBe("utf-8"); expect(link.href).toBe("https://example.com/public/path/chunk1.js"); link = document.head._children[1]; @@ -80,6 +81,7 @@ it("should prefetch and preload child chunks on chunk load", () => { expect(link.rel).toBe("prefetch"); expect(link.as).toBe("script"); expect(link.href).toBe("https://example.com/public/path/chunk1-c.js"); + expect(link.charset).toBe("utf-8"); expect(link.crossOrigin).toBe("anonymous"); link = document.head._children[7];