From 61420094dafcc3a916bfd5141c227afdab8b009c Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 5 Dec 2024 22:33:52 +0100 Subject: [PATCH 1/4] fix: transform everything that is not a selector inside `:global` --- .changeset/red-worms-suffer.md | 5 +++++ .../compiler/phases/3-transform/css/index.js | 20 ++++++++++--------- .../css/samples/global-block/expected.css | 11 ++++++++++ .../css/samples/global-block/input.svelte | 11 ++++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 .changeset/red-worms-suffer.md diff --git a/.changeset/red-worms-suffer.md b/.changeset/red-worms-suffer.md new file mode 100644 index 000000000000..bf8d08ecdcbf --- /dev/null +++ b/.changeset/red-worms-suffer.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: transform everything that is not a selector inside `:global` diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js index c1175e4b5b80..55741e51de71 100644 --- a/packages/svelte/src/compiler/phases/3-transform/css/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js @@ -13,6 +13,7 @@ import { dev } from '../../../state.js'; * hash: string; * minify: boolean; * selector: string; + * is_global_block: boolean; * keyframes: string[]; * specificity: { * bumped: boolean @@ -36,6 +37,7 @@ export function render_stylesheet(source, analysis, options) { minify: analysis.inject_styles && !options.dev, selector: `.${analysis.css.hash}`, keyframes: analysis.css.keyframes, + is_global_block: false, specificity: { bumped: false } @@ -154,7 +156,7 @@ const visitors = { return; } - if (!is_used(node)) { + if (!is_used(node) && !state.is_global_block) { if (state.minify) { state.code.remove(node.start, node.end); } else { @@ -182,20 +184,20 @@ const visitors = { state.code.appendLeft(node.block.end, '*/'); } - // don't recurse into selector or body + // don't recurse into selectors but visit the body + visit(node.block, { ...state, is_global_block: true }); return; } - - // don't recurse into body - visit(node.prelude); - return; } - next(); + next({ ...state, is_global_block: node.metadata.is_global_block || state.is_global_block }); }, SelectorList(node, { state, next, path }) { - // Only add comments if we're not inside a complex selector that itself is unused - if (!path.find((n) => n.type === 'ComplexSelector' && !n.metadata.used)) { + // Only add comments if we're not inside a complex selector that itself is unused or a global block + if ( + !state.is_global_block && + !path.find((n) => n.type === 'ComplexSelector' && !n.metadata.used) + ) { const children = node.children; let pruning = false; let prune_start = children[0].start; diff --git a/packages/svelte/tests/css/samples/global-block/expected.css b/packages/svelte/tests/css/samples/global-block/expected.css index 3acc1b021230..c13985b3ffc4 100644 --- a/packages/svelte/tests/css/samples/global-block/expected.css +++ b/packages/svelte/tests/css/samples/global-block/expected.css @@ -69,3 +69,14 @@ color: red; } }*/ + /* :global{*/ + .x{ + animation: svelte-xyz-test 1s; + } + /*}*/ + + @keyframes svelte-xyz-test{ + to{ + opacity: 1; + } + } diff --git a/packages/svelte/tests/css/samples/global-block/input.svelte b/packages/svelte/tests/css/samples/global-block/input.svelte index 2f2cdfcbd5aa..1ae8a06fdbe5 100644 --- a/packages/svelte/tests/css/samples/global-block/input.svelte +++ b/packages/svelte/tests/css/samples/global-block/input.svelte @@ -71,4 +71,15 @@ color: red; } } + :global{ + .x{ + animation: test 1s; + } + } + + @keyframes test{ + to{ + opacity: 1; + } + } From c997b0f68e2512569817238d62d4b5514709f1b8 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 5 Dec 2024 22:46:56 +0100 Subject: [PATCH 2/4] fix: don't transform keyframes names in global selector --- .../svelte/src/compiler/phases/3-transform/css/index.js | 2 +- packages/svelte/tests/css/samples/global-block/expected.css | 6 ++++++ packages/svelte/tests/css/samples/global-block/input.svelte | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js index 55741e51de71..6ff3b8d38d16 100644 --- a/packages/svelte/src/compiler/phases/3-transform/css/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js @@ -89,7 +89,7 @@ const visitors = { if (node.prelude.startsWith('-global-')) { state.code.remove(start, start + 8); - } else { + } else if (!state.is_global_block) { state.code.prependRight(start, `${state.hash}-`); } diff --git a/packages/svelte/tests/css/samples/global-block/expected.css b/packages/svelte/tests/css/samples/global-block/expected.css index c13985b3ffc4..8a7c493d7c90 100644 --- a/packages/svelte/tests/css/samples/global-block/expected.css +++ b/packages/svelte/tests/css/samples/global-block/expected.css @@ -73,6 +73,12 @@ .x{ animation: svelte-xyz-test 1s; } + + @keyframes test-in{ + to{ + opacity: 1; + } + } /*}*/ @keyframes svelte-xyz-test{ diff --git a/packages/svelte/tests/css/samples/global-block/input.svelte b/packages/svelte/tests/css/samples/global-block/input.svelte index 1ae8a06fdbe5..dc1a7540108f 100644 --- a/packages/svelte/tests/css/samples/global-block/input.svelte +++ b/packages/svelte/tests/css/samples/global-block/input.svelte @@ -75,6 +75,12 @@ .x{ animation: test 1s; } + + @keyframes test-in{ + to{ + opacity: 1; + } + } } @keyframes test{ From d96b23d4b92d347d31fe0981f7c62c355174eae2 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 5 Dec 2024 23:04:31 +0100 Subject: [PATCH 3/4] chore: use path instead of state --- .../compiler/phases/3-transform/css/index.js | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js index 6ff3b8d38d16..540cdb41aed6 100644 --- a/packages/svelte/src/compiler/phases/3-transform/css/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js @@ -13,7 +13,6 @@ import { dev } from '../../../state.js'; * hash: string; * minify: boolean; * selector: string; - * is_global_block: boolean; * keyframes: string[]; * specificity: { * bumped: boolean @@ -37,7 +36,6 @@ export function render_stylesheet(source, analysis, options) { minify: analysis.inject_styles && !options.dev, selector: `.${analysis.css.hash}`, keyframes: analysis.css.keyframes, - is_global_block: false, specificity: { bumped: false } @@ -80,7 +78,7 @@ const visitors = { context.state.code.addSourcemapLocation(node.end); context.next(); }, - Atrule(node, { state, next }) { + Atrule(node, { state, next, path }) { if (is_keyframes_node(node)) { let start = node.start + node.name.length + 1; while (state.code.original[start] === ' ') start += 1; @@ -89,7 +87,7 @@ const visitors = { if (node.prelude.startsWith('-global-')) { state.code.remove(start, start + 8); - } else if (!state.is_global_block) { + } else if (!is_global_block(path)) { state.code.prependRight(start, `${state.hash}-`); } @@ -136,7 +134,7 @@ const visitors = { } } }, - Rule(node, { state, next, visit }) { + Rule(node, { state, next, visit, path }) { if (state.minify) { remove_preceding_whitespace(node.start, state); remove_preceding_whitespace(node.block.end - 1, state); @@ -156,7 +154,7 @@ const visitors = { return; } - if (!is_used(node) && !state.is_global_block) { + if (!is_used(node) && !is_global_block(path)) { if (state.minify) { state.code.remove(node.start, node.end); } else { @@ -185,17 +183,17 @@ const visitors = { } // don't recurse into selectors but visit the body - visit(node.block, { ...state, is_global_block: true }); + visit(node.block); return; } } - next({ ...state, is_global_block: node.metadata.is_global_block || state.is_global_block }); + next(); }, SelectorList(node, { state, next, path }) { // Only add comments if we're not inside a complex selector that itself is unused or a global block if ( - !state.is_global_block && + !is_global_block(path) && !path.find((n) => n.type === 'ComplexSelector' && !n.metadata.used) ) { const children = node.children; @@ -361,6 +359,14 @@ const visitors = { } }; +/** + * + * @param {Array} path + */ +function is_global_block(path) { + return path.some((node) => node.type === 'Rule' && node.metadata.is_global_block); +} + /** * @param {Css.PseudoClassSelector} selector * @param {Css.Combinator | null} combinator From ed4f62d5abd5a814d0c84b1c778ea29d1e049125 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 5 Dec 2024 23:05:38 +0100 Subject: [PATCH 4/4] chore: rename to `is_in_global_block` --- .../svelte/src/compiler/phases/3-transform/css/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js index 540cdb41aed6..75b63260d567 100644 --- a/packages/svelte/src/compiler/phases/3-transform/css/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js @@ -87,7 +87,7 @@ const visitors = { if (node.prelude.startsWith('-global-')) { state.code.remove(start, start + 8); - } else if (!is_global_block(path)) { + } else if (!is_in_global_block(path)) { state.code.prependRight(start, `${state.hash}-`); } @@ -154,7 +154,7 @@ const visitors = { return; } - if (!is_used(node) && !is_global_block(path)) { + if (!is_used(node) && !is_in_global_block(path)) { if (state.minify) { state.code.remove(node.start, node.end); } else { @@ -193,7 +193,7 @@ const visitors = { SelectorList(node, { state, next, path }) { // Only add comments if we're not inside a complex selector that itself is unused or a global block if ( - !is_global_block(path) && + !is_in_global_block(path) && !path.find((n) => n.type === 'ComplexSelector' && !n.metadata.used) ) { const children = node.children; @@ -363,7 +363,7 @@ const visitors = { * * @param {Array} path */ -function is_global_block(path) { +function is_in_global_block(path) { return path.some((node) => node.type === 'Rule' && node.metadata.is_global_block); }