Skip to content

Commit

Permalink
fix: allow tailwindcss plugins to be added after initial execution (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianGonz97 authored Feb 27, 2025
1 parent 7dcf6d0 commit faa8f38
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-islands-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'sv': patch
---

fix: properly add tailwind plugins on subsequent add-on executions
48 changes: 24 additions & 24 deletions packages/addons/tailwindcss/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -74,37 +73,38 @@ export default defineAddon({
});

sv.file('src/app.css', (content) => {
if (content.includes('tailwindcss')) {
return 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
);

let code = content;
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');
}

const { ast, generateCode } = parseCss(content);
const originalFirst = ast.first;

const nodes = addImports(ast, ["'tailwindcss'"]);
const lastAtRule = atRules.findLast((rule) => ['plugin', 'import'].includes(rule.name));
const pluginPos = lastAtRule!.source!.end!.offset;

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 pluginRule = findAtRule('plugin', plugin.package);
if (!pluginRule) {
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) {
Expand Down

0 comments on commit faa8f38

Please sign in to comment.