From 8e93b75698e30d2f9d06dfda08cfb250ff02f1dd Mon Sep 17 00:00:00 2001 From: Anton Khlynovskiy Date: Wed, 26 Jan 2022 16:54:28 +0300 Subject: [PATCH 1/4] feat: do not hash localName if the localName is inlined: Adds a new setting .modules.hashStrategy, default is backward-compat --- README.md | 31 + src/options.json | 5 + src/utils.js | 21 +- .../__snapshots__/modules-option.test.js.snap | 760 ++++++++++++++++++ .../validate-options.test.js.snap | 30 +- test/modules-option.test.js | 80 ++ 6 files changed, 910 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0f19738f..c3ddb229 100644 --- a/README.md +++ b/README.md @@ -872,6 +872,37 @@ module.exports = { }; ``` +##### `hashStrategy` + +Type: `'use-local-name' | 'omit-local-name' | 'auto'` +Default: `'use-local-name'` + +Should local name be used when computing the hash. + +- `'auto'` Auto detect based on [localIdentName](#localidentname). Use this value to get the output that is better compressable by GZIP or Brotli. +- `'use-local-name'` Each identifier in a module gets its own hash digest. +- `'omit-local-name'` All identifiers from the same module shares the same hash digest. Handle with care! + +**webpack.config.js** + +```js +module.exports = { + module: { + rules: [ + { + test: /\.css$/i, + loader: "css-loader", + options: { + modules: { + hashStrategy: "auto", + }, + }, + }, + ], + }, +}; +``` + ##### `localIdentRegExp` Type: `String|RegExp` diff --git a/src/options.json b/src/options.json index c9b25a14..9f2db86d 100644 --- a/src/options.json +++ b/src/options.json @@ -114,6 +114,11 @@ "link": "https://github.com/webpack-contrib/css-loader#localidenthashdigestlength", "type": "number" }, + "hashStrategy": { + "description": "Allows to specify should localName be used when computing the hash.", + "link": "https://github.com/webpack-contrib/css-loader#hashstrategy", + "enum": ["use-local-name", "omit-local-name", "auto"] + }, "localIdentRegExp": { "description": "Allows to specify custom RegExp for local ident name.", "link": "https://github.com/webpack-contrib/css-loader#localidentregexp", diff --git a/src/utils.js b/src/utils.js index d7200431..a55c4b9a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -330,14 +330,28 @@ function defaultGetLocalIdent( localName, options ) { - const { context, hashSalt } = options; + const { context, hashSalt, hashStrategy } = options; const { resourcePath } = loaderContext; const relativeResourcePath = normalizePath( path.relative(context, resourcePath) ); + let useLocalNameInHash; + switch (hashStrategy) { + case "omit-local-name": + useLocalNameInHash = false; + break; + case "auto": + useLocalNameInHash = !/\[local\]/.test(localIdentName); + break; + default: + // undefined or "use-local-name" + useLocalNameInHash = true; + } // eslint-disable-next-line no-param-reassign - options.content = `${relativeResourcePath}\x00${localName}`; + options.content = useLocalNameInHash + ? `${relativeResourcePath}\x00${localName}` + : relativeResourcePath; let { hashFunction, hashDigest, hashDigestLength } = options; const matches = localIdentName.match( @@ -756,6 +770,7 @@ function getModulesPlugins(options, loaderContext) { localIdentHashDigest, localIdentHashDigestLength, localIdentRegExp, + hashStrategy, } = options.modules; let plugins = []; @@ -780,6 +795,7 @@ function getModulesPlugins(options, loaderContext) { hashFunction: localIdentHashFunction, hashDigest: localIdentHashDigest, hashDigestLength: localIdentHashDigestLength, + hashStrategy, regExp: localIdentRegExp, } ); @@ -798,6 +814,7 @@ function getModulesPlugins(options, loaderContext) { hashFunction: localIdentHashFunction, hashDigest: localIdentHashDigest, hashDigestLength: localIdentHashDigestLength, + hashStrategy, regExp: localIdentRegExp, } ); diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index 4757aaf9..23e56d05 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -3397,6 +3397,766 @@ Array [ exports[`"modules" option should work and respect the "hashSalt" option: warnings 1`] = `Array []`; +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: errors 1`] = `Array []`; + +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: module 1`] = ` +"// Imports +import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; +import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\".test__iHMJbI42 {\\\\n background: red;\\\\n}\\\\n\\\\n._test__iHMJbI42 {\\\\n background: blue;\\\\n}\\\\n\\\\n.className__iHMJbI42 {\\\\n background: red;\\\\n}\\\\n\\\\n#someId__iHMJbI42 {\\\\n background: green;\\\\n}\\\\n\\\\n.className__iHMJbI42 .subClass__iHMJbI42 {\\\\n color: green;\\\\n}\\\\n\\\\n#someId__iHMJbI42 .subClass__iHMJbI42 {\\\\n color: blue;\\\\n}\\\\n\\\\n.-a0-34a___f__iHMJbI42 {\\\\n color: red;\\\\n}\\\\n\\\\n.m_x_\\\\\\\\@__iHMJbI42 {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n.B\\\\\\\\&W\\\\\\\\?__iHMJbI42 {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\":\`(\\\\\\" */\\\\n.\\\\\\\\3A \\\\\\\\\`\\\\\\\\(__iHMJbI42 {\\\\n color: aqua;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\"1a2b3c\\\\\\" */\\\\n.\\\\\\\\31 a2b3c__iHMJbI42 {\\\\n color: aliceblue;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"#fake-id\\\\\\" */\\\\n#\\\\\\\\#fake-id__iHMJbI42 {\\\\n color: antiquewhite;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"-a-b-c-\\\\\\" */\\\\n#-a-b-c-__iHMJbI42 {\\\\n color: azure;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"©\\\\\\" */\\\\n#©__iHMJbI42 {\\\\n color: black;\\\\n}\\\\n\\\\n.♥__iHMJbI42 { background: lime; }\\\\n.©__iHMJbI42 { background: lime; }\\\\n.😍__iHMJbI42 { background: lime; }\\\\n.“‘’”__iHMJbI42 { background: lime; }\\\\n.☺☃__iHMJbI42 { background: lime; }\\\\n.⌘⌥__iHMJbI42 { background: lime; }\\\\n.𝄞♪♩♫♬__iHMJbI42 { background: lime; }\\\\n.💩__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\?__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\@__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\.__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\3A \\\\\\\\)__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\3A \\\\\\\\\`\\\\\\\\(__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\31 23__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\31 a2b3c__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\<\\\\\\\\>\\\\\\\\<\\\\\\\\<\\\\\\\\<\\\\\\\\>\\\\\\\\>\\\\\\\\<\\\\\\\\>__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\[\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\>\\\\\\\\+\\\\\\\\<\\\\\\\\<\\\\\\\\<\\\\\\\\<\\\\\\\\-\\\\\\\\]\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\+\\\\\\\\.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\<\\\\\\\\<\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\.\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\.\\\\\\\\>\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\.__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\#__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\#\\\\\\\\#__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\#\\\\\\\\.\\\\\\\\#\\\\\\\\.\\\\\\\\#__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\___iHMJbI42 { background: lime; }\\\\n.\\\\\\\\{\\\\\\\\}__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\#fake\\\\\\\\-id__iHMJbI42 { background: lime; }\\\\n.foo\\\\\\\\.bar__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\3A hover__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\3A hover\\\\\\\\3A focus\\\\\\\\3A active__iHMJbI42 { background: lime; }\\\\n.\\\\\\\\[attr\\\\\\\\=value\\\\\\\\]__iHMJbI42 { background: lime; }\\\\n.f\\\\\\\\/o\\\\\\\\/o__iHMJbI42 { background: lime; }\\\\n.f\\\\\\\\\\\\\\\\o\\\\\\\\\\\\\\\\o__iHMJbI42 { background: lime; }\\\\n.f\\\\\\\\*o\\\\\\\\*o__iHMJbI42 { background: lime; }\\\\n.f\\\\\\\\!o\\\\\\\\!o__iHMJbI42 { background: lime; }\\\\n.f\\\\\\\\'o\\\\\\\\'o__iHMJbI42 { background: lime; }\\\\n.f\\\\\\\\~o\\\\\\\\~o__iHMJbI42 { background: lime; }\\\\n.f\\\\\\\\+o\\\\\\\\+o__iHMJbI42 { background: lime; }\\\\n\\\\n.foo\\\\\\\\/bar__iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.foo\\\\\\\\\\\\\\\\bar__iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.foo\\\\\\\\/bar\\\\\\\\/baz__iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.foo\\\\\\\\\\\\\\\\bar\\\\\\\\\\\\\\\\baz__iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\", \\"\\"]); +// Exports +___CSS_LOADER_EXPORT___.locals = { + \\"123\\": \\"123__iHMJbI42\\", + \\"test\\": \\"test__iHMJbI42\\", + \\"_test\\": \\"_test__iHMJbI42\\", + \\"className\\": \\"className__iHMJbI42\\", + \\"someId\\": \\"someId__iHMJbI42\\", + \\"subClass\\": \\"subClass__iHMJbI42\\", + \\"-a0-34a___f\\": \\"-a0-34a___f__iHMJbI42\\", + \\"m_x_@\\": \\"m_x_@__iHMJbI42\\", + \\"B&W?\\": \\"B&W?__iHMJbI42\\", + \\":\`(\\": \\":\`(__iHMJbI42\\", + \\"1a2b3c\\": \\"1a2b3c__iHMJbI42\\", + \\"#fake-id\\": \\"#fake-id__iHMJbI42\\", + \\"-a-b-c-\\": \\"-a-b-c-__iHMJbI42\\", + \\"©\\": \\"©__iHMJbI42\\", + \\"♥\\": \\"♥__iHMJbI42\\", + \\"😍\\": \\"😍__iHMJbI42\\", + \\"“‘’”\\": \\"“‘’”__iHMJbI42\\", + \\"☺☃\\": \\"☺☃__iHMJbI42\\", + \\"⌘⌥\\": \\"⌘⌥__iHMJbI42\\", + \\"𝄞♪♩♫♬\\": \\"𝄞♪♩♫♬__iHMJbI42\\", + \\"💩\\": \\"💩__iHMJbI42\\", + \\"?\\": \\"?__iHMJbI42\\", + \\"@\\": \\"@__iHMJbI42\\", + \\".\\": \\".__iHMJbI42\\", + \\":)\\": \\":)__iHMJbI42\\", + \\"

\\": \\"

__iHMJbI42\\", + \\"<><<<>><>\\": \\"<><<<>><>__iHMJbI42\\", + \\"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.\\": \\"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.__iHMJbI42\\", + \\"#\\": \\"#__iHMJbI42\\", + \\"##\\": \\"##__iHMJbI42\\", + \\"#.#.#\\": \\"#.#.#__iHMJbI42\\", + \\"_\\": \\"___iHMJbI42\\", + \\"{}\\": \\"{}__iHMJbI42\\", + \\"foo.bar\\": \\"foo.bar__iHMJbI42\\", + \\":hover\\": \\":hover__iHMJbI42\\", + \\":hover:focus:active\\": \\":hover:focus:active__iHMJbI42\\", + \\"[attr=value]\\": \\"[attr=value]__iHMJbI42\\", + \\"f/o/o\\": \\"f/o/o__iHMJbI42\\", + \\"f\\\\\\\\o\\\\\\\\o\\": \\"f\\\\\\\\o\\\\\\\\o__iHMJbI42\\", + \\"f*o*o\\": \\"f*o*o__iHMJbI42\\", + \\"f!o!o\\": \\"f!o!o__iHMJbI42\\", + \\"f'o'o\\": \\"f'o'o__iHMJbI42\\", + \\"f~o~o\\": \\"f~o~o__iHMJbI42\\", + \\"f+o+o\\": \\"f+o+o__iHMJbI42\\", + \\"foo/bar\\": \\"foo/bar__iHMJbI42\\", + \\"foo\\\\\\\\bar\\": \\"foo\\\\\\\\bar__iHMJbI42\\", + \\"foo/bar/baz\\": \\"foo/bar/baz__iHMJbI42\\", + \\"foo\\\\\\\\bar\\\\\\\\baz\\": \\"foo\\\\\\\\bar\\\\\\\\baz__iHMJbI42\\" +}; +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: result 1`] = ` +Array [ + Array [ + "./modules/localIdentName/localIdentName.css", + ".test__iHMJbI42 { + background: red; +} + +._test__iHMJbI42 { + background: blue; +} + +.className__iHMJbI42 { + background: red; +} + +#someId__iHMJbI42 { + background: green; +} + +.className__iHMJbI42 .subClass__iHMJbI42 { + color: green; +} + +#someId__iHMJbI42 .subClass__iHMJbI42 { + color: blue; +} + +.-a0-34a___f__iHMJbI42 { + color: red; +} + +.m_x_\\\\@__iHMJbI42 { + margin-left: auto !important; + margin-right: auto !important; +} + +.B\\\\&W\\\\?__iHMJbI42 { + margin-left: auto !important; + margin-right: auto !important; +} + +/* matches elements with class=\\":\`(\\" */ +.\\\\3A \\\\\`\\\\(__iHMJbI42 { + color: aqua; +} + +/* matches elements with class=\\"1a2b3c\\" */ +.\\\\31 a2b3c__iHMJbI42 { + color: aliceblue; +} + +/* matches the element with id=\\"#fake-id\\" */ +#\\\\#fake-id__iHMJbI42 { + color: antiquewhite; +} + +/* matches the element with id=\\"-a-b-c-\\" */ +#-a-b-c-__iHMJbI42 { + color: azure; +} + +/* matches the element with id=\\"©\\" */ +#©__iHMJbI42 { + color: black; +} + +.♥__iHMJbI42 { background: lime; } +.©__iHMJbI42 { background: lime; } +.😍__iHMJbI42 { background: lime; } +.“‘’”__iHMJbI42 { background: lime; } +.☺☃__iHMJbI42 { background: lime; } +.⌘⌥__iHMJbI42 { background: lime; } +.𝄞♪♩♫♬__iHMJbI42 { background: lime; } +.💩__iHMJbI42 { background: lime; } +.\\\\?__iHMJbI42 { background: lime; } +.\\\\@__iHMJbI42 { background: lime; } +.\\\\.__iHMJbI42 { background: lime; } +.\\\\3A \\\\)__iHMJbI42 { background: lime; } +.\\\\3A \\\\\`\\\\(__iHMJbI42 { background: lime; } +.\\\\31 23__iHMJbI42 { background: lime; } +.\\\\31 a2b3c__iHMJbI42 { background: lime; } +.\\\\__iHMJbI42 { background: lime; } +.\\\\<\\\\>\\\\<\\\\<\\\\<\\\\>\\\\>\\\\<\\\\>__iHMJbI42 { background: lime; } +.\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\[\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\>\\\\+\\\\<\\\\<\\\\<\\\\<\\\\-\\\\]\\\\>\\\\+\\\\+\\\\.\\\\>\\\\+\\\\.\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\.\\\\+\\\\+\\\\+\\\\.\\\\>\\\\+\\\\+\\\\.\\\\<\\\\<\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\>\\\\.\\\\+\\\\+\\\\+\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\>\\\\+\\\\.\\\\>\\\\.__iHMJbI42 { background: lime; } +.\\\\#__iHMJbI42 { background: lime; } +.\\\\#\\\\#__iHMJbI42 { background: lime; } +.\\\\#\\\\.\\\\#\\\\.\\\\#__iHMJbI42 { background: lime; } +.\\\\___iHMJbI42 { background: lime; } +.\\\\{\\\\}__iHMJbI42 { background: lime; } +.\\\\#fake\\\\-id__iHMJbI42 { background: lime; } +.foo\\\\.bar__iHMJbI42 { background: lime; } +.\\\\3A hover__iHMJbI42 { background: lime; } +.\\\\3A hover\\\\3A focus\\\\3A active__iHMJbI42 { background: lime; } +.\\\\[attr\\\\=value\\\\]__iHMJbI42 { background: lime; } +.f\\\\/o\\\\/o__iHMJbI42 { background: lime; } +.f\\\\\\\\o\\\\\\\\o__iHMJbI42 { background: lime; } +.f\\\\*o\\\\*o__iHMJbI42 { background: lime; } +.f\\\\!o\\\\!o__iHMJbI42 { background: lime; } +.f\\\\'o\\\\'o__iHMJbI42 { background: lime; } +.f\\\\~o\\\\~o__iHMJbI42 { background: lime; } +.f\\\\+o\\\\+o__iHMJbI42 { background: lime; } + +.foo\\\\/bar__iHMJbI42 { + background: hotpink; +} + +.foo\\\\\\\\bar__iHMJbI42 { + background: hotpink; +} + +.foo\\\\/bar\\\\/baz__iHMJbI42 { + background: hotpink; +} + +.foo\\\\\\\\bar\\\\\\\\baz__iHMJbI42 { + background: hotpink; +} +", + "", + ], +] +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: warnings 1`] = `Array []`; + +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: errors 1`] = `Array []`; + +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: module 1`] = ` +"// Imports +import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; +import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\".KuIShlgs {\\\\n background: red;\\\\n}\\\\n\\\\n.Lb3fhDAu {\\\\n background: blue;\\\\n}\\\\n\\\\n.LdhpkZRW {\\\\n background: red;\\\\n}\\\\n\\\\n#b0rhwJSt {\\\\n background: green;\\\\n}\\\\n\\\\n.LdhpkZRW .Mw9j4nId {\\\\n color: green;\\\\n}\\\\n\\\\n#b0rhwJSt .Mw9j4nId {\\\\n color: blue;\\\\n}\\\\n\\\\n.DdFWMPol {\\\\n color: red;\\\\n}\\\\n\\\\n.OdAmghrm {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n.h4SEF34C {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\":\`(\\\\\\" */\\\\n.fKJQkLar {\\\\n color: aqua;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\"1a2b3c\\\\\\" */\\\\n.YR1u_buY {\\\\n color: aliceblue;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"#fake-id\\\\\\" */\\\\n#AqiAGSfn {\\\\n color: antiquewhite;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"-a-b-c-\\\\\\" */\\\\n#CwXv27VM {\\\\n color: azure;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"©\\\\\\" */\\\\n#jBj0sZiW {\\\\n color: black;\\\\n}\\\\n\\\\n.vJl9A9Ds { background: lime; }\\\\n.jBj0sZiW { background: lime; }\\\\n.CNLr9yJw { background: lime; }\\\\n.GM0Y0nFC { background: lime; }\\\\n.NKrBw7EA { background: lime; }\\\\n.edHWpSne { background: lime; }\\\\n.QyMp9YME { background: lime; }\\\\n.B82YxwgR { background: lime; }\\\\n.ndmpvNNl { background: lime; }\\\\n.v3gq0wPo { background: lime; }\\\\n.zd5uIZq6 { background: lime; }\\\\n.ZiZnRjRT { background: lime; }\\\\n.fKJQkLar { background: lime; }\\\\n.oqRGsO4U { background: lime; }\\\\n.YR1u_buY { background: lime; }\\\\n.TdAx2ZSk { background: lime; }\\\\n.ozNsTIG0 { background: lime; }\\\\n.ByKoYcSr { background: lime; }\\\\n.HkwIsjW5 { background: lime; }\\\\n.IJc6Xl4Z { background: lime; }\\\\n.BnPpnJmP { background: lime; }\\\\n.bCwkZEDu { background: lime; }\\\\n.IZkBfE9i { background: lime; }\\\\n.AqiAGSfn { background: lime; }\\\\n.uajo7mHz { background: lime; }\\\\n.HVudUNXn { background: lime; }\\\\n.ZlaaXvHL { background: lime; }\\\\n.PWvC4jVM { background: lime; }\\\\n.A5l5sDOD { background: lime; }\\\\n.DFfh4Kyq { background: lime; }\\\\n.gv1E2n_b { background: lime; }\\\\n._aIyR9ET { background: lime; }\\\\n.HSXNnSjt { background: lime; }\\\\n.MrVzSIcS { background: lime; }\\\\n.EvMHRmCu { background: lime; }\\\\n\\\\n.hei2uQgD {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.IgSzmmsC {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.p6KJMhNW {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.HZerWgmU {\\\\n background: hotpink;\\\\n}\\\\n\\", \\"\\"]); +// Exports +___CSS_LOADER_EXPORT___.locals = { + \\"123\\": \\"oqRGsO4U\\", + \\"test\\": \\"KuIShlgs\\", + \\"_test\\": \\"Lb3fhDAu\\", + \\"className\\": \\"LdhpkZRW\\", + \\"someId\\": \\"b0rhwJSt\\", + \\"subClass\\": \\"Mw9j4nId\\", + \\"-a0-34a___f\\": \\"DdFWMPol\\", + \\"m_x_@\\": \\"OdAmghrm\\", + \\"B&W?\\": \\"h4SEF34C\\", + \\":\`(\\": \\"fKJQkLar\\", + \\"1a2b3c\\": \\"YR1u_buY\\", + \\"#fake-id\\": \\"AqiAGSfn\\", + \\"-a-b-c-\\": \\"CwXv27VM\\", + \\"©\\": \\"jBj0sZiW\\", + \\"♥\\": \\"vJl9A9Ds\\", + \\"😍\\": \\"CNLr9yJw\\", + \\"“‘’”\\": \\"GM0Y0nFC\\", + \\"☺☃\\": \\"NKrBw7EA\\", + \\"⌘⌥\\": \\"edHWpSne\\", + \\"𝄞♪♩♫♬\\": \\"QyMp9YME\\", + \\"💩\\": \\"B82YxwgR\\", + \\"?\\": \\"ndmpvNNl\\", + \\"@\\": \\"v3gq0wPo\\", + \\".\\": \\"zd5uIZq6\\", + \\":)\\": \\"ZiZnRjRT\\", + \\"

\\": \\"TdAx2ZSk\\", + \\"<><<<>><>\\": \\"ozNsTIG0\\", + \\"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.\\": \\"ByKoYcSr\\", + \\"#\\": \\"HkwIsjW5\\", + \\"##\\": \\"IJc6Xl4Z\\", + \\"#.#.#\\": \\"BnPpnJmP\\", + \\"_\\": \\"bCwkZEDu\\", + \\"{}\\": \\"IZkBfE9i\\", + \\"foo.bar\\": \\"uajo7mHz\\", + \\":hover\\": \\"HVudUNXn\\", + \\":hover:focus:active\\": \\"ZlaaXvHL\\", + \\"[attr=value]\\": \\"PWvC4jVM\\", + \\"f/o/o\\": \\"A5l5sDOD\\", + \\"f\\\\\\\\o\\\\\\\\o\\": \\"DFfh4Kyq\\", + \\"f*o*o\\": \\"gv1E2n_b\\", + \\"f!o!o\\": \\"_aIyR9ET\\", + \\"f'o'o\\": \\"HSXNnSjt\\", + \\"f~o~o\\": \\"MrVzSIcS\\", + \\"f+o+o\\": \\"EvMHRmCu\\", + \\"foo/bar\\": \\"hei2uQgD\\", + \\"foo\\\\\\\\bar\\": \\"IgSzmmsC\\", + \\"foo/bar/baz\\": \\"p6KJMhNW\\", + \\"foo\\\\\\\\bar\\\\\\\\baz\\": \\"HZerWgmU\\" +}; +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: result 1`] = ` +Array [ + Array [ + "./modules/localIdentName/localIdentName.css", + ".KuIShlgs { + background: red; +} + +.Lb3fhDAu { + background: blue; +} + +.LdhpkZRW { + background: red; +} + +#b0rhwJSt { + background: green; +} + +.LdhpkZRW .Mw9j4nId { + color: green; +} + +#b0rhwJSt .Mw9j4nId { + color: blue; +} + +.DdFWMPol { + color: red; +} + +.OdAmghrm { + margin-left: auto !important; + margin-right: auto !important; +} + +.h4SEF34C { + margin-left: auto !important; + margin-right: auto !important; +} + +/* matches elements with class=\\":\`(\\" */ +.fKJQkLar { + color: aqua; +} + +/* matches elements with class=\\"1a2b3c\\" */ +.YR1u_buY { + color: aliceblue; +} + +/* matches the element with id=\\"#fake-id\\" */ +#AqiAGSfn { + color: antiquewhite; +} + +/* matches the element with id=\\"-a-b-c-\\" */ +#CwXv27VM { + color: azure; +} + +/* matches the element with id=\\"©\\" */ +#jBj0sZiW { + color: black; +} + +.vJl9A9Ds { background: lime; } +.jBj0sZiW { background: lime; } +.CNLr9yJw { background: lime; } +.GM0Y0nFC { background: lime; } +.NKrBw7EA { background: lime; } +.edHWpSne { background: lime; } +.QyMp9YME { background: lime; } +.B82YxwgR { background: lime; } +.ndmpvNNl { background: lime; } +.v3gq0wPo { background: lime; } +.zd5uIZq6 { background: lime; } +.ZiZnRjRT { background: lime; } +.fKJQkLar { background: lime; } +.oqRGsO4U { background: lime; } +.YR1u_buY { background: lime; } +.TdAx2ZSk { background: lime; } +.ozNsTIG0 { background: lime; } +.ByKoYcSr { background: lime; } +.HkwIsjW5 { background: lime; } +.IJc6Xl4Z { background: lime; } +.BnPpnJmP { background: lime; } +.bCwkZEDu { background: lime; } +.IZkBfE9i { background: lime; } +.AqiAGSfn { background: lime; } +.uajo7mHz { background: lime; } +.HVudUNXn { background: lime; } +.ZlaaXvHL { background: lime; } +.PWvC4jVM { background: lime; } +.A5l5sDOD { background: lime; } +.DFfh4Kyq { background: lime; } +.gv1E2n_b { background: lime; } +._aIyR9ET { background: lime; } +.HSXNnSjt { background: lime; } +.MrVzSIcS { background: lime; } +.EvMHRmCu { background: lime; } + +.hei2uQgD { + background: hotpink; +} + +.IgSzmmsC { + background: hotpink; +} + +.p6KJMhNW { + background: hotpink; +} + +.HZerWgmU { + background: hotpink; +} +", + "", + ], +] +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: warnings 1`] = `Array []`; + +exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": errors 1`] = `Array []`; + +exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": module 1`] = ` +"// Imports +import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; +import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\".iHMJbI42 {\\\\n background: red;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: blue;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: red;\\\\n}\\\\n\\\\n#iHMJbI42 {\\\\n background: green;\\\\n}\\\\n\\\\n.iHMJbI42 .iHMJbI42 {\\\\n color: green;\\\\n}\\\\n\\\\n#iHMJbI42 .iHMJbI42 {\\\\n color: blue;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n color: red;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\":\`(\\\\\\" */\\\\n.iHMJbI42 {\\\\n color: aqua;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\"1a2b3c\\\\\\" */\\\\n.iHMJbI42 {\\\\n color: aliceblue;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"#fake-id\\\\\\" */\\\\n#iHMJbI42 {\\\\n color: antiquewhite;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"-a-b-c-\\\\\\" */\\\\n#iHMJbI42 {\\\\n color: azure;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"©\\\\\\" */\\\\n#iHMJbI42 {\\\\n color: black;\\\\n}\\\\n\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\", \\"\\"]); +// Exports +___CSS_LOADER_EXPORT___.locals = { + \\"123\\": \\"iHMJbI42\\", + \\"test\\": \\"iHMJbI42\\", + \\"_test\\": \\"iHMJbI42\\", + \\"className\\": \\"iHMJbI42\\", + \\"someId\\": \\"iHMJbI42\\", + \\"subClass\\": \\"iHMJbI42\\", + \\"-a0-34a___f\\": \\"iHMJbI42\\", + \\"m_x_@\\": \\"iHMJbI42\\", + \\"B&W?\\": \\"iHMJbI42\\", + \\":\`(\\": \\"iHMJbI42\\", + \\"1a2b3c\\": \\"iHMJbI42\\", + \\"#fake-id\\": \\"iHMJbI42\\", + \\"-a-b-c-\\": \\"iHMJbI42\\", + \\"©\\": \\"iHMJbI42\\", + \\"♥\\": \\"iHMJbI42\\", + \\"😍\\": \\"iHMJbI42\\", + \\"“‘’”\\": \\"iHMJbI42\\", + \\"☺☃\\": \\"iHMJbI42\\", + \\"⌘⌥\\": \\"iHMJbI42\\", + \\"𝄞♪♩♫♬\\": \\"iHMJbI42\\", + \\"💩\\": \\"iHMJbI42\\", + \\"?\\": \\"iHMJbI42\\", + \\"@\\": \\"iHMJbI42\\", + \\".\\": \\"iHMJbI42\\", + \\":)\\": \\"iHMJbI42\\", + \\"

\\": \\"iHMJbI42\\", + \\"<><<<>><>\\": \\"iHMJbI42\\", + \\"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.\\": \\"iHMJbI42\\", + \\"#\\": \\"iHMJbI42\\", + \\"##\\": \\"iHMJbI42\\", + \\"#.#.#\\": \\"iHMJbI42\\", + \\"_\\": \\"iHMJbI42\\", + \\"{}\\": \\"iHMJbI42\\", + \\"foo.bar\\": \\"iHMJbI42\\", + \\":hover\\": \\"iHMJbI42\\", + \\":hover:focus:active\\": \\"iHMJbI42\\", + \\"[attr=value]\\": \\"iHMJbI42\\", + \\"f/o/o\\": \\"iHMJbI42\\", + \\"f\\\\\\\\o\\\\\\\\o\\": \\"iHMJbI42\\", + \\"f*o*o\\": \\"iHMJbI42\\", + \\"f!o!o\\": \\"iHMJbI42\\", + \\"f'o'o\\": \\"iHMJbI42\\", + \\"f~o~o\\": \\"iHMJbI42\\", + \\"f+o+o\\": \\"iHMJbI42\\", + \\"foo/bar\\": \\"iHMJbI42\\", + \\"foo\\\\\\\\bar\\": \\"iHMJbI42\\", + \\"foo/bar/baz\\": \\"iHMJbI42\\", + \\"foo\\\\\\\\bar\\\\\\\\baz\\": \\"iHMJbI42\\" +}; +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": result 1`] = ` +Array [ + Array [ + "./modules/localIdentName/localIdentName.css", + ".iHMJbI42 { + background: red; +} + +.iHMJbI42 { + background: blue; +} + +.iHMJbI42 { + background: red; +} + +#iHMJbI42 { + background: green; +} + +.iHMJbI42 .iHMJbI42 { + color: green; +} + +#iHMJbI42 .iHMJbI42 { + color: blue; +} + +.iHMJbI42 { + color: red; +} + +.iHMJbI42 { + margin-left: auto !important; + margin-right: auto !important; +} + +.iHMJbI42 { + margin-left: auto !important; + margin-right: auto !important; +} + +/* matches elements with class=\\":\`(\\" */ +.iHMJbI42 { + color: aqua; +} + +/* matches elements with class=\\"1a2b3c\\" */ +.iHMJbI42 { + color: aliceblue; +} + +/* matches the element with id=\\"#fake-id\\" */ +#iHMJbI42 { + color: antiquewhite; +} + +/* matches the element with id=\\"-a-b-c-\\" */ +#iHMJbI42 { + color: azure; +} + +/* matches the element with id=\\"©\\" */ +#iHMJbI42 { + color: black; +} + +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } +.iHMJbI42 { background: lime; } + +.iHMJbI42 { + background: hotpink; +} + +.iHMJbI42 { + background: hotpink; +} + +.iHMJbI42 { + background: hotpink; +} + +.iHMJbI42 { + background: hotpink; +} +", + "", + ], +] +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": warnings 1`] = `Array []`; + +exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": errors 1`] = `Array []`; + +exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": module 1`] = ` +"// Imports +import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; +import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\".test__KuIShlgs {\\\\n background: red;\\\\n}\\\\n\\\\n._test__Lb3fhDAu {\\\\n background: blue;\\\\n}\\\\n\\\\n.className__LdhpkZRW {\\\\n background: red;\\\\n}\\\\n\\\\n#someId__b0rhwJSt {\\\\n background: green;\\\\n}\\\\n\\\\n.className__LdhpkZRW .subClass__Mw9j4nId {\\\\n color: green;\\\\n}\\\\n\\\\n#someId__b0rhwJSt .subClass__Mw9j4nId {\\\\n color: blue;\\\\n}\\\\n\\\\n.-a0-34a___f__DdFWMPol {\\\\n color: red;\\\\n}\\\\n\\\\n.m_x_\\\\\\\\@__OdAmghrm {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n.B\\\\\\\\&W\\\\\\\\?__h4SEF34C {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\":\`(\\\\\\" */\\\\n.\\\\\\\\3A \\\\\\\\\`\\\\\\\\(__fKJQkLar {\\\\n color: aqua;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\"1a2b3c\\\\\\" */\\\\n.\\\\\\\\31 a2b3c__YR1u_buY {\\\\n color: aliceblue;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"#fake-id\\\\\\" */\\\\n#\\\\\\\\#fake-id__AqiAGSfn {\\\\n color: antiquewhite;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"-a-b-c-\\\\\\" */\\\\n#-a-b-c-__CwXv27VM {\\\\n color: azure;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"©\\\\\\" */\\\\n#©__jBj0sZiW {\\\\n color: black;\\\\n}\\\\n\\\\n.♥__vJl9A9Ds { background: lime; }\\\\n.©__jBj0sZiW { background: lime; }\\\\n.😍__CNLr9yJw { background: lime; }\\\\n.“‘’”__GM0Y0nFC { background: lime; }\\\\n.☺☃__NKrBw7EA { background: lime; }\\\\n.⌘⌥__edHWpSne { background: lime; }\\\\n.𝄞♪♩♫♬__QyMp9YME { background: lime; }\\\\n.💩__B82YxwgR { background: lime; }\\\\n.\\\\\\\\?__ndmpvNNl { background: lime; }\\\\n.\\\\\\\\@__v3gq0wPo { background: lime; }\\\\n.\\\\\\\\.__zd5uIZq6 { background: lime; }\\\\n.\\\\\\\\3A \\\\\\\\)__ZiZnRjRT { background: lime; }\\\\n.\\\\\\\\3A \\\\\\\\\`\\\\\\\\(__fKJQkLar { background: lime; }\\\\n.\\\\\\\\31 23__oqRGsO4U { background: lime; }\\\\n.\\\\\\\\31 a2b3c__YR1u_buY { background: lime; }\\\\n.\\\\\\\\__TdAx2ZSk { background: lime; }\\\\n.\\\\\\\\<\\\\\\\\>\\\\\\\\<\\\\\\\\<\\\\\\\\<\\\\\\\\>\\\\\\\\>\\\\\\\\<\\\\\\\\>__ozNsTIG0 { background: lime; }\\\\n.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\[\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\>\\\\\\\\+\\\\\\\\<\\\\\\\\<\\\\\\\\<\\\\\\\\<\\\\\\\\-\\\\\\\\]\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\+\\\\\\\\.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\<\\\\\\\\<\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\.\\\\\\\\+\\\\\\\\+\\\\\\\\+\\\\\\\\.\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\.\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\-\\\\\\\\.\\\\\\\\>\\\\\\\\+\\\\\\\\.\\\\\\\\>\\\\\\\\.__ByKoYcSr { background: lime; }\\\\n.\\\\\\\\#__HkwIsjW5 { background: lime; }\\\\n.\\\\\\\\#\\\\\\\\#__IJc6Xl4Z { background: lime; }\\\\n.\\\\\\\\#\\\\\\\\.\\\\\\\\#\\\\\\\\.\\\\\\\\#__BnPpnJmP { background: lime; }\\\\n.\\\\\\\\___bCwkZEDu { background: lime; }\\\\n.\\\\\\\\{\\\\\\\\}__IZkBfE9i { background: lime; }\\\\n.\\\\\\\\#fake\\\\\\\\-id__AqiAGSfn { background: lime; }\\\\n.foo\\\\\\\\.bar__uajo7mHz { background: lime; }\\\\n.\\\\\\\\3A hover__HVudUNXn { background: lime; }\\\\n.\\\\\\\\3A hover\\\\\\\\3A focus\\\\\\\\3A active__ZlaaXvHL { background: lime; }\\\\n.\\\\\\\\[attr\\\\\\\\=value\\\\\\\\]__PWvC4jVM { background: lime; }\\\\n.f\\\\\\\\/o\\\\\\\\/o__A5l5sDOD { background: lime; }\\\\n.f\\\\\\\\\\\\\\\\o\\\\\\\\\\\\\\\\o__DFfh4Kyq { background: lime; }\\\\n.f\\\\\\\\*o\\\\\\\\*o__gv1E2n_b { background: lime; }\\\\n.f\\\\\\\\!o\\\\\\\\!o___aIyR9ET { background: lime; }\\\\n.f\\\\\\\\'o\\\\\\\\'o__HSXNnSjt { background: lime; }\\\\n.f\\\\\\\\~o\\\\\\\\~o__MrVzSIcS { background: lime; }\\\\n.f\\\\\\\\+o\\\\\\\\+o__EvMHRmCu { background: lime; }\\\\n\\\\n.foo\\\\\\\\/bar__hei2uQgD {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.foo\\\\\\\\\\\\\\\\bar__IgSzmmsC {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.foo\\\\\\\\/bar\\\\\\\\/baz__p6KJMhNW {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.foo\\\\\\\\\\\\\\\\bar\\\\\\\\\\\\\\\\baz__HZerWgmU {\\\\n background: hotpink;\\\\n}\\\\n\\", \\"\\"]); +// Exports +___CSS_LOADER_EXPORT___.locals = { + \\"123\\": \\"123__oqRGsO4U\\", + \\"test\\": \\"test__KuIShlgs\\", + \\"_test\\": \\"_test__Lb3fhDAu\\", + \\"className\\": \\"className__LdhpkZRW\\", + \\"someId\\": \\"someId__b0rhwJSt\\", + \\"subClass\\": \\"subClass__Mw9j4nId\\", + \\"-a0-34a___f\\": \\"-a0-34a___f__DdFWMPol\\", + \\"m_x_@\\": \\"m_x_@__OdAmghrm\\", + \\"B&W?\\": \\"B&W?__h4SEF34C\\", + \\":\`(\\": \\":\`(__fKJQkLar\\", + \\"1a2b3c\\": \\"1a2b3c__YR1u_buY\\", + \\"#fake-id\\": \\"#fake-id__AqiAGSfn\\", + \\"-a-b-c-\\": \\"-a-b-c-__CwXv27VM\\", + \\"©\\": \\"©__jBj0sZiW\\", + \\"♥\\": \\"♥__vJl9A9Ds\\", + \\"😍\\": \\"😍__CNLr9yJw\\", + \\"“‘’”\\": \\"“‘’”__GM0Y0nFC\\", + \\"☺☃\\": \\"☺☃__NKrBw7EA\\", + \\"⌘⌥\\": \\"⌘⌥__edHWpSne\\", + \\"𝄞♪♩♫♬\\": \\"𝄞♪♩♫♬__QyMp9YME\\", + \\"💩\\": \\"💩__B82YxwgR\\", + \\"?\\": \\"?__ndmpvNNl\\", + \\"@\\": \\"@__v3gq0wPo\\", + \\".\\": \\".__zd5uIZq6\\", + \\":)\\": \\":)__ZiZnRjRT\\", + \\"

\\": \\"

__TdAx2ZSk\\", + \\"<><<<>><>\\": \\"<><<<>><>__ozNsTIG0\\", + \\"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.\\": \\"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.__ByKoYcSr\\", + \\"#\\": \\"#__HkwIsjW5\\", + \\"##\\": \\"##__IJc6Xl4Z\\", + \\"#.#.#\\": \\"#.#.#__BnPpnJmP\\", + \\"_\\": \\"___bCwkZEDu\\", + \\"{}\\": \\"{}__IZkBfE9i\\", + \\"foo.bar\\": \\"foo.bar__uajo7mHz\\", + \\":hover\\": \\":hover__HVudUNXn\\", + \\":hover:focus:active\\": \\":hover:focus:active__ZlaaXvHL\\", + \\"[attr=value]\\": \\"[attr=value]__PWvC4jVM\\", + \\"f/o/o\\": \\"f/o/o__A5l5sDOD\\", + \\"f\\\\\\\\o\\\\\\\\o\\": \\"f\\\\\\\\o\\\\\\\\o__DFfh4Kyq\\", + \\"f*o*o\\": \\"f*o*o__gv1E2n_b\\", + \\"f!o!o\\": \\"f!o!o___aIyR9ET\\", + \\"f'o'o\\": \\"f'o'o__HSXNnSjt\\", + \\"f~o~o\\": \\"f~o~o__MrVzSIcS\\", + \\"f+o+o\\": \\"f+o+o__EvMHRmCu\\", + \\"foo/bar\\": \\"foo/bar__hei2uQgD\\", + \\"foo\\\\\\\\bar\\": \\"foo\\\\\\\\bar__IgSzmmsC\\", + \\"foo/bar/baz\\": \\"foo/bar/baz__p6KJMhNW\\", + \\"foo\\\\\\\\bar\\\\\\\\baz\\": \\"foo\\\\\\\\bar\\\\\\\\baz__HZerWgmU\\" +}; +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": result 1`] = ` +Array [ + Array [ + "./modules/localIdentName/localIdentName.css", + ".test__KuIShlgs { + background: red; +} + +._test__Lb3fhDAu { + background: blue; +} + +.className__LdhpkZRW { + background: red; +} + +#someId__b0rhwJSt { + background: green; +} + +.className__LdhpkZRW .subClass__Mw9j4nId { + color: green; +} + +#someId__b0rhwJSt .subClass__Mw9j4nId { + color: blue; +} + +.-a0-34a___f__DdFWMPol { + color: red; +} + +.m_x_\\\\@__OdAmghrm { + margin-left: auto !important; + margin-right: auto !important; +} + +.B\\\\&W\\\\?__h4SEF34C { + margin-left: auto !important; + margin-right: auto !important; +} + +/* matches elements with class=\\":\`(\\" */ +.\\\\3A \\\\\`\\\\(__fKJQkLar { + color: aqua; +} + +/* matches elements with class=\\"1a2b3c\\" */ +.\\\\31 a2b3c__YR1u_buY { + color: aliceblue; +} + +/* matches the element with id=\\"#fake-id\\" */ +#\\\\#fake-id__AqiAGSfn { + color: antiquewhite; +} + +/* matches the element with id=\\"-a-b-c-\\" */ +#-a-b-c-__CwXv27VM { + color: azure; +} + +/* matches the element with id=\\"©\\" */ +#©__jBj0sZiW { + color: black; +} + +.♥__vJl9A9Ds { background: lime; } +.©__jBj0sZiW { background: lime; } +.😍__CNLr9yJw { background: lime; } +.“‘’”__GM0Y0nFC { background: lime; } +.☺☃__NKrBw7EA { background: lime; } +.⌘⌥__edHWpSne { background: lime; } +.𝄞♪♩♫♬__QyMp9YME { background: lime; } +.💩__B82YxwgR { background: lime; } +.\\\\?__ndmpvNNl { background: lime; } +.\\\\@__v3gq0wPo { background: lime; } +.\\\\.__zd5uIZq6 { background: lime; } +.\\\\3A \\\\)__ZiZnRjRT { background: lime; } +.\\\\3A \\\\\`\\\\(__fKJQkLar { background: lime; } +.\\\\31 23__oqRGsO4U { background: lime; } +.\\\\31 a2b3c__YR1u_buY { background: lime; } +.\\\\__TdAx2ZSk { background: lime; } +.\\\\<\\\\>\\\\<\\\\<\\\\<\\\\>\\\\>\\\\<\\\\>__ozNsTIG0 { background: lime; } +.\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\[\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\>\\\\+\\\\<\\\\<\\\\<\\\\<\\\\-\\\\]\\\\>\\\\+\\\\+\\\\.\\\\>\\\\+\\\\.\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\.\\\\+\\\\+\\\\+\\\\.\\\\>\\\\+\\\\+\\\\.\\\\<\\\\<\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\>\\\\.\\\\+\\\\+\\\\+\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\>\\\\+\\\\.\\\\>\\\\.__ByKoYcSr { background: lime; } +.\\\\#__HkwIsjW5 { background: lime; } +.\\\\#\\\\#__IJc6Xl4Z { background: lime; } +.\\\\#\\\\.\\\\#\\\\.\\\\#__BnPpnJmP { background: lime; } +.\\\\___bCwkZEDu { background: lime; } +.\\\\{\\\\}__IZkBfE9i { background: lime; } +.\\\\#fake\\\\-id__AqiAGSfn { background: lime; } +.foo\\\\.bar__uajo7mHz { background: lime; } +.\\\\3A hover__HVudUNXn { background: lime; } +.\\\\3A hover\\\\3A focus\\\\3A active__ZlaaXvHL { background: lime; } +.\\\\[attr\\\\=value\\\\]__PWvC4jVM { background: lime; } +.f\\\\/o\\\\/o__A5l5sDOD { background: lime; } +.f\\\\\\\\o\\\\\\\\o__DFfh4Kyq { background: lime; } +.f\\\\*o\\\\*o__gv1E2n_b { background: lime; } +.f\\\\!o\\\\!o___aIyR9ET { background: lime; } +.f\\\\'o\\\\'o__HSXNnSjt { background: lime; } +.f\\\\~o\\\\~o__MrVzSIcS { background: lime; } +.f\\\\+o\\\\+o__EvMHRmCu { background: lime; } + +.foo\\\\/bar__hei2uQgD { + background: hotpink; +} + +.foo\\\\\\\\bar__IgSzmmsC { + background: hotpink; +} + +.foo\\\\/bar\\\\/baz__p6KJMhNW { + background: hotpink; +} + +.foo\\\\\\\\bar\\\\\\\\baz__HZerWgmU { + background: hotpink; +} +", + "", + ], +] +`; + +exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": warnings 1`] = `Array []`; + exports[`"modules" option should work and respect the "localConvention" option with the "asIs" value: errors 1`] = `Array []`; exports[`"modules" option should work and respect the "localConvention" option with the "asIs" value: module 1`] = ` diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap index 07e4a828..0e295060 100644 --- a/test/__snapshots__/validate-options.test.js.snap +++ b/test/__snapshots__/validate-options.test.js.snap @@ -85,7 +85,7 @@ exports[`validate options should throw an error on the "importLoaders" option wi exports[`validate options should throw an error on the "modules" option with "{"auto":"invalid"}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -109,7 +109,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "{"exportLocalsConvention":"unknown"}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -161,7 +161,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "{"localIdentRegExp":true}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -177,7 +177,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "{"mode":"globals"}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -194,7 +194,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "{"mode":"locals"}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -211,7 +211,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "{"mode":"pures"}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -228,7 +228,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "{"mode":true}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -252,7 +252,7 @@ exports[`validate options should throw an error on the "modules" option with "{" exports[`validate options should throw an error on the "modules" option with "globals" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -260,13 +260,13 @@ exports[`validate options should throw an error on the "modules" option with "gl * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" * options.modules should be an object: - object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" + object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" `; exports[`validate options should throw an error on the "modules" option with "locals" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -274,13 +274,13 @@ exports[`validate options should throw an error on the "modules" option with "lo * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" * options.modules should be an object: - object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" + object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" `; exports[`validate options should throw an error on the "modules" option with "pures" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -288,13 +288,13 @@ exports[`validate options should throw an error on the "modules" option with "pu * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" * options.modules should be an object: - object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" + object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" `; exports[`validate options should throw an error on the "modules" option with "true" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules should be one of these: - boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" | object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? } -> Allows to enable/disable CSS Modules or ICSS and setup configuration. -> Read more at https://github.com/webpack-contrib/css-loader#modules Details: @@ -302,7 +302,7 @@ exports[`validate options should throw an error on the "modules" option with "tr * options.modules should be one of these: \\"local\\" | \\"global\\" | \\"pure\\" | \\"icss\\" * options.modules should be an object: - object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" + object { auto?, mode?, localIdentName?, localIdentContext?, localIdentHashSalt?, localIdentHashFunction?, localIdentHashDigest?, localIdentHashDigestLength?, hashStrategy?, localIdentRegExp?, getLocalIdent?, namedExport?, exportGlobals?, exportLocalsConvention?, exportOnlyLocals? }" `; exports[`validate options should throw an error on the "sourceMap" option with "true" value 1`] = ` diff --git a/test/modules-option.test.js b/test/modules-option.test.js index bba0fada..5731a329 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -381,6 +381,86 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot("errors"); }); + it('should work and respect the "hashStrategy" = "use-local-name"', async () => { + const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { + modules: { + localIdentName: "[local]__[hash:base64:8]", + // localName should be used even if [local] is contained in the localIdentName template + hashStrategy: "use-local-name", + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource("./modules/localIdentName/localIdentName.css", stats) + ).toMatchSnapshot("module"); + expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( + "result" + ); + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); + + it('should work and respect the "hashStrategy" = "omit-local-name"', async () => { + const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { + modules: { + localIdentName: "[hash:base64:8]", + // localName should not be used even if [local] is absent from the localIdentName template + hashStrategy: "omit-local-name", + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource("./modules/localIdentName/localIdentName.css", stats) + ).toMatchSnapshot("module"); + expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( + "result" + ); + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); + + it('should work and respect the "hashStrategy" = "auto" and [local]', async () => { + const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { + modules: { + localIdentName: "[local]__[hash:base64:8]", + // localName should not be used: [local] is used + hashStrategy: "auto", + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource("./modules/localIdentName/localIdentName.css", stats) + ).toMatchSnapshot("module"); + expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( + "result" + ); + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); + + it('should work and respect the "hashStrategy" = "auto" and no [local]', async () => { + const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { + modules: { + localIdentName: "[hash:base64:8]", + // localName should be used: [local] is not used + hashStrategy: "auto", + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource("./modules/localIdentName/localIdentName.css", stats) + ).toMatchSnapshot("module"); + expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( + "result" + ); + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); + it('should work and has "undefined" context if no context was given', async () => { expect.assertions(59); From 976ff89756b31035f19e8a441ee55378f255ba76 Mon Sep 17 00:00:00 2001 From: Anton Khlynovskiy Date: Thu, 27 Jan 2022 15:41:03 +0300 Subject: [PATCH 2/4] feat: do not hash localName if the localName is inlined: Remove senseless .modules.hashStrategy = "omit-local-name" --- README.md | 5 +- src/options.json | 2 +- src/utils.js | 19 +- .../__snapshots__/modules-option.test.js.snap | 190 ------------------ test/modules-option.test.js | 20 -- 5 files changed, 7 insertions(+), 229 deletions(-) diff --git a/README.md b/README.md index c3ddb229..296ba3a9 100644 --- a/README.md +++ b/README.md @@ -874,14 +874,13 @@ module.exports = { ##### `hashStrategy` -Type: `'use-local-name' | 'omit-local-name' | 'auto'` +Type: `'use-local-name' | 'auto'` Default: `'use-local-name'` Should local name be used when computing the hash. -- `'auto'` Auto detect based on [localIdentName](#localidentname). Use this value to get the output that is better compressable by GZIP or Brotli. - `'use-local-name'` Each identifier in a module gets its own hash digest. -- `'omit-local-name'` All identifiers from the same module shares the same hash digest. Handle with care! +- `'auto'` Identifiers from the same module shares the same hash digest if it's possible. Use this value to optimize the output for better GZIP or Brotli compression. **webpack.config.js** diff --git a/src/options.json b/src/options.json index 9f2db86d..a642c037 100644 --- a/src/options.json +++ b/src/options.json @@ -117,7 +117,7 @@ "hashStrategy": { "description": "Allows to specify should localName be used when computing the hash.", "link": "https://github.com/webpack-contrib/css-loader#hashstrategy", - "enum": ["use-local-name", "omit-local-name", "auto"] + "enum": ["use-local-name", "auto"] }, "localIdentRegExp": { "description": "Allows to specify custom RegExp for local ident name.", diff --git a/src/utils.js b/src/utils.js index a55c4b9a..57c2ac84 100644 --- a/src/utils.js +++ b/src/utils.js @@ -336,22 +336,11 @@ function defaultGetLocalIdent( path.relative(context, resourcePath) ); - let useLocalNameInHash; - switch (hashStrategy) { - case "omit-local-name": - useLocalNameInHash = false; - break; - case "auto": - useLocalNameInHash = !/\[local\]/.test(localIdentName); - break; - default: - // undefined or "use-local-name" - useLocalNameInHash = true; - } // eslint-disable-next-line no-param-reassign - options.content = useLocalNameInHash - ? `${relativeResourcePath}\x00${localName}` - : relativeResourcePath; + options.content = + hashStrategy === "auto" && /\[local\]/.test(localIdentName) + ? relativeResourcePath + : `${relativeResourcePath}\x00${localName}`; let { hashFunction, hashDigest, hashDigestLength } = options; const matches = localIdentName.match( diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index 23e56d05..20c06962 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -3777,196 +3777,6 @@ Array [ exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: warnings 1`] = `Array []`; -exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": errors 1`] = `Array []`; - -exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": module 1`] = ` -"// Imports -import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; -import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; -var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___); -// Module -___CSS_LOADER_EXPORT___.push([module.id, \\".iHMJbI42 {\\\\n background: red;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: blue;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: red;\\\\n}\\\\n\\\\n#iHMJbI42 {\\\\n background: green;\\\\n}\\\\n\\\\n.iHMJbI42 .iHMJbI42 {\\\\n color: green;\\\\n}\\\\n\\\\n#iHMJbI42 .iHMJbI42 {\\\\n color: blue;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n color: red;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n margin-left: auto !important;\\\\n margin-right: auto !important;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\":\`(\\\\\\" */\\\\n.iHMJbI42 {\\\\n color: aqua;\\\\n}\\\\n\\\\n/* matches elements with class=\\\\\\"1a2b3c\\\\\\" */\\\\n.iHMJbI42 {\\\\n color: aliceblue;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"#fake-id\\\\\\" */\\\\n#iHMJbI42 {\\\\n color: antiquewhite;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"-a-b-c-\\\\\\" */\\\\n#iHMJbI42 {\\\\n color: azure;\\\\n}\\\\n\\\\n/* matches the element with id=\\\\\\"©\\\\\\" */\\\\n#iHMJbI42 {\\\\n color: black;\\\\n}\\\\n\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n.iHMJbI42 { background: lime; }\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\\\n.iHMJbI42 {\\\\n background: hotpink;\\\\n}\\\\n\\", \\"\\"]); -// Exports -___CSS_LOADER_EXPORT___.locals = { - \\"123\\": \\"iHMJbI42\\", - \\"test\\": \\"iHMJbI42\\", - \\"_test\\": \\"iHMJbI42\\", - \\"className\\": \\"iHMJbI42\\", - \\"someId\\": \\"iHMJbI42\\", - \\"subClass\\": \\"iHMJbI42\\", - \\"-a0-34a___f\\": \\"iHMJbI42\\", - \\"m_x_@\\": \\"iHMJbI42\\", - \\"B&W?\\": \\"iHMJbI42\\", - \\":\`(\\": \\"iHMJbI42\\", - \\"1a2b3c\\": \\"iHMJbI42\\", - \\"#fake-id\\": \\"iHMJbI42\\", - \\"-a-b-c-\\": \\"iHMJbI42\\", - \\"©\\": \\"iHMJbI42\\", - \\"♥\\": \\"iHMJbI42\\", - \\"😍\\": \\"iHMJbI42\\", - \\"“‘’”\\": \\"iHMJbI42\\", - \\"☺☃\\": \\"iHMJbI42\\", - \\"⌘⌥\\": \\"iHMJbI42\\", - \\"𝄞♪♩♫♬\\": \\"iHMJbI42\\", - \\"💩\\": \\"iHMJbI42\\", - \\"?\\": \\"iHMJbI42\\", - \\"@\\": \\"iHMJbI42\\", - \\".\\": \\"iHMJbI42\\", - \\":)\\": \\"iHMJbI42\\", - \\"

\\": \\"iHMJbI42\\", - \\"<><<<>><>\\": \\"iHMJbI42\\", - \\"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.\\": \\"iHMJbI42\\", - \\"#\\": \\"iHMJbI42\\", - \\"##\\": \\"iHMJbI42\\", - \\"#.#.#\\": \\"iHMJbI42\\", - \\"_\\": \\"iHMJbI42\\", - \\"{}\\": \\"iHMJbI42\\", - \\"foo.bar\\": \\"iHMJbI42\\", - \\":hover\\": \\"iHMJbI42\\", - \\":hover:focus:active\\": \\"iHMJbI42\\", - \\"[attr=value]\\": \\"iHMJbI42\\", - \\"f/o/o\\": \\"iHMJbI42\\", - \\"f\\\\\\\\o\\\\\\\\o\\": \\"iHMJbI42\\", - \\"f*o*o\\": \\"iHMJbI42\\", - \\"f!o!o\\": \\"iHMJbI42\\", - \\"f'o'o\\": \\"iHMJbI42\\", - \\"f~o~o\\": \\"iHMJbI42\\", - \\"f+o+o\\": \\"iHMJbI42\\", - \\"foo/bar\\": \\"iHMJbI42\\", - \\"foo\\\\\\\\bar\\": \\"iHMJbI42\\", - \\"foo/bar/baz\\": \\"iHMJbI42\\", - \\"foo\\\\\\\\bar\\\\\\\\baz\\": \\"iHMJbI42\\" -}; -export default ___CSS_LOADER_EXPORT___; -" -`; - -exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": result 1`] = ` -Array [ - Array [ - "./modules/localIdentName/localIdentName.css", - ".iHMJbI42 { - background: red; -} - -.iHMJbI42 { - background: blue; -} - -.iHMJbI42 { - background: red; -} - -#iHMJbI42 { - background: green; -} - -.iHMJbI42 .iHMJbI42 { - color: green; -} - -#iHMJbI42 .iHMJbI42 { - color: blue; -} - -.iHMJbI42 { - color: red; -} - -.iHMJbI42 { - margin-left: auto !important; - margin-right: auto !important; -} - -.iHMJbI42 { - margin-left: auto !important; - margin-right: auto !important; -} - -/* matches elements with class=\\":\`(\\" */ -.iHMJbI42 { - color: aqua; -} - -/* matches elements with class=\\"1a2b3c\\" */ -.iHMJbI42 { - color: aliceblue; -} - -/* matches the element with id=\\"#fake-id\\" */ -#iHMJbI42 { - color: antiquewhite; -} - -/* matches the element with id=\\"-a-b-c-\\" */ -#iHMJbI42 { - color: azure; -} - -/* matches the element with id=\\"©\\" */ -#iHMJbI42 { - color: black; -} - -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } -.iHMJbI42 { background: lime; } - -.iHMJbI42 { - background: hotpink; -} - -.iHMJbI42 { - background: hotpink; -} - -.iHMJbI42 { - background: hotpink; -} - -.iHMJbI42 { - background: hotpink; -} -", - "", - ], -] -`; - -exports[`"modules" option should work and respect the "hashStrategy" = "omit-local-name": warnings 1`] = `Array []`; - exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": errors 1`] = `Array []`; exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": module 1`] = ` diff --git a/test/modules-option.test.js b/test/modules-option.test.js index 5731a329..3d862af5 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -401,26 +401,6 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot("errors"); }); - it('should work and respect the "hashStrategy" = "omit-local-name"', async () => { - const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { - modules: { - localIdentName: "[hash:base64:8]", - // localName should not be used even if [local] is absent from the localIdentName template - hashStrategy: "omit-local-name", - }, - }); - const stats = await compile(compiler); - - expect( - getModuleSource("./modules/localIdentName/localIdentName.css", stats) - ).toMatchSnapshot("module"); - expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( - "result" - ); - expect(getWarnings(stats)).toMatchSnapshot("warnings"); - expect(getErrors(stats)).toMatchSnapshot("errors"); - }); - it('should work and respect the "hashStrategy" = "auto" and [local]', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { From 40cb2985c0882ba1f8ae769a8e8edef0c13a5c92 Mon Sep 17 00:00:00 2001 From: Anton Khlynovskiy Date: Fri, 28 Jan 2022 16:28:43 +0300 Subject: [PATCH 3/4] chore: update nanoid version in the lockfile --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 588164b5..69f2af41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11014,9 +11014,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -23850,9 +23850,9 @@ "dev": true }, "nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" }, "natural-compare": { "version": "1.4.0", From 381d470729f54b74657650bb7eea7370ad9f7ad9 Mon Sep 17 00:00:00 2001 From: Anton Khlynovskiy Date: Wed, 2 Feb 2022 13:23:36 +0300 Subject: [PATCH 4/4] feat: do not hash localName if the localName is inlined: rename option values --- README.md | 10 ++++---- src/options.json | 2 +- src/utils.js | 2 +- .../__snapshots__/modules-option.test.js.snap | 24 +++++++++---------- test/modules-option.test.js | 12 +++++----- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 296ba3a9..ec00f7bf 100644 --- a/README.md +++ b/README.md @@ -874,13 +874,13 @@ module.exports = { ##### `hashStrategy` -Type: `'use-local-name' | 'auto'` -Default: `'use-local-name'` +Type: `'resource-path-and-local-name' | 'minimal-subset'` +Default: `'resource-path-and-local-name'` Should local name be used when computing the hash. -- `'use-local-name'` Each identifier in a module gets its own hash digest. -- `'auto'` Identifiers from the same module shares the same hash digest if it's possible. Use this value to optimize the output for better GZIP or Brotli compression. +- `'resource-path-and-local-name'` Both resource path and local name are used when hashing. Each identifier in a module gets its own hash digest, always. +- `'minimal-subset'` Auto detect if identifier names can be omitted from hashing. Use this value to optimize the output for better GZIP or Brotli compression. **webpack.config.js** @@ -893,7 +893,7 @@ module.exports = { loader: "css-loader", options: { modules: { - hashStrategy: "auto", + hashStrategy: "minimal-subset", }, }, }, diff --git a/src/options.json b/src/options.json index a642c037..bb61fb12 100644 --- a/src/options.json +++ b/src/options.json @@ -117,7 +117,7 @@ "hashStrategy": { "description": "Allows to specify should localName be used when computing the hash.", "link": "https://github.com/webpack-contrib/css-loader#hashstrategy", - "enum": ["use-local-name", "auto"] + "enum": ["resource-path-and-local-name", "minimal-subset"] }, "localIdentRegExp": { "description": "Allows to specify custom RegExp for local ident name.", diff --git a/src/utils.js b/src/utils.js index 57c2ac84..020cd370 100644 --- a/src/utils.js +++ b/src/utils.js @@ -338,7 +338,7 @@ function defaultGetLocalIdent( // eslint-disable-next-line no-param-reassign options.content = - hashStrategy === "auto" && /\[local\]/.test(localIdentName) + hashStrategy === "minimal-subset" && /\[local\]/.test(localIdentName) ? relativeResourcePath : `${relativeResourcePath}\x00${localName}`; diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index 20c06962..e52dfe07 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -3397,9 +3397,9 @@ Array [ exports[`"modules" option should work and respect the "hashSalt" option: warnings 1`] = `Array []`; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: errors 1`] = `Array []`; +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and [local]: errors 1`] = `Array []`; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: module 1`] = ` +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and [local]: module 1`] = ` "// Imports import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; @@ -3461,7 +3461,7 @@ export default ___CSS_LOADER_EXPORT___; " `; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: result 1`] = ` +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and [local]: result 1`] = ` Array [ Array [ "./modules/localIdentName/localIdentName.css", @@ -3585,11 +3585,11 @@ Array [ ] `; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and [local]: warnings 1`] = `Array []`; +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and [local]: warnings 1`] = `Array []`; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: errors 1`] = `Array []`; +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and no [local]: errors 1`] = `Array []`; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: module 1`] = ` +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and no [local]: module 1`] = ` "// Imports import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; @@ -3651,7 +3651,7 @@ export default ___CSS_LOADER_EXPORT___; " `; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: result 1`] = ` +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and no [local]: result 1`] = ` Array [ Array [ "./modules/localIdentName/localIdentName.css", @@ -3775,11 +3775,11 @@ Array [ ] `; -exports[`"modules" option should work and respect the "hashStrategy" = "auto" and no [local]: warnings 1`] = `Array []`; +exports[`"modules" option should work and respect the "hashStrategy" = "minimal-subset" and no [local]: warnings 1`] = `Array []`; -exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": errors 1`] = `Array []`; +exports[`"modules" option should work and respect the "hashStrategy" = "resource-path-and-local-name": errors 1`] = `Array []`; -exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": module 1`] = ` +exports[`"modules" option should work and respect the "hashStrategy" = "resource-path-and-local-name": module 1`] = ` "// Imports import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \\"../../../../src/runtime/noSourceMaps.js\\"; import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; @@ -3841,7 +3841,7 @@ export default ___CSS_LOADER_EXPORT___; " `; -exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": result 1`] = ` +exports[`"modules" option should work and respect the "hashStrategy" = "resource-path-and-local-name": result 1`] = ` Array [ Array [ "./modules/localIdentName/localIdentName.css", @@ -3965,7 +3965,7 @@ Array [ ] `; -exports[`"modules" option should work and respect the "hashStrategy" = "use-local-name": warnings 1`] = `Array []`; +exports[`"modules" option should work and respect the "hashStrategy" = "resource-path-and-local-name": warnings 1`] = `Array []`; exports[`"modules" option should work and respect the "localConvention" option with the "asIs" value: errors 1`] = `Array []`; diff --git a/test/modules-option.test.js b/test/modules-option.test.js index 3d862af5..13a21635 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -381,12 +381,12 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot("errors"); }); - it('should work and respect the "hashStrategy" = "use-local-name"', async () => { + it('should work and respect the "hashStrategy" = "resource-path-and-local-name"', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[local]__[hash:base64:8]", // localName should be used even if [local] is contained in the localIdentName template - hashStrategy: "use-local-name", + hashStrategy: "resource-path-and-local-name", }, }); const stats = await compile(compiler); @@ -401,12 +401,12 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot("errors"); }); - it('should work and respect the "hashStrategy" = "auto" and [local]', async () => { + it('should work and respect the "hashStrategy" = "minimal-subset" and [local]', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[local]__[hash:base64:8]", // localName should not be used: [local] is used - hashStrategy: "auto", + hashStrategy: "minimal-subset", }, }); const stats = await compile(compiler); @@ -421,12 +421,12 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot("errors"); }); - it('should work and respect the "hashStrategy" = "auto" and no [local]', async () => { + it('should work and respect the "hashStrategy" = "minimal-subset" and no [local]', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[hash:base64:8]", // localName should be used: [local] is not used - hashStrategy: "auto", + hashStrategy: "minimal-subset", }, }); const stats = await compile(compiler);