From 50997421ff3d7e00fcfbc90e27b5b39f93a10414 Mon Sep 17 00:00:00 2001 From: AdrianGonz97 <31664583+AdrianGonz97@users.noreply.github.com> Date: Wed, 26 Feb 2025 18:23:25 -0500 Subject: [PATCH 1/6] allow plugins to be added after initial add-on run --- packages/addons/tailwindcss/index.ts | 43 ++++++++++++---------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/packages/addons/tailwindcss/index.ts b/packages/addons/tailwindcss/index.ts index a1a30130f..1eabde85a 100644 --- a/packages/addons/tailwindcss/index.ts +++ b/packages/addons/tailwindcss/index.ts @@ -1,5 +1,4 @@ import { defineAddon, defineAddonOptions } from '@sveltejs/cli-core'; -import { addAtRule, addImports } from '@sveltejs/cli-core/css'; import { array, functions, imports, object, exports } from '@sveltejs/cli-core/js'; import { parseCss, parseJson, parseScript, parseSvelte } from '@sveltejs/cli-core/parsers'; import { addSlot } from '@sveltejs/cli-core/html'; @@ -74,37 +73,31 @@ export default defineAddon({ }); sv.file('src/app.css', (content) => { - if (content.includes('tailwindcss')) { - return content; - } + let code = content; - const { ast, generateCode } = parseCss(content); - const originalFirst = ast.first; + const importsTailwind = content.match(/@import ["']tailwindcss["']/); + if (!importsTailwind) { + code = "@import 'tailwindcss';\n" + code; + } - const nodes = addImports(ast, ["'tailwindcss'"]); + const lastAtRule = code.match(/@(import|plugin).*[;]/gm)?.at(-1); + if (!lastAtRule) throw new Error('Impossible condition: Missing `@import` atrule.'); + const pluginPos = code.indexOf(lastAtRule) + lastAtRule.length; + const { ast } = parseCss(code); + const atRules = ast.nodes.filter((x) => x.type === 'atrule'); for (const plugin of plugins) { if (!options.plugins.includes(plugin.id)) continue; - - addAtRule(ast, 'plugin', `'${plugin.package}'`, true); - } - - if ( - originalFirst !== ast.first && - originalFirst?.type === 'atrule' && - originalFirst.name === 'import' - ) { - originalFirst.raws.before = '\n'; + const atRule = atRules.find( + (x) => x.name === 'plugin' && x.params === `'${plugin.package}'` + ); + if (!atRule) { + const pluginImport = `\n@plugin '${plugin.package}';`; + code = code.substring(0, pluginPos) + pluginImport + code.substring(pluginPos); + } } - // We remove the first node to avoid adding a newline at the top of the stylesheet - nodes.shift(); - - // Each node is prefixed with single newline, ensuring the imports will always be single spaced. - // Without this, the CSS printer will vary the spacing depending on the current state of the stylesheet - nodes.forEach((n) => (n.raws.before = '\n')); - - return generateCode(); + return code; }); if (!kit) { From f1a916eaebd85de57ce1157fb0a1f15125a7f3c5 Mon Sep 17 00:00:00 2001 From: AdrianGonz97 <31664583+AdrianGonz97@users.noreply.github.com> Date: Wed, 26 Feb 2025 18:26:17 -0500 Subject: [PATCH 2/6] changeset --- .changeset/ninety-islands-cross.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/ninety-islands-cross.md diff --git a/.changeset/ninety-islands-cross.md b/.changeset/ninety-islands-cross.md new file mode 100644 index 000000000..b9b6e33a8 --- /dev/null +++ b/.changeset/ninety-islands-cross.md @@ -0,0 +1,5 @@ +--- +'sv': patch +--- + +fix: properly add tailwind plugins on subsequent add-on executions From 1489bbdcbfcda3f924bc95e6e3d18dfb4ff624ee Mon Sep 17 00:00:00 2001 From: AdrianGonz97 <31664583+AdrianGonz97@users.noreply.github.com> Date: Thu, 27 Feb 2025 10:20:50 -0500 Subject: [PATCH 3/6] check for double or single quotes --- packages/addons/tailwindcss/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/addons/tailwindcss/index.ts b/packages/addons/tailwindcss/index.ts index 1eabde85a..b687457d5 100644 --- a/packages/addons/tailwindcss/index.ts +++ b/packages/addons/tailwindcss/index.ts @@ -88,9 +88,10 @@ export default defineAddon({ const atRules = ast.nodes.filter((x) => x.type === 'atrule'); for (const plugin of plugins) { if (!options.plugins.includes(plugin.id)) continue; - const atRule = atRules.find( - (x) => x.name === 'plugin' && x.params === `'${plugin.package}'` - ); + + // Checks for both double and single quote variants + const pkgs = [`'${plugin.package}'`, `"${plugin.package}"`]; + const atRule = atRules.find((x) => x.name === 'plugin' && pkgs.includes(x.params)); if (!atRule) { const pluginImport = `\n@plugin '${plugin.package}';`; code = code.substring(0, pluginPos) + pluginImport + code.substring(pluginPos); From 0c0cd3bc7fc49cc1bc4d6c6e46f86a03f913b269 Mon Sep 17 00:00:00 2001 From: AdrianGonz97 <31664583+AdrianGonz97@users.noreply.github.com> Date: Thu, 27 Feb 2025 10:27:26 -0500 Subject: [PATCH 4/6] tweak --- packages/addons/tailwindcss/index.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/addons/tailwindcss/index.ts b/packages/addons/tailwindcss/index.ts index b687457d5..6c2b07f60 100644 --- a/packages/addons/tailwindcss/index.ts +++ b/packages/addons/tailwindcss/index.ts @@ -89,9 +89,12 @@ export default defineAddon({ for (const plugin of plugins) { if (!options.plugins.includes(plugin.id)) continue; - // Checks for both double and single quote variants - const pkgs = [`'${plugin.package}'`, `"${plugin.package}"`]; - const atRule = atRules.find((x) => x.name === 'plugin' && pkgs.includes(x.params)); + const atRule = atRules.find( + (rule) => + rule.name === 'plugin' && + // Checks for both double and single quote variants + rule.params.replace(/['"]/g, '') === plugin.package + ); if (!atRule) { const pluginImport = `\n@plugin '${plugin.package}';`; code = code.substring(0, pluginPos) + pluginImport + code.substring(pluginPos); From 6db05903f0135270857fe431a07e846b0b606a11 Mon Sep 17 00:00:00 2001 From: AdrianGonz97 <31664583+AdrianGonz97@users.noreply.github.com> Date: Thu, 27 Feb 2025 11:06:21 -0500 Subject: [PATCH 5/6] improve robustness --- packages/addons/tailwindcss/index.ts | 32 ++++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/addons/tailwindcss/index.ts b/packages/addons/tailwindcss/index.ts index 6c2b07f60..880faee6e 100644 --- a/packages/addons/tailwindcss/index.ts +++ b/packages/addons/tailwindcss/index.ts @@ -73,29 +73,33 @@ export default defineAddon({ }); sv.file('src/app.css', (content) => { - let code = content; + let atRules = parseCss(content).ast.nodes.filter((node) => node.type === 'atrule'); + + const findAtRule = (name: string, params: string) => + atRules.find( + (rule) => + rule.name === name && + // checks for both double and single quote variants + rule.params.replace(/['"]/g, '') === params + ); - const importsTailwind = content.match(/@import ["']tailwindcss["']/); + let code = content; + const importsTailwind = findAtRule('import', 'tailwindcss'); if (!importsTailwind) { code = "@import 'tailwindcss';\n" + code; } - const lastAtRule = code.match(/@(import|plugin).*[;]/gm)?.at(-1); - if (!lastAtRule) throw new Error('Impossible condition: Missing `@import` atrule.'); - const pluginPos = code.indexOf(lastAtRule) + lastAtRule.length; + // reparse to account for the newly added tailwindcss import + atRules = parseCss(code).ast.nodes.filter((node) => node.type === 'atrule'); + + const lastAtRule = atRules.findLast((rule) => ['plugin', 'import'].includes(rule.name)); + const pluginPos = lastAtRule!.source!.end!.offset; - const { ast } = parseCss(code); - const atRules = ast.nodes.filter((x) => x.type === 'atrule'); for (const plugin of plugins) { if (!options.plugins.includes(plugin.id)) continue; - const atRule = atRules.find( - (rule) => - rule.name === 'plugin' && - // Checks for both double and single quote variants - rule.params.replace(/['"]/g, '') === plugin.package - ); - if (!atRule) { + const pluginRule = findAtRule('plugin', plugin.package); + if (!pluginRule) { const pluginImport = `\n@plugin '${plugin.package}';`; code = code.substring(0, pluginPos) + pluginImport + code.substring(pluginPos); } From b2154ea60dcb1bb3bab0d1de112fa655fba7a698 Mon Sep 17 00:00:00 2001 From: AdrianGonz97 <31664583+AdrianGonz97@users.noreply.github.com> Date: Thu, 27 Feb 2025 11:09:32 -0500 Subject: [PATCH 6/6] final tweak --- packages/addons/tailwindcss/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/addons/tailwindcss/index.ts b/packages/addons/tailwindcss/index.ts index 880faee6e..18fe640ba 100644 --- a/packages/addons/tailwindcss/index.ts +++ b/packages/addons/tailwindcss/index.ts @@ -87,11 +87,10 @@ export default defineAddon({ const importsTailwind = findAtRule('import', 'tailwindcss'); if (!importsTailwind) { code = "@import 'tailwindcss';\n" + code; + // reparse to account for the newly added tailwindcss import + atRules = parseCss(code).ast.nodes.filter((node) => node.type === 'atrule'); } - // reparse to account for the newly added tailwindcss import - atRules = parseCss(code).ast.nodes.filter((node) => node.type === 'atrule'); - const lastAtRule = atRules.findLast((rule) => ['plugin', 'import'].includes(rule.name)); const pluginPos = lastAtRule!.source!.end!.offset;