From 9af465e598b51f933ac15baeab09caf086c3083b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:49:52 -0400 Subject: [PATCH 01/10] Update dependency prettier to ~3.3.0 (#564) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b5bde2..4464631 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "eslint-plugin-prettier": "^5.0.0", "postcss": "^8.0.0", "postcss-scss": "^4.0.0", - "prettier": "~3.2.0", + "prettier": "~3.3.0", "sugarss": "^4.0.0" }, "peerDependencies": { From d43ca1506d65d9943a3c4bb885aff94dc809d69c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:33:57 -0500 Subject: [PATCH 02/10] Update dependency prettier to ~3.4.0 (#569) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4464631..b4b2e9e 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "eslint-plugin-prettier": "^5.0.0", "postcss": "^8.0.0", "postcss-scss": "^4.0.0", - "prettier": "~3.3.0", + "prettier": "~3.4.0", "sugarss": "^4.0.0" }, "peerDependencies": { From 32deb082c687c0d324e5812b3593f7e44af10166 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 14:42:05 -0400 Subject: [PATCH 03/10] Update dependency c8 to v10 (#565) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b4b2e9e..3a8fa1e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "ava": "^6.0.0", - "c8": "^9.0.0", + "c8": "^10.0.0", "eslint": "^8.27.0", "eslint-config-problems": "^8.0.0", "eslint-plugin-prettier": "^5.0.0", From cad00220bf02f881be6475e943c499906b623241 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 14:42:26 -0400 Subject: [PATCH 04/10] Update dependency sugarss to v5 (#568) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a8fa1e..2203501 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "postcss": "^8.0.0", "postcss-scss": "^4.0.0", "prettier": "~3.4.0", - "sugarss": "^4.0.0" + "sugarss": "^5.0.0" }, "peerDependencies": { "postcss": "^8.0.0" From 83108aa207e96eeac159dde08e2153cddeb7172e Mon Sep 17 00:00:00 2001 From: Romain Menke <11521496+romainmenke@users.noreply.github.com> Date: Sat, 7 Jun 2025 20:47:00 +0200 Subject: [PATCH 05/10] Fix incorrect cascade layer order when some resources can not be inlined (#574) --- lib/apply-conditions.js | 45 ++++++++++++++++--- lib/apply-styles.js | 2 +- lib/base64-encoded-import.js | 2 + lib/parse-statements.js | 18 ++++++++ lib/parse-styles.js | 13 ++++-- .../imports/layer-followed-by-ignore.css | 4 ++ test/fixtures/imports/layer-only.css | 1 + ...yer-followed-by-ignore-with-conditions.css | 2 + ...wed-by-ignore-with-conditions.expected.css | 6 +++ ...-followed-by-ignore-without-conditions.css | 3 ++ ...-by-ignore-without-conditions.expected.css | 3 ++ test/fixtures/layer-followed-by-ignore.css | 2 + .../layer-followed-by-ignore.expected.css | 2 + .../layer-statement-with-conditions.css | 1 + ...yer-statement-with-conditions.expected.css | 3 ++ test/layer.js | 24 ++++++++++ 16 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 test/fixtures/imports/layer-followed-by-ignore.css create mode 100644 test/fixtures/imports/layer-only.css create mode 100644 test/fixtures/layer-followed-by-ignore-with-conditions.css create mode 100644 test/fixtures/layer-followed-by-ignore-with-conditions.expected.css create mode 100644 test/fixtures/layer-followed-by-ignore-without-conditions.css create mode 100644 test/fixtures/layer-followed-by-ignore-without-conditions.expected.css create mode 100644 test/fixtures/layer-followed-by-ignore.css create mode 100644 test/fixtures/layer-followed-by-ignore.expected.css create mode 100644 test/fixtures/layer-statement-with-conditions.css create mode 100644 test/fixtures/layer-statement-with-conditions.expected.css diff --git a/lib/apply-conditions.js b/lib/apply-conditions.js index 76a8475..2005c6b 100644 --- a/lib/apply-conditions.js +++ b/lib/apply-conditions.js @@ -3,12 +3,38 @@ const base64EncodedConditionalImport = require("./base64-encoded-import") module.exports = function applyConditions(bundle, atRule) { - bundle.forEach(stmt => { + const firstImportStatementIndex = bundle.findIndex( + stmt => stmt.type === "import", + ) + const lastImportStatementIndex = bundle.findLastIndex( + stmt => stmt.type === "import", + ) + + bundle.forEach((stmt, index) => { + if (stmt.type === "charset" || stmt.type === "warning") { + return + } + if ( - stmt.type === "charset" || - stmt.type === "warning" || - !stmt.conditions?.length + stmt.type === "layer" && + ((index < lastImportStatementIndex && stmt.conditions?.length) || + (index > firstImportStatementIndex && index < lastImportStatementIndex)) ) { + stmt.type = "import" + stmt.node = stmt.node.clone({ + name: "import", + params: base64EncodedConditionalImport( + `'data:text/css;base64,${Buffer.from(stmt.node.toString()).toString( + "base64", + )}'`, + stmt.conditions, + ), + }) + + return + } + + if (!stmt.conditions?.length) { return } @@ -20,8 +46,15 @@ module.exports = function applyConditions(bundle, atRule) { return } - const { nodes } = stmt - const { parent } = nodes[0] + let nodes + let parent + if (stmt.type === "layer") { + nodes = [stmt.node] + parent = stmt.node.parent + } else { + nodes = stmt.nodes + parent = nodes[0].parent + } const atRules = [] diff --git a/lib/apply-styles.js b/lib/apply-styles.js index ca961b1..a92e7ff 100644 --- a/lib/apply-styles.js +++ b/lib/apply-styles.js @@ -5,7 +5,7 @@ module.exports = function applyStyles(bundle, styles) { // Strip additional statements. bundle.forEach(stmt => { - if (["charset", "import"].includes(stmt.type)) { + if (["charset", "import", "layer"].includes(stmt.type)) { stmt.node.parent = undefined styles.append(stmt.node) } else if (stmt.type === "nodes") { diff --git a/lib/base64-encoded-import.js b/lib/base64-encoded-import.js index a928c62..5e49779 100644 --- a/lib/base64-encoded-import.js +++ b/lib/base64-encoded-import.js @@ -8,6 +8,8 @@ const formatImportPrelude = require("./format-import-prelude") // To achieve this we create a list of base64 encoded imports, where each import contains a stylesheet with another import. // Each import can define a single group of conditions and a single cascade layer. module.exports = function base64EncodedConditionalImport(prelude, conditions) { + if (!conditions?.length) return prelude + conditions.reverse() const first = conditions.pop() let params = `${prelude} ${formatImportPrelude( diff --git a/lib/parse-statements.js b/lib/parse-statements.js index 788193a..3df0bad 100644 --- a/lib/parse-statements.js +++ b/lib/parse-statements.js @@ -9,6 +9,7 @@ const { stringify } = valueParser module.exports = function parseStatements(result, styles, conditions, from) { const statements = [] let nodes = [] + let encounteredNonImportNodes = false styles.each(node => { let stmt @@ -17,6 +18,14 @@ module.exports = function parseStatements(result, styles, conditions, from) { stmt = parseImport(result, node, conditions, from) else if (node.name === "charset") stmt = parseCharset(result, node, conditions, from) + else if ( + node.name === "layer" && + !encounteredNonImportNodes && + !node.nodes + ) + stmt = parseLayer(result, node, conditions, from) + } else if (node.type !== "comment") { + encounteredNonImportNodes = true } if (stmt) { @@ -233,3 +242,12 @@ function parseImport(result, atRule, conditions, from) { return stmt } + +function parseLayer(result, atRule, conditions, from) { + return { + type: "layer", + node: atRule, + conditions: [...conditions], + from, + } +} diff --git a/lib/parse-styles.js b/lib/parse-styles.js index 9dd43d7..766de9c 100644 --- a/lib/parse-styles.js +++ b/lib/parse-styles.js @@ -33,7 +33,7 @@ async function parseStyles( } let charset - const imports = [] + const beforeBundle = [] const bundle = [] function handleCharset(stmt) { @@ -56,19 +56,24 @@ async function parseStyles( else if (stmt.type === "import") { if (stmt.children) { stmt.children.forEach((child, index) => { - if (child.type === "import") imports.push(child) + if (child.type === "import") beforeBundle.push(child) + else if (child.type === "layer") beforeBundle.push(child) else if (child.type === "charset") handleCharset(child) else bundle.push(child) // For better output if (index === 0) child.parent = stmt }) - } else imports.push(stmt) + } else beforeBundle.push(stmt) + } else if (stmt.type === "layer") { + beforeBundle.push(stmt) } else if (stmt.type === "nodes") { bundle.push(stmt) } }) - return charset ? [charset, ...imports.concat(bundle)] : imports.concat(bundle) + return charset + ? [charset, ...beforeBundle.concat(bundle)] + : beforeBundle.concat(bundle) } async function resolveImportId(result, stmt, options, state, postcss) { diff --git a/test/fixtures/imports/layer-followed-by-ignore.css b/test/fixtures/imports/layer-followed-by-ignore.css new file mode 100644 index 0000000..13f9646 --- /dev/null +++ b/test/fixtures/imports/layer-followed-by-ignore.css @@ -0,0 +1,4 @@ +/* a comment */ + +@layer layer-alpha; +@import "http://css"; diff --git a/test/fixtures/imports/layer-only.css b/test/fixtures/imports/layer-only.css new file mode 100644 index 0000000..9dc1acc --- /dev/null +++ b/test/fixtures/imports/layer-only.css @@ -0,0 +1 @@ +@layer layer-beta; diff --git a/test/fixtures/layer-followed-by-ignore-with-conditions.css b/test/fixtures/layer-followed-by-ignore-with-conditions.css new file mode 100644 index 0000000..e5cf2e5 --- /dev/null +++ b/test/fixtures/layer-followed-by-ignore-with-conditions.css @@ -0,0 +1,2 @@ +@import "layer-only.css" print; +@import "layer-followed-by-ignore.css" screen; diff --git a/test/fixtures/layer-followed-by-ignore-with-conditions.expected.css b/test/fixtures/layer-followed-by-ignore-with-conditions.expected.css new file mode 100644 index 0000000..3d1a219 --- /dev/null +++ b/test/fixtures/layer-followed-by-ignore-with-conditions.expected.css @@ -0,0 +1,6 @@ +@import 'data:text/css;base64,QGxheWVyIGxheWVyLWJldGE=' print; +@import 'data:text/css;base64,QGxheWVyIGxheWVyLWFscGhh' screen; +@import "http://css" screen; +@media screen{ +/* a comment */ +} diff --git a/test/fixtures/layer-followed-by-ignore-without-conditions.css b/test/fixtures/layer-followed-by-ignore-without-conditions.css new file mode 100644 index 0000000..6b48f60 --- /dev/null +++ b/test/fixtures/layer-followed-by-ignore-without-conditions.css @@ -0,0 +1,3 @@ +@import "http://css-a"; +@import url("layer-only.css"); +@import "http://css-b"; diff --git a/test/fixtures/layer-followed-by-ignore-without-conditions.expected.css b/test/fixtures/layer-followed-by-ignore-without-conditions.expected.css new file mode 100644 index 0000000..6e8818a --- /dev/null +++ b/test/fixtures/layer-followed-by-ignore-without-conditions.expected.css @@ -0,0 +1,3 @@ +@import "http://css-a"; +@import 'data:text/css;base64,QGxheWVyIGxheWVyLWJldGE='; +@import "http://css-b"; diff --git a/test/fixtures/layer-followed-by-ignore.css b/test/fixtures/layer-followed-by-ignore.css new file mode 100644 index 0000000..1c4c793 --- /dev/null +++ b/test/fixtures/layer-followed-by-ignore.css @@ -0,0 +1,2 @@ +@layer layer-alpha; +@import "http://css"; diff --git a/test/fixtures/layer-followed-by-ignore.expected.css b/test/fixtures/layer-followed-by-ignore.expected.css new file mode 100644 index 0000000..1c4c793 --- /dev/null +++ b/test/fixtures/layer-followed-by-ignore.expected.css @@ -0,0 +1,2 @@ +@layer layer-alpha; +@import "http://css"; diff --git a/test/fixtures/layer-statement-with-conditions.css b/test/fixtures/layer-statement-with-conditions.css new file mode 100644 index 0000000..2256df4 --- /dev/null +++ b/test/fixtures/layer-statement-with-conditions.css @@ -0,0 +1 @@ +@import "layer-only.css" print; diff --git a/test/fixtures/layer-statement-with-conditions.expected.css b/test/fixtures/layer-statement-with-conditions.expected.css new file mode 100644 index 0000000..9f57df6 --- /dev/null +++ b/test/fixtures/layer-statement-with-conditions.expected.css @@ -0,0 +1,3 @@ +@media print{ +@layer layer-beta +} diff --git a/test/layer.js b/test/layer.js index c80cc32..52236a6 100644 --- a/test/layer.js +++ b/test/layer.js @@ -33,3 +33,27 @@ test( checkFixture, "layer-duplicate-anonymous-imports-skip", ) + +test( + "should correctly handle layer statements followed by ignored imports", + checkFixture, + "layer-followed-by-ignore", +) + +test( + "should correctly handle layer statements followed by ignored imports in conditional imports", + checkFixture, + "layer-followed-by-ignore-with-conditions", +) + +test( + "should correctly handle layer statements followed by ignored imports in unconditional imports", + checkFixture, + "layer-followed-by-ignore-without-conditions", +) + +test( + "should correctly handle layer statements in conditional imports", + checkFixture, + "layer-statement-with-conditions", +) From 25441554913ca9f4f8469636ef7001d9cdbdb832 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 14:47:17 -0400 Subject: [PATCH 06/10] Update dependency prettier to ~3.5.0 (#572) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2203501..6c61d3e 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "eslint-plugin-prettier": "^5.0.0", "postcss": "^8.0.0", "postcss-scss": "^4.0.0", - "prettier": "~3.4.0", + "prettier": "~3.5.0", "sugarss": "^5.0.0" }, "peerDependencies": { From 92276420402a400566f30d7b494f8b51ef76b0f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 15:10:32 -0400 Subject: [PATCH 07/10] Migrate config renovate.json (#575) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index a513283..98372bf 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,6 @@ { "extends": [ - "config:base", + "config:recommended", ":preserveSemverRanges", ":label(deps)" ] From 10325fc02498da689d3c6f2821c6448c6064831c Mon Sep 17 00:00:00 2001 From: Ryan Zimmerman Date: Mon, 9 Jun 2025 10:57:52 -0400 Subject: [PATCH 08/10] Upgrade eslint & config; use flat config (#576) --- eslint.config.js | 27 +++++++++++++++++++++++++++ package.json | 23 +++-------------------- 2 files changed, 30 insertions(+), 20 deletions(-) create mode 100644 eslint.config.js diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..0398af2 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,27 @@ +"use strict" + +const problems = require("eslint-config-problems") +const prettier = require("eslint-plugin-prettier") +const globals = require("globals") + +module.exports = [ + problems, + { + languageOptions: { + globals: { + ...globals.node, + }, + sourceType: "commonjs", + }, + plugins: { prettier }, + rules: { + "prettier/prettier": [ + "error", + { + semi: false, + arrowParens: "avoid", + }, + ], + }, + }, +] diff --git a/package.json b/package.json index 6c61d3e..363aea5 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,10 @@ "devDependencies": { "ava": "^6.0.0", "c8": "^10.0.0", - "eslint": "^8.27.0", - "eslint-config-problems": "^8.0.0", + "eslint": "^9.28.0", + "eslint-config-problems": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", + "globals": "^16.2.0", "postcss": "^8.0.0", "postcss-scss": "^4.0.0", "prettier": "~3.5.0", @@ -44,23 +45,5 @@ "lint": "eslint . --fix", "pretest": "npm run lint", "test": "c8 ava" - }, - "eslintConfig": { - "extends": "eslint-config-problems", - "env": { - "node": true - }, - "plugins": [ - "prettier" - ], - "rules": { - "prettier/prettier": [ - "error", - { - "semi": false, - "arrowParens": "avoid" - } - ] - } } } From a3f38897da54e61bcb4a34484dc6a6c0543134bc Mon Sep 17 00:00:00 2001 From: Ryan Zimmerman Date: Mon, 9 Jun 2025 10:58:14 -0400 Subject: [PATCH 09/10] Test on modern Node versions (#577) --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ac064b2..111b2c6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 22.x, 24.x] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} From 4ae9894edc6bced4ad983c5556de493d77c8cc6d Mon Sep 17 00:00:00 2001 From: Romain Menke Date: Tue, 17 Jun 2025 07:36:32 +0200 Subject: [PATCH 10/10] 16.1.1 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dc9d28..4c2d1b3 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 16.1.1 / 2025-06-17 + +- Fix incorrect cascade layer order when some resources can not be inlined ([#567](https://github.com/postcss/postcss-import/issues/567), [#574](https://github.com/postcss/postcss-import/pull/574)) + # 16.1.0 / 2024-03-20 - Allow bundling URLs with fragments (useful for Vite users) ([#560](https://github.com/postcss/postcss-import/issues/560), [#561](https://github.com/postcss/postcss-import/pull/561)) diff --git a/package.json b/package.json index 363aea5..09b5f2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-import", - "version": "16.1.0", + "version": "16.1.1", "description": "PostCSS plugin to import CSS files", "keywords": [ "css",