From f93ad2a8f0f5f048bfbd2bad9ba3237d30e323af Mon Sep 17 00:00:00 2001 From: Nic <162764842+Nic-Polumeyv@users.noreply.github.com> Date: Fri, 17 Jul 2026 20:45:48 -0400 Subject: [PATCH] Allow skipping only same-file duplicates with skipDuplicates: "same-file", fixes #601 --- README.md | 7 ++++++- lib/parse-styles.js | 5 +++-- test/fixtures/imports/same-file-dedup/a/shared.css | 1 + test/fixtures/imports/same-file-dedup/b/shared.css | 1 + test/fixtures/same-file-dedup.css | 3 +++ test/fixtures/same-file-dedup.expected.css | 2 ++ test/import.js | 9 +++++++++ 7 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/imports/same-file-dedup/a/shared.css create mode 100644 test/fixtures/imports/same-file-dedup/b/shared.css create mode 100644 test/fixtures/same-file-dedup.css create mode 100644 test/fixtures/same-file-dedup.expected.css diff --git a/README.md b/README.md index 9c96cf2..0bf2617 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ promised content. #### `skipDuplicates` -Type: `Boolean` +Type: `Boolean` or `"same-file"` Default: `true` By default, similar files (based on the same content) are being skipped. @@ -188,6 +188,11 @@ It's to optimize output and skip similar files like `normalize.css` for example. If this behavior is not what you want, just set this option to `false` to disable it. +Setting this option to `"same-file"` skips repeated imports of the same file, +but not different files sharing the same content. Use it when imported files +contain at-rules whose paths resolve relative to the file's own location, so +that byte-identical files at different paths are not actually duplicates. + #### `addModulesDirectories` Type: `Array` diff --git a/lib/parse-styles.js b/lib/parse-styles.js index 766de9c..ec0e44b 100644 --- a/lib/parse-styles.js +++ b/lib/parse-styles.js @@ -178,8 +178,9 @@ async function loadImportContent( } // skip previous imported files not containing @import rules + // (content dedup does not apply in "same-file" mode) if ( - options.skipDuplicates && + options.skipDuplicates === true && state.hashFiles[content]?.[stmtDuplicateCheckKey] ) { return @@ -196,7 +197,7 @@ async function loadImportContent( const styles = importedResult.root result.messages = result.messages.concat(importedResult.messages) - if (options.skipDuplicates) { + if (options.skipDuplicates === true) { const hasImport = styles.some(child => { return child.type === "atrule" && child.name === "import" }) diff --git a/test/fixtures/imports/same-file-dedup/a/shared.css b/test/fixtures/imports/same-file-dedup/a/shared.css new file mode 100644 index 0000000..6abac48 --- /dev/null +++ b/test/fixtures/imports/same-file-dedup/a/shared.css @@ -0,0 +1 @@ +shared {} diff --git a/test/fixtures/imports/same-file-dedup/b/shared.css b/test/fixtures/imports/same-file-dedup/b/shared.css new file mode 100644 index 0000000..6abac48 --- /dev/null +++ b/test/fixtures/imports/same-file-dedup/b/shared.css @@ -0,0 +1 @@ +shared {} diff --git a/test/fixtures/same-file-dedup.css b/test/fixtures/same-file-dedup.css new file mode 100644 index 0000000..ef02919 --- /dev/null +++ b/test/fixtures/same-file-dedup.css @@ -0,0 +1,3 @@ +@import "same-file-dedup/a/shared.css"; +@import "same-file-dedup/b/shared.css"; +@import "same-file-dedup/a/shared.css"; diff --git a/test/fixtures/same-file-dedup.expected.css b/test/fixtures/same-file-dedup.expected.css new file mode 100644 index 0000000..572363e --- /dev/null +++ b/test/fixtures/same-file-dedup.expected.css @@ -0,0 +1,2 @@ +shared {} +shared {} diff --git a/test/import.js b/test/import.js index e2a2bd1..6fc22c5 100644 --- a/test/import.js +++ b/test/import.js @@ -46,6 +46,15 @@ test( test("should import stylesheets with same content", checkFixture, "same") +test( + "should only skip same-file duplicates with skipDuplicates: same-file", + checkFixture, + "same-file-dedup", + { + skipDuplicates: "same-file", + }, +) + test("should ignore & adjust external import", checkFixture, "ignore") test("should not fail with only one absolute import", t => {