Skip to content

Commit f30efb6

Browse files
committed
feat(shadcn): add tailwind version detection
1 parent c8c4027 commit f30efb6

File tree

10 files changed

+91
-68
lines changed

10 files changed

+91
-68
lines changed

packages/shadcn/src/preflights/preflight-init.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,16 @@ export async function preFlightInit(
8181
const tailwindSpinner = spinner(`Validating Tailwind CSS.`, {
8282
silent: options.silent,
8383
}).start()
84-
if (!projectInfo?.tailwindConfigFile || !projectInfo?.tailwindCssFile) {
84+
if (
85+
projectInfo.tailwindVersion === "v3" &&
86+
(!projectInfo?.tailwindConfigFile || !projectInfo?.tailwindCssFile)
87+
) {
88+
errors[ERRORS.TAILWIND_NOT_CONFIGURED] = true
89+
tailwindSpinner?.fail()
90+
} else if (
91+
projectInfo.tailwindVersion === "v4" &&
92+
!projectInfo?.tailwindCssFile
93+
) {
8594
errors[ERRORS.TAILWIND_NOT_CONFIGURED] = true
8695
tailwindSpinner?.fail()
8796
} else {

packages/shadcn/src/utils/get-config.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { highlighter } from "@/src/utils/highlighter"
33
import { resolveImport } from "@/src/utils/resolve-import"
44
import { cosmiconfig } from "cosmiconfig"
55
import fg from "fast-glob"
6-
import fs from "fs-extra"
76
import { loadConfig } from "tsconfig-paths"
87
import { z } from "zod"
98

@@ -27,7 +26,7 @@ export const rawConfigSchema = z
2726
rsc: z.coerce.boolean().default(false),
2827
tsx: z.coerce.boolean().default(true),
2928
tailwind: z.object({
30-
config: z.string(),
29+
config: z.string().optional(),
3130
css: z.string(),
3231
baseColor: z.string(),
3332
cssVariables: z.boolean().default(true),
@@ -96,7 +95,9 @@ export async function resolveConfigPaths(cwd: string, config: RawConfig) {
9695
...config,
9796
resolvedPaths: {
9897
cwd,
99-
tailwindConfig: path.resolve(cwd, config.tailwind.config),
98+
tailwindConfig: config.tailwind.config
99+
? path.resolve(cwd, config.tailwind.config)
100+
: "",
100101
tailwindCss: path.resolve(cwd, config.tailwind.css),
101102
utils: await resolveImport(config.aliases["utils"], tsConfig),
102103
components: await resolveImport(config.aliases["components"], tsConfig),

packages/shadcn/src/utils/get-project-info.ts

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type ProjectInfo = {
1919
isTsx: boolean
2020
tailwindConfigFile: string | null
2121
tailwindCssFile: string | null
22+
tailwindVersion: "v3" | "v4" | null
2223
aliasPrefix: string | null
2324
}
2425

@@ -43,6 +44,7 @@ export async function getProjectInfo(cwd: string): Promise<ProjectInfo | null> {
4344
isTsx,
4445
tailwindConfigFile,
4546
tailwindCssFile,
47+
tailwindVersion,
4648
aliasPrefix,
4749
packageJson,
4850
] = await Promise.all([
@@ -55,6 +57,7 @@ export async function getProjectInfo(cwd: string): Promise<ProjectInfo | null> {
5557
isTypeScriptProject(cwd),
5658
getTailwindConfigFile(cwd),
5759
getTailwindCssFile(cwd),
60+
getTailwindVersion(cwd),
5861
getTsConfigAliasPrefix(cwd),
5962
getPackageInfo(cwd, false),
6063
])
@@ -70,6 +73,7 @@ export async function getProjectInfo(cwd: string): Promise<ProjectInfo | null> {
7073
isTsx,
7174
tailwindConfigFile,
7275
tailwindCssFile,
76+
tailwindVersion,
7377
aliasPrefix,
7478
}
7579

@@ -121,21 +125,50 @@ export async function getProjectInfo(cwd: string): Promise<ProjectInfo | null> {
121125
return type
122126
}
123127

128+
export async function getTailwindVersion(
129+
cwd: string
130+
): Promise<ProjectInfo["tailwindVersion"]> {
131+
const packageInfo = getPackageInfo(cwd)
132+
133+
if (
134+
!packageInfo?.dependencies?.tailwindcss &&
135+
!packageInfo?.devDependencies?.tailwindcss
136+
) {
137+
return null
138+
}
139+
140+
if (
141+
/^(?:\^|~)?3(?:\.\d+)*(?:-.*)?$/.test(
142+
packageInfo?.dependencies?.tailwindcss ||
143+
packageInfo?.devDependencies?.tailwindcss ||
144+
""
145+
)
146+
) {
147+
return "v3"
148+
}
149+
150+
return "v4"
151+
}
152+
124153
export async function getTailwindCssFile(cwd: string) {
125-
const files = await fg.glob(["**/*.css", "**/*.scss"], {
126-
cwd,
127-
deep: 5,
128-
ignore: PROJECT_SHARED_IGNORE,
129-
})
154+
const [files, tailwindVersion] = await Promise.all([
155+
fg.glob(["**/*.css", "**/*.scss"], {
156+
cwd,
157+
deep: 5,
158+
ignore: PROJECT_SHARED_IGNORE,
159+
}),
160+
getTailwindVersion(cwd),
161+
])
130162

131163
if (!files.length) {
132164
return null
133165
}
134166

167+
const needle =
168+
tailwindVersion === "v4" ? `@import "tailwindcss"` : "@tailwind base"
135169
for (const file of files) {
136170
const contents = await fs.readFile(path.resolve(cwd, file), "utf8")
137-
// Assume that if the file contains `@tailwind base` it's the main css file.
138-
if (contents.includes("@tailwind base")) {
171+
if (contents.includes(needle)) {
139172
return file
140173
}
141174
}
@@ -237,8 +270,8 @@ export async function getProjectConfig(
237270

238271
if (
239272
!projectInfo ||
240-
!projectInfo.tailwindConfigFile ||
241-
!projectInfo.tailwindCssFile
273+
!projectInfo.tailwindCssFile ||
274+
(projectInfo.tailwindVersion === "v3" && !projectInfo.tailwindConfigFile)
242275
) {
243276
return null
244277
}
@@ -249,7 +282,7 @@ export async function getProjectConfig(
249282
tsx: projectInfo.isTsx,
250283
style: "new-york",
251284
tailwind: {
252-
config: projectInfo.tailwindConfigFile,
285+
config: projectInfo.tailwindConfigFile ?? "",
253286
baseColor: "zinc",
254287
css: projectInfo.tailwindCssFile,
255288
cssVariables: true,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "next-app-src",
3+
"version": "0.1.0",
4+
"private": true,
5+
"scripts": {
6+
"dev": "next dev",
7+
"build": "next build",
8+
"start": "next start",
9+
"lint": "next lint"
10+
},
11+
"dependencies": {
12+
"tailwindcss": "3.1.2"
13+
}
14+
}

packages/shadcn/test/fixtures/frameworks/next-app/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "next lint"
10+
},
11+
"dependencies": {
12+
"tailwindcss": "^3.0.0"
1013
}
1114
}

packages/shadcn/test/fixtures/frameworks/next-pages-src/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "next lint"
10+
},
11+
"dependencies": {
12+
"tailwindcss": "^4.0.0"
1013
}
1114
}
Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1 @@
1-
@tailwind base;
2-
@tailwind components;
3-
@tailwind utilities;
4-
5-
:root {
6-
--foreground-rgb: 0, 0, 0;
7-
--background-start-rgb: 214, 219, 220;
8-
--background-end-rgb: 255, 255, 255;
9-
}
10-
11-
@media (prefers-color-scheme: dark) {
12-
:root {
13-
--foreground-rgb: 255, 255, 255;
14-
--background-start-rgb: 0, 0, 0;
15-
--background-end-rgb: 0, 0, 0;
16-
}
17-
}
18-
19-
body {
20-
color: rgb(var(--foreground-rgb));
21-
background: linear-gradient(
22-
to bottom,
23-
transparent,
24-
rgb(var(--background-end-rgb))
25-
)
26-
rgb(var(--background-start-rgb));
27-
}
1+
@import "tailwindcss";

packages/shadcn/test/fixtures/frameworks/next-pages/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "next lint"
10+
},
11+
"devDependencies": {
12+
"tailwindcss": "4.1.2"
1013
}
1114
}
Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1 @@
1-
@tailwind base;
2-
@tailwind components;
3-
@tailwind utilities;
4-
5-
:root {
6-
--foreground-rgb: 0, 0, 0;
7-
--background-start-rgb: 214, 219, 220;
8-
--background-end-rgb: 255, 255, 255;
9-
}
10-
11-
@media (prefers-color-scheme: dark) {
12-
:root {
13-
--foreground-rgb: 255, 255, 255;
14-
--background-start-rgb: 0, 0, 0;
15-
--background-end-rgb: 0, 0, 0;
16-
}
17-
}
18-
19-
body {
20-
color: rgb(var(--foreground-rgb));
21-
background: linear-gradient(
22-
to bottom,
23-
transparent,
24-
rgb(var(--background-end-rgb))
25-
)
26-
rgb(var(--background-start-rgb));
27-
}
1+
@import "tailwindcss";

packages/shadcn/test/utils/get-project-info.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe("get project info", async () => {
1515
isTsx: true,
1616
tailwindConfigFile: "tailwind.config.ts",
1717
tailwindCssFile: "app/globals.css",
18+
tailwindVersion: "v3",
1819
aliasPrefix: "@",
1920
},
2021
},
@@ -27,6 +28,7 @@ describe("get project info", async () => {
2728
isTsx: true,
2829
tailwindConfigFile: "tailwind.config.ts",
2930
tailwindCssFile: "src/app/styles.css",
31+
tailwindVersion: "v3",
3032
aliasPrefix: "#",
3133
},
3234
},
@@ -39,6 +41,7 @@ describe("get project info", async () => {
3941
isTsx: true,
4042
tailwindConfigFile: "tailwind.config.ts",
4143
tailwindCssFile: "styles/globals.css",
44+
tailwindVersion: "v4",
4245
aliasPrefix: "~",
4346
},
4447
},
@@ -51,6 +54,7 @@ describe("get project info", async () => {
5154
isTsx: true,
5255
tailwindConfigFile: "tailwind.config.ts",
5356
tailwindCssFile: "src/styles/globals.css",
57+
tailwindVersion: "v4",
5458
aliasPrefix: "@",
5559
},
5660
},
@@ -63,6 +67,7 @@ describe("get project info", async () => {
6367
isTsx: true,
6468
tailwindConfigFile: "tailwind.config.ts",
6569
tailwindCssFile: "src/styles/globals.css",
70+
tailwindVersion: "v3",
6671
aliasPrefix: "~",
6772
},
6873
},
@@ -75,6 +80,7 @@ describe("get project info", async () => {
7580
isTsx: true,
7681
tailwindConfigFile: "tailwind.config.ts",
7782
tailwindCssFile: "src/styles/globals.css",
83+
tailwindVersion: "v3",
7884
aliasPrefix: "~",
7985
},
8086
},
@@ -87,6 +93,7 @@ describe("get project info", async () => {
8793
isTsx: true,
8894
tailwindConfigFile: "tailwind.config.ts",
8995
tailwindCssFile: "app/tailwind.css",
96+
tailwindVersion: "v3",
9097
aliasPrefix: "~",
9198
},
9299
},
@@ -99,6 +106,7 @@ describe("get project info", async () => {
99106
isTsx: true,
100107
tailwindConfigFile: "tailwind.config.ts",
101108
tailwindCssFile: "app/tailwind.css",
109+
tailwindVersion: "v3",
102110
aliasPrefix: "~",
103111
},
104112
},
@@ -111,6 +119,7 @@ describe("get project info", async () => {
111119
isTsx: true,
112120
tailwindConfigFile: "tailwind.config.js",
113121
tailwindCssFile: "src/index.css",
122+
tailwindVersion: "v3",
114123
aliasPrefix: null,
115124
},
116125
},

0 commit comments

Comments
 (0)