Skip to content

Commit 919349c

Browse files
Add bundled v4 fallback (#390)
* Add fallback for v4 * Fallback to v4 by default * Add tests * Fix testing aginst unminified build * Update changelog
1 parent 30f8d8e commit 919349c

File tree

14 files changed

+90
-24
lines changed

14 files changed

+90
-24
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- Improved monorepo support by loading Tailwind CSS relative to the input file instead of prettier config file ([#386](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/386))
1717
- Improved monorepo support by loading v3 configs relative to the input file instead of prettier config file ([#386](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/386))
1818
- Fix whitespace removal inside nested concat and template expressions ([#396](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/396))
19+
- Fallback to Tailwind CSS v4 instead of v3 by default ([#390](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/390))
1920

2021
## [0.6.14] - 2025-07-09
2122

build.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ function patchCjsInterop() {
4747
let code = [
4848
`import {createRequire as __global__createRequire__} from 'module'`,
4949
`import {dirname as __global__dirname__} from 'path'`,
50-
`import {fileURLToPath} from 'url'`,
50+
`import {fileURLToPath as __global__fileURLToPath__} from 'url'`,
5151

5252
// CJS interop fixes
5353
`const require=__global__createRequire__(import.meta.url)`,
54-
`const __filename=fileURLToPath(import.meta.url)`,
54+
`const __filename=__global__fileURLToPath__(import.meta.url)`,
5555
`const __dirname=__global__dirname__(__filename)`,
5656
]
5757

src/config.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,6 @@ export async function getTailwindConfig(options: ParserOptions): Promise<any> {
117117
stylesheet ??= `${pkgDir}/theme.css`
118118
}
119119

120-
// No stylesheet was given or otherwise found in a local v4 installation
121-
// nor was a tailwind config given or found.
122-
//
123-
// Fallback to v3
124-
if (!stylesheet) {
125-
return pathToApiMap.remember(null, () => loadV3(null, null))
126-
}
127-
128120
return pathToApiMap.remember(`${pkgDir}:${stylesheet}`, () => loadV4(mod, stylesheet))
129121
}
130122

src/versions/assets.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// @ts-ignore
2+
import index from 'tailwindcss-v4/index.css'
3+
// @ts-ignore
4+
import preflight from 'tailwindcss-v4/preflight.css'
5+
// @ts-ignore
6+
import theme from 'tailwindcss-v4/theme.css'
7+
// @ts-ignore
8+
import utilities from 'tailwindcss-v4/utilities.css'
9+
10+
export const assets: Record<string, string> = {
11+
tailwindcss: index,
12+
'tailwindcss/index': index,
13+
'tailwindcss/index.css': index,
14+
15+
'tailwindcss/preflight': preflight,
16+
'tailwindcss/preflight.css': preflight,
17+
18+
'tailwindcss/theme': theme,
19+
'tailwindcss/theme.css': theme,
20+
21+
'tailwindcss/utilities': utilities,
22+
'tailwindcss/utilities.css': utilities,
23+
}

src/versions/v4.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// @ts-check
21
import * as fs from 'node:fs/promises'
32
import * as path from 'node:path'
43
import { pathToFileURL } from 'node:url'
54
import { createJiti, type Jiti } from 'jiti'
5+
import * as v4 from 'tailwindcss-v4'
66
import { resolveCssFrom, resolveJsFrom } from '../resolve'
77
import type { UnifiedApi } from '../types'
8+
import { assets } from './assets'
89

910
interface DesignSystem {
1011
getClassOrder(classList: string[]): [string, bigint | null][]
@@ -40,11 +41,10 @@ interface ApiV4 {
4041

4142
export async function loadV4(mod: ApiV4 | null, stylesheet: string | null): Promise<UnifiedApi> {
4243
// This is not Tailwind v4
44+
let isFallback = false
4345
if (!mod || !mod.__unstable__loadDesignSystem) {
44-
throw new Error('Unable to load Tailwind CSS v4: Your installation of Tailwind CSS is not v4')
45-
46-
// TODO
47-
// mod = (await import('tailwindcss-v4')) as ApiV4
46+
mod = v4 as ApiV4
47+
isFallback = true
4848
}
4949

5050
// Create a Jiti instance that can be used to load plugins and config files
@@ -63,9 +63,7 @@ export async function loadV4(mod: ApiV4 | null, stylesheet: string | null): Prom
6363
} else {
6464
importBasePath = process.cwd()
6565
stylesheet = path.join(importBasePath, 'fake.css')
66-
67-
// TODO: bundled theme.css file?
68-
css = ''
66+
css = assets['tailwindcss/theme.css']
6967
}
7068

7169
// Load the design system and set up a compatible context object that is
@@ -90,11 +88,19 @@ export async function loadV4(mod: ApiV4 | null, stylesheet: string | null): Prom
9088
}),
9189

9290
loadStylesheet: async (id: string, base: string) => {
93-
let resolved = resolveCssFrom(base, id)
91+
try {
92+
let resolved = resolveCssFrom(base, id)
93+
94+
return {
95+
base: path.dirname(resolved),
96+
content: await fs.readFile(resolved, 'utf-8'),
97+
}
98+
} catch (err) {
99+
if (isFallback && id in assets) {
100+
return { base, content: assets[id] }
101+
}
94102

95-
return {
96-
base: path.dirname(resolved),
97-
content: await fs.readFile(resolved, 'utf-8'),
103+
throw err
98104
}
99105
},
100106

tests/fixtures.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ let fixtures = [
1616
dir: 'no-prettier-config',
1717
ext: 'html',
1818
},
19+
{
20+
name: 'no local install of Tailwind CSS (uses v4)',
21+
dir: 'no-local-version',
22+
ext: 'html',
23+
},
24+
{
25+
name: 'no stylesheet given (uses v4)',
26+
dir: 'no-stylesheet-given',
27+
ext: 'html',
28+
},
1929
{
2030
name: 'inferred config path',
2131
dir: 'basic',
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import "tailwindcss";
2+
3+
@theme {
4+
--color-tomato: tomato;
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div class="sm:bg-tomato bg-red-500"></div>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div class="bg-red-500 sm:bg-tomato"></div>

tests/fixtures/no-local-version/package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)