diff --git a/README.md b/README.md index 57c86b33..57d213dd 100644 --- a/README.md +++ b/README.md @@ -487,6 +487,15 @@ To import a local classname from another module. To import from multiple modules use multiple `composes:` rules. +```css +:local(.className) { + composes: edit highlight from "./edit.css", button from "module/button.css", classFromThisModule; + background: red; +} +``` + +or + ```css :local(.className) { composes: edit highlight from "./edit.css"; diff --git a/package-lock.json b/package-lock.json index 672d6c2b..3786e3f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-extract-imports": "^3.1.0", "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.1.2", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.5.4" @@ -13015,9 +13015,9 @@ } }, "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -13042,9 +13042,9 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.2.tgz", - "integrity": "sha512-hHTYdjVmywC2TAmz134e9M4WZ6i9bh9OoHD8l2qVqc/fXxti1+4UDfZ+Pw/WCdkNIi811eJiTQ+RsfTFEuAjXw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -25512,9 +25512,9 @@ "requires": {} }, "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "requires": {} }, "postcss-modules-local-by-default": { @@ -25528,9 +25528,9 @@ } }, "postcss-modules-scope": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.2.tgz", - "integrity": "sha512-hHTYdjVmywC2TAmz134e9M4WZ6i9bh9OoHD8l2qVqc/fXxti1+4UDfZ+Pw/WCdkNIi811eJiTQ+RsfTFEuAjXw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "requires": { "postcss-selector-parser": "^6.0.4" } diff --git a/package.json b/package.json index bd9674d8..fd71a2b5 100644 --- a/package.json +++ b/package.json @@ -57,9 +57,9 @@ "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-extract-imports": "^3.1.0", "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.1.2", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.5.4" diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index ae599c55..97cc528f 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -21031,6 +21031,123 @@ Array [ exports[`"modules" option should work with global compose: warnings 1`] = `Array []`; +exports[`"modules" option should work with multiple compose: errors 1`] = `Array []`; + +exports[`"modules" option should work with multiple compose: 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\\"; +import ___CSS_LOADER_ICSS_IMPORT_0___ from \\"-!../../../../src/index.js??ruleSet[1].rules[0].use[0]!./alias.css\\"; +import ___CSS_LOADER_ICSS_IMPORT_1___ from \\"-!../../../../src/index.js??ruleSet[1].rules[0].use[0]!./alias-1.css\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___); +___CSS_LOADER_EXPORT___.i(___CSS_LOADER_ICSS_IMPORT_0___, \\"\\", true); +___CSS_LOADER_EXPORT___.i(___CSS_LOADER_ICSS_IMPORT_1___, \\"\\", true); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \`.RsClSIMkfTMmUvwYT4aD { + color: red; +} + +.OdpZEdUc2oHF96Xqdoba { + color: blue; +} + +.A3lCTIjOyIaMw91SUTt_ { + color: blue; +} + +.global-class { + padding: 10px; +} + +.global-class-1 { + padding: 10px; +} + +.global-class-2 { + padding: 10px; +} + +.BwiLdQraIwYyRAA53QEQ { + color: gainsboro; +} + +.DemABT8Zz2xVnnu848uO { +} +\`, \\"\\"]); +// Exports +___CSS_LOADER_EXPORT___.locals = { + \\"other-class\\": \`RsClSIMkfTMmUvwYT4aD\`, + \\"class-1\\": \`OdpZEdUc2oHF96Xqdoba\`, + \\"class-2\\": \`A3lCTIjOyIaMw91SUTt_\`, + \\"class\\": \`BwiLdQraIwYyRAA53QEQ RsClSIMkfTMmUvwYT4aD OdpZEdUc2oHF96Xqdoba A3lCTIjOyIaMw91SUTt_ \${___CSS_LOADER_ICSS_IMPORT_0___.locals[\\"imported-alias\\"]} \${___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"imported-alias-2\\"]} \${___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"imported-alias-3\\"]} global-class global-class-1 global-class-2\`, + \\"class-other\\": \`DemABT8Zz2xVnnu848uO RsClSIMkfTMmUvwYT4aD OdpZEdUc2oHF96Xqdoba\` +}; +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"modules" option should work with multiple compose: result 1`] = ` +Array [ + Array [ + "../../src/index.js??ruleSet[1].rules[0].use[0]!./modules/composes/alias.css", + ".dnhKs1AYKq4KodZdfzcx { + display: table; +} +", + "", + ], + Array [ + "../../src/index.js??ruleSet[1].rules[0].use[0]!./modules/composes/alias-1.css", + ".Lg5UPByIZH1XWiASCk_q { + background: red; +} + +.QllkotlwlKJ4pFhiIzqP { + background: red; +} +", + "", + ], + Array [ + "./modules/composes/multiple.css", + ".RsClSIMkfTMmUvwYT4aD { + color: red; +} + +.OdpZEdUc2oHF96Xqdoba { + color: blue; +} + +.A3lCTIjOyIaMw91SUTt_ { + color: blue; +} + +.global-class { + padding: 10px; +} + +.global-class-1 { + padding: 10px; +} + +.global-class-2 { + padding: 10px; +} + +.BwiLdQraIwYyRAA53QEQ { + color: gainsboro; +} + +.DemABT8Zz2xVnnu848uO { +} +", + "", + ], +] +`; + +exports[`"modules" option should work with multiple compose: warnings 1`] = `Array []`; + exports[`"modules" option should work with the "[local]" placeholder for the "localIdentName" option: errors 1`] = `Array []`; exports[`"modules" option should work with the "[local]" placeholder for the "localIdentName" option: module 1`] = ` diff --git a/test/fixtures/modules/composes/alias-1.css b/test/fixtures/modules/composes/alias-1.css new file mode 100644 index 00000000..80cba29a --- /dev/null +++ b/test/fixtures/modules/composes/alias-1.css @@ -0,0 +1,7 @@ +.imported-alias-2 { + background: red; +} + +.imported-alias-3 { + background: red; +} diff --git a/test/fixtures/modules/composes/multiple.css b/test/fixtures/modules/composes/multiple.css new file mode 100644 index 00000000..3520c43e --- /dev/null +++ b/test/fixtures/modules/composes/multiple.css @@ -0,0 +1,38 @@ +.other-class { + color: red; +} + +.class-1 { + color: blue; +} + +.class-2 { + color: blue; +} + +:global(.global-class) { + padding: 10px; +} + +:global(.global-class-1) { + padding: 10px; +} + +:global(.global-class-2) { + padding: 10px; +} + +.class { + composes: + other-class, + class-1 class-2, + imported-alias from './alias.css', + imported-alias-2 imported-alias-3 from './alias-1.css', + global-class from global, + global-class-1 global-class-2 from global; + color: gainsboro; +} + +.class-other { + composes: other-class class-1; +} diff --git a/test/fixtures/modules/composes/multiple.js b/test/fixtures/modules/composes/multiple.js new file mode 100644 index 00000000..63f5814e --- /dev/null +++ b/test/fixtures/modules/composes/multiple.js @@ -0,0 +1,5 @@ +import css from './multiple.css'; + +__export__ = css; + +export default css; diff --git a/test/modules-option.test.js b/test/modules-option.test.js index 9529312b..06b7d708 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -2433,4 +2433,20 @@ describe('"modules" option', () => { expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); + + it("should work with multiple compose", async () => { + const compiler = getCompiler("./modules/composes/multiple.js", { + modules: true, + }); + const stats = await compile(compiler); + + expect( + getModuleSource("./modules/composes/multiple.css", stats) + ).toMatchSnapshot("module"); + expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( + "result" + ); + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + expect(getErrors(stats)).toMatchSnapshot("errors"); + }); });