Skip to content

Commit abe84f2

Browse files
jycouetAdrianGonz97manuel3108
authored
feat: add tailwindcss 4.0 (#422)
* feat: ADD tailwindcss 4.0 * cleanup * simplify app.css * update vite.config.tjs * import addDefault * rgb to oklch * 👌 FIX: linting (FTW) * correct oklch (tmp only tailwind) * back to all * typography without any plugin ✅ * Update .changeset/empty-geese-draw.md Co-authored-by: CokaKoala <[email protected]> * Update .changeset/empty-geese-draw.md --------- Co-authored-by: CokaKoala <[email protected]> Co-authored-by: Manuel <[email protected]>
1 parent 41cc5f6 commit abe84f2

File tree

3 files changed

+45
-117
lines changed

3 files changed

+45
-117
lines changed

.changeset/empty-geese-draw.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'sv': patch
3+
---
4+
5+
feat: update to `tailwindcss` v4.0.0

packages/addons/_tests/tailwindcss/test.ts

+21-18
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,28 @@ test.concurrent.for(variants)('none - %s', async (variant, { page, ...ctx }) =>
1616
ctx.onTestFinished(async () => await close());
1717

1818
const el = page.getByTestId('base');
19-
await expect(el).toHaveCSS('background-color', 'rgb(71, 85, 105)');
20-
await expect(el).toHaveCSS('border-color', 'rgb(249, 250, 251)');
19+
await expect(el).toHaveCSS('background-color', 'oklch(0.446 0.043 257.281)');
20+
await expect(el).toHaveCSS('border-color', 'oklch(0.985 0.002 247.839)');
2121
await expect(el).toHaveCSS('border-width', '4px');
2222
await expect(el).toHaveCSS('margin-top', '4px');
2323
});
2424

25-
test.concurrent.for(variants)('typography - %s', async (variant, { page, ...ctx }) => {
26-
const cwd = await ctx.run(variant, { tailwindcss: { plugins: ['typography'] } });
27-
28-
// ...add files
29-
addFixture(cwd, variant);
30-
31-
const { close } = await prepareServer({ cwd, page });
32-
// kill server process when we're done
33-
ctx.onTestFinished(async () => await close());
34-
35-
const el = page.getByTestId('typography');
36-
await expect(el).toHaveCSS('font-size', '18px');
37-
await expect(el).toHaveCSS('line-height', '28px');
38-
await expect(el).toHaveCSS('text-align', 'right');
39-
await expect(el).toHaveCSS('text-decoration-line', 'line-through');
40-
});
25+
test.concurrent.for(variants)(
26+
'typography without plugin - %s',
27+
async (variant, { page, ...ctx }) => {
28+
const cwd = await ctx.run(variant, { tailwindcss });
29+
30+
// ...add files
31+
addFixture(cwd, variant);
32+
33+
const { close } = await prepareServer({ cwd, page });
34+
// kill server process when we're done
35+
ctx.onTestFinished(async () => await close());
36+
37+
const el = page.getByTestId('typography');
38+
await expect(el).toHaveCSS('font-size', '18px');
39+
await expect(el).toHaveCSS('line-height', '28px');
40+
await expect(el).toHaveCSS('text-align', 'right');
41+
await expect(el).toHaveCSS('text-decoration-line', 'line-through');
42+
}
43+
);

packages/addons/tailwindcss/index.ts

+19-99
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,50 @@
1-
import { defineAddon, defineAddonOptions } from '@sveltejs/cli-core';
1+
import { defineAddon } from '@sveltejs/cli-core';
22
import { addImports } from '@sveltejs/cli-core/css';
3-
import { array, common, exports, imports, object } from '@sveltejs/cli-core/js';
4-
import { parseCss, parseScript, parseJson, parseSvelte } from '@sveltejs/cli-core/parsers';
3+
import { array, functions, imports, object, exports } from '@sveltejs/cli-core/js';
4+
import { parseCss, parseJson, parseScript, parseSvelte } from '@sveltejs/cli-core/parsers';
55
import { addSlot } from '@sveltejs/cli-core/html';
66

