From ebf8eb4d956cf2beba9c3d009af1353caadb6e63 Mon Sep 17 00:00:00 2001 From: Yukimasa Funaoka Date: Mon, 11 Aug 2025 20:38:16 +0900 Subject: [PATCH 1/2] feat: support [folder] template strings in localIdentName option --- crates/rspack_plugin_css/src/utils.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/rspack_plugin_css/src/utils.rs b/crates/rspack_plugin_css/src/utils.rs index 18fbc3ea8f6a..a2cd26ac1074 100644 --- a/crates/rspack_plugin_css/src/utils.rs +++ b/crates/rspack_plugin_css/src/utils.rs @@ -2,6 +2,7 @@ use std::{ borrow::Cow, fmt::Write, hash::Hasher, + path::Path, sync::{Arc, LazyLock}, }; @@ -85,6 +86,11 @@ impl<'a> LocalIdentOptions<'a> { )), local, unique_name: &output.unique_name, + folder: Path::new(&self.relative_resource) + .parent() + .and_then(|p| p.file_name()) + .and_then(|s| s.to_str()) + .unwrap_or(""), } .render_local_ident_name(self.local_name_ident) .await @@ -95,6 +101,7 @@ struct LocalIdentNameRenderOptions<'a> { path_data: PathData<'a>, local: &'a str, unique_name: &'a str, + folder: &'a str, } impl LocalIdentNameRenderOptions<'_> { @@ -108,6 +115,7 @@ impl LocalIdentNameRenderOptions<'_> { Ok( s.cow_replace("[uniqueName]", self.unique_name) .cow_replace("[local]", self.local) + .cow_replace("[folder]", self.folder) .into_owned(), ) } From 74962e0b3f7373ac5c12ed98f7542e5341580446 Mon Sep 17 00:00:00 2001 From: Yukimasa Funaoka Date: Tue, 12 Aug 2025 20:41:07 +0900 Subject: [PATCH 2/2] chore: add tests --- .../ConfigTestCases.basictest.js.snap | 60 ++++++++++++++++--- .../configCases/css/local-ident-name/index.js | 17 +++++- .../nested1/nested2/style.module.css | 25 ++++++++ .../css/local-ident-name/test.config.js | 2 + .../css/local-ident-name/webpack.config.js | 6 ++ 5 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 tests/webpack-test/configCases/css/local-ident-name/nested1/nested2/style.module.css diff --git a/tests/webpack-test/__snapshots__/ConfigTestCases.basictest.js.snap b/tests/webpack-test/__snapshots__/ConfigTestCases.basictest.js.snap index 5bbec0b44f6c..587d44be2deb 100644 --- a/tests/webpack-test/__snapshots__/ConfigTestCases.basictest.js.snap +++ b/tests/webpack-test/__snapshots__/ConfigTestCases.basictest.js.snap @@ -530,6 +530,28 @@ Object { `; exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 8`] = ` +Object { + "btn--info_is-disabled_1": "-btn--info_is-disabled_1", + "btn-info_is-disabled": "-btn-info_is-disabled", + "foo": "bar", + "foo_bar": "-foo_bar", + "my-btn-info_is-disabled": "value", + "simple": "-simple", +} +`; + +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 9`] = ` +Object { + "btn--info_is-disabled_1": "nested2-btn--info_is-disabled_1", + "btn-info_is-disabled": "nested2-btn-info_is-disabled", + "foo": "bar", + "foo_bar": "nested2-foo_bar", + "my-btn-info_is-disabled": "value", + "simple": "nested2-simple", +} +`; + +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 10`] = ` Object { "btn--info_is-disabled_1": "./style.module.less__btn--info_is-disabled_1", "btn-info_is-disabled": "./style.module.less__btn-info_is-disabled", @@ -540,7 +562,7 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 9`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 11`] = ` Object { "btn--info_is-disabled_1": "_style_module_css-btn--info_is-disabled_1", "btn-info_is-disabled": "_style_module_css-btn-info_is-disabled", @@ -551,7 +573,7 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 10`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 12`] = ` Object { "btn--info_is-disabled_1": "feb1ff69382c6202", "btn-info_is-disabled": "f9df66ace1f48520", @@ -562,7 +584,7 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 11`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 13`] = ` Object { "btn--info_is-disabled_1": "_6fc78548db75122e-btn--info_is-disabled_1", "btn-info_is-disabled": "_6fc78548db75122e-btn-info_is-disabled", @@ -573,7 +595,7 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 12`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 14`] = ` Object { "btn--info_is-disabled_1": "./style.module__btn--info_is-disabled_1", "btn-info_is-disabled": "./style.module__btn-info_is-disabled", @@ -584,7 +606,7 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 13`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 15`] = ` Object { "btn--info_is-disabled_1": "./style.module.css__btn--info_is-disabled_1", "btn-info_is-disabled": "./style.module.css__btn-info_is-disabled", @@ -595,7 +617,7 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 14`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 16`] = ` Object { "btn--info_is-disabled_1": "./style.module.css?q#f__btn--info_is-disabled_1", "btn-info_is-disabled": "./style.module.css?q#f__btn-info_is-disabled", @@ -606,7 +628,7 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 15`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 17`] = ` Object { "btn--info_is-disabled_1": "-_style_module_css_uniqueName-id-contenthash-[contenthash]", "btn-info_is-disabled": "-_style_module_css_uniqueName-id-contenthash-[contenthash]", @@ -617,7 +639,29 @@ Object { } `; -exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 16`] = ` +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 18`] = ` +Object { + "btn--info_is-disabled_1": "-btn--info_is-disabled_1", + "btn-info_is-disabled": "-btn-info_is-disabled", + "foo": "bar", + "foo_bar": "-foo_bar", + "my-btn-info_is-disabled": "value", + "simple": "-simple", +} +`; + +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 19`] = ` +Object { + "btn--info_is-disabled_1": "nested2-btn--info_is-disabled_1", + "btn-info_is-disabled": "nested2-btn-info_is-disabled", + "foo": "bar", + "foo_bar": "nested2-foo_bar", + "my-btn-info_is-disabled": "value", + "simple": "nested2-simple", +} +`; + +exports[`ConfigTestCases css local-ident-name exported tests should have correct local ident for css export locals 20`] = ` Object { "btn--info_is-disabled_1": "./style.module.less__btn--info_is-disabled_1", "btn-info_is-disabled": "./style.module.less__btn-info_is-disabled", diff --git a/tests/webpack-test/configCases/css/local-ident-name/index.js b/tests/webpack-test/configCases/css/local-ident-name/index.js index 816c494697a6..6645a8aea7f8 100644 --- a/tests/webpack-test/configCases/css/local-ident-name/index.js +++ b/tests/webpack-test/configCases/css/local-ident-name/index.js @@ -7,8 +7,21 @@ it("should have correct local ident for css export locals", (done) => { import("./style.module.css?file-local"), import("./style.module.css?q#f"), import("./style.module.css?uniqueName-id-contenthash"), + import("./style.module.css?folder-local"), + import("./nested1/nested2/style.module.css?folder-local"), import("./style.module.less"), - ]).then(([idLocal, hash, hashLocal, pathNameLocal, fileLocal, queryFragment, uniqueNameIdContenthash, less]) => { + ]).then(([ + idLocal, + hash, + hashLocal, + pathNameLocal, + fileLocal, + queryFragment, + uniqueNameIdContenthash, + folderLocalRoot, + folderLocal, + less + ]) => { expect(idLocal).toMatchSnapshot(); expect(hash).toMatchSnapshot(); expect(hashLocal).toMatchSnapshot(); @@ -16,6 +29,8 @@ it("should have correct local ident for css export locals", (done) => { expect(fileLocal).toMatchSnapshot(); expect(queryFragment).toMatchSnapshot(); expect(uniqueNameIdContenthash).toMatchSnapshot(); + expect(folderLocalRoot).toMatchSnapshot(); + expect(folderLocal).toMatchSnapshot(); expect(less).toMatchSnapshot(); done() }).catch(done) diff --git a/tests/webpack-test/configCases/css/local-ident-name/nested1/nested2/style.module.css b/tests/webpack-test/configCases/css/local-ident-name/nested1/nested2/style.module.css new file mode 100644 index 000000000000..864a29382e04 --- /dev/null +++ b/tests/webpack-test/configCases/css/local-ident-name/nested1/nested2/style.module.css @@ -0,0 +1,25 @@ +.btn-info_is-disabled { + color: blue; +} + +.btn--info_is-disabled_1 { + color: blue; +} + +.simple { + color: red; +} + +a { + color: yellow; +} + +:export { + foo: bar; + my-btn-info_is-disabled: value; +} + +.foo_bar { + --color-red: red; + color: var(--color-red); +} diff --git a/tests/webpack-test/configCases/css/local-ident-name/test.config.js b/tests/webpack-test/configCases/css/local-ident-name/test.config.js index 97c3e830c498..6476817c1b9c 100644 --- a/tests/webpack-test/configCases/css/local-ident-name/test.config.js +++ b/tests/webpack-test/configCases/css/local-ident-name/test.config.js @@ -8,6 +8,8 @@ module.exports = { `style_module_css_file-local.bundle${i}.js`, `style_module_css_q_f.bundle${i}.js`, `style_module_css_uniqueName-id-contenthash.bundle${i}.js`, + `style_module_css_folder-local.bundle${i}.js`, + `nested1_nested2_style_module_css_folder-local.bundle${i}.js`, `style_module_less.bundle${i}.js`, `bundle${i}.js` ]; diff --git a/tests/webpack-test/configCases/css/local-ident-name/webpack.config.js b/tests/webpack-test/configCases/css/local-ident-name/webpack.config.js index c043998da636..9a4f927d47c5 100644 --- a/tests/webpack-test/configCases/css/local-ident-name/webpack.config.js +++ b/tests/webpack-test/configCases/css/local-ident-name/webpack.config.js @@ -50,6 +50,12 @@ const common = { generator: { localIdentName: "[uniqueName]-[id]-[contenthash]" } + }, + { + resourceQuery: /\?folder-local$/, + generator: { + localIdentName: "[folder]-[local]" + } } ] }