7-
type Plugin = {
8-
id: string;
9-
package: string;
10-
version: string;
11-
identifier: string;
12-
};
13-
14-
const plugins: Plugin[] = [
15-
{
16-
id: 'typography',
17-
package: '@tailwindcss/typography',
18-
version: '^0.5.16',
19-
identifier: 'typography'
20-
},
21-
{
22-
id: 'forms',
23-
package: '@tailwindcss/forms',
24-
version: '^0.5.10',
25-
identifier: 'forms'
26-
},
27-
{
28-
id: 'container-queries',
29-
package: '@tailwindcss/container-queries',
30-
version: '^0.1.1',
31-
identifier: 'containerQueries'
32-
}
33-
];
34-
35-
const options = defineAddonOptions({
36-
plugins: {
37-
type: 'multiselect',
38-
question: 'Which plugins would you like to add?',
39-
options: plugins.map((p) => ({ value: p.id, label: p.id, hint: p.package })),
40-
default: []
41-
}
42-
});
43-
447
export default defineAddon({
458
id: 'tailwindcss',
469
alias: 'tailwind',
4710
shortDescription: 'css framework',
4811
homepage: 'https://tailwindcss.com',
49-
options,
50-
run: ({ sv, options, typescript, kit, dependencyVersion }) => {
12+
options: {},
13+
run: ({ sv, typescript, kit, dependencyVersion }) => {
5114
const ext = typescript ? 'ts' : 'js';
5215
const prettierInstalled = Boolean(dependencyVersion('prettier'));
5316

54-
sv.devDependency('tailwindcss', '^3.4.17');
55-
sv.devDependency('autoprefixer', '^10.4.20');
56-
57-
if (prettierInstalled) sv.devDependency('prettier-plugin-tailwindcss', '^0.6.10');
17+
sv.devDependency('tailwindcss', '^4.0.0');
18+
sv.devDependency('@tailwindcss/vite', '^4.0.0');
5819

59-
for (const plugin of plugins) {
60-
if (!options.plugins.includes(plugin.id)) continue;
20+
if (prettierInstalled) sv.devDependency('prettier-plugin-tailwindcss', '^0.6.11');
6121

62-
sv.devDependency(plugin.package, plugin.version);
63-
}
64-
65-
sv.file(`tailwind.config.${ext}`, (content) => {
22+
// add the vite plugin
23+
sv.file(`vite.config.${ext}`, (content) => {
6624
const { ast, generateCode } = parseScript(content);
67-
let root;
68-
const rootExport = object.createEmpty();
69-
if (typescript) {
70-
imports.addNamed(ast, 'tailwindcss', { Config: 'Config' }, true);
71-
root = common.satisfiesExpression(rootExport, 'Config');
72-
}
73-
74-
const { astNode: exportDeclaration, value: node } = exports.defaultExport(
75-
ast,
76-
root ?? rootExport
77-
);
78-
79-
const config = node.type === 'TSSatisfiesExpression' ? node.expression : node;
80-
if (config.type !== 'ObjectExpression') {
81-
throw new Error(`Unexpected tailwind config shape: ${config.type}`);
82-
}
83-
84-
if (!typescript) {
85-
common.addJsDocTypeComment(exportDeclaration, "import('tailwindcss').Config");
86-
}
87-
88-
const contentArray = object.property(config, 'content', array.createEmpty());
89-
array.push(contentArray, './src/**/*.{html,js,svelte,ts}');
90-
91-
const themeObject = object.property(config, 'theme', object.createEmpty());
92-
object.property(themeObject, 'extend', object.createEmpty());
9325

94-
const pluginsArray = object.property(config, 'plugins', array.createEmpty());
26+
const vitePluginName = 'tailwindcss';
27+
imports.addDefault(ast, '@tailwindcss/vite', vitePluginName);
9528

96-
for (const plugin of plugins) {
97-
if (!options.plugins.includes(plugin.id)) continue;
98-
imports.addDefault(ast, plugin.package, plugin.identifier);
99-
array.push(pluginsArray, { type: 'Identifier', name: plugin.identifier });
100-
}
29+
const { value: rootObject } = exports.defaultExport(ast, functions.call('defineConfig', []));
30+
const param1 = functions.argumentByIndex(rootObject, 0, object.createEmpty());
10131

102-
return generateCode();
103-
});
104-
105-
sv.file('postcss.config.js', (content) => {
106-
const { ast, generateCode } = parseScript(content);
107-
const { value: rootObject } = exports.defaultExport(ast, object.createEmpty());
108-
const pluginsObject = object.property(rootObject, 'plugins', object.createEmpty());
32+
const pluginsArray = object.property(param1, 'plugins', array.createEmpty());
33+
const pluginFunctionCall = functions.call(vitePluginName, []);
34+
array.push(pluginsArray, pluginFunctionCall);
10935

110-
object.property(pluginsObject, 'tailwindcss', object.createEmpty());
111-
object.property(pluginsObject, 'autoprefixer', object.createEmpty());
11236
return generateCode();
11337
});
11438

11539
sv.file('src/app.css', (content) => {
116-
const layerImports = ['base', 'components', 'utilities'].map(
117-
(layer) => `tailwindcss/${layer}`
118-
);
119-
if (layerImports.every((i) => content.includes(i))) {
40+
if (content.includes('tailwindcss')) {
12041
return content;
12142
}
12243

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

126-
const specifiers = layerImports.map((i) => `'${i}'`);
127-
const nodes = addImports(ast, specifiers);
47+
const nodes = addImports(ast, ["'tailwindcss'"]);
12848

12949
if (
13050
originalFirst !== ast.first &&

0 commit comments

Comments
 (0)