Skip to content

Commit e4bfa8c

Browse files
Bundle core plugins with the standalone build (#15028)
Closes #15012 We do not have replacements for these plugins _just yet_. In order to increase compatibility with setups that rely on some of these legacy plugins, this PR bundles `@tailwindcss/forms`, `@tailwindcss/typography`, and `@tailwindcss/aspect-ratio` (after #15029) with the standalone build now. In comparison to v3, this omits the `@tailwindcss/container-queries` plugin since is not a first-party feature of Tailwind CSS v4. ## Test Plan Added an integration test. I also tested this by running the standalone binary in a temporary folder with as simple input css: ```css @import "tailwindcss"; @plugin "@tailwindcss/typography"; ```
1 parent b73c746 commit e4bfa8c

File tree

7 files changed

+162
-1
lines changed

7 files changed

+162
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Reintroduce `max-w-screen-*` utilities that read from the `--breakpoint` namespace as deprecated utilities ([#15013](https://github.com/tailwindlabs/tailwindcss/pull/15013))
1313
- Support using CSS variables as arbitrary values without `var(…)` by using parentheses instead of square brackets (e.g. `bg-(--my-color)`) ([#15020](https://github.com/tailwindlabs/tailwindcss/pull/15020))
1414
- Add new `in-*` variant ([#15025](https://github.com/tailwindlabs/tailwindcss/pull/15025))
15+
- Bundle `@tailwindcss/forms`, `@tailwindcss/typography`, and `@tailwindcss/aspect-ratio` with the standalone CLI ([#15028](https://github.com/tailwindlabs/tailwindcss/pull/15028))
1516
- Allow `addUtilities()` and `addComponents()` to work with child combinators and other complex selectors ([#15029](https://github.com/tailwindlabs/tailwindcss/pull/15029))
1617
- Support colors that use `<alpha-value>` in JS configs and plugins ([#15033](https://github.com/tailwindlabs/tailwindcss/pull/15033))
1718
- _Upgrade (experimental)_: Migrate `[&>*]` to the `*` variant ([#15022](https://github.com/tailwindlabs/tailwindcss/pull/15022))

integrations/cli/standalone.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import os from 'node:os'
2+
import path from 'node:path'
3+
import { candidate, css, html, json, test } from '../utils'
4+
5+
const STANDALONE_BINARY = (() => {
6+
switch (os.platform()) {
7+
case 'win32':
8+
return 'tailwindcss-windows-x64.exe'
9+
case 'darwin':
10+
return os.arch() === 'x64' ? 'tailwindcss-macos-x64' : 'tailwindcss-macos-arm64'
11+
case 'linux':
12+
return os.arch() === 'x64' ? 'tailwindcss-linux-x64' : 'tailwindcss-linux-arm64'
13+
default:
14+
throw new Error(`Unsupported platform: ${os.platform()} ${os.arch()}`)
15+
}
16+
})()
17+
18+
test(
19+
'includes first-party plugins',
20+
{
21+
fs: {
22+
'package.json': json`
23+
{
24+
"dependencies": {
25+
"tailwindcss": "workspace:^",
26+
"@tailwindcss/cli": "workspace:^"
27+
}
28+
}
29+
`,
30+
'index.html': html`
31+
<div className="prose">
32+
<h1>Headline</h1>
33+
</div>
34+
<input type="text" class="form-input" />
35+
<div class="aspect-w-16"></div>
36+
`,
37+
'src/index.css': css`
38+
@import 'tailwindcss/theme' theme(reference);
39+
@import 'tailwindcss/utilities';
40+
41+
@plugin '@tailwindcss/forms';
42+
@plugin '@tailwindcss/typography';
43+
@plugin '@tailwindcss/aspect-ratio';
44+
`,
45+
},
46+
},
47+
async ({ fs, exec }) => {
48+
await exec(
49+
`${path.resolve(__dirname, `../../packages/@tailwindcss-standalone/dist/${STANDALONE_BINARY}`)} --input src/index.css --output dist/out.css`,
50+
)
51+
52+
await fs.expectFileToContain('dist/out.css', [
53+
candidate`form-input`,
54+
candidate`prose`,
55+
candidate`aspect-w-16`,
56+
])
57+
},
58+
)

packages/@tailwindcss-node/src/compile.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export async function loadModule(id: string, base: string, onDependency: (path:
9898
if (!resolvedPath) {
9999
throw new Error(`Could not resolve '${id}' from '${base}'`)
100100
}
101+
101102
let [module, moduleDependencies] = await Promise.all([
102103
importModule(pathToFileURL(resolvedPath).href + '?id=' + Date.now()),
103104
getModuleDependencies(resolvedPath),
@@ -140,6 +141,13 @@ async function loadStylesheet(id: string, base: string, onDependency: (path: str
140141
// can be resolved properly.
141142
let jiti: null | Jiti = null
142143
async function importModule(path: string): Promise<any> {
144+
if (typeof globalThis.__tw_load === 'function') {
145+
let module = await globalThis.__tw_load(path)
146+
if (module) {
147+
return module
148+
}
149+
}
150+
143151
try {
144152
return await import(path)
145153
} catch (error) {
@@ -174,6 +182,12 @@ const jsResolver = EnhancedResolve.ResolverFactory.createResolver({
174182
})
175183

176184
function resolveJsId(id: string, base: string): Promise<string | false | undefined> {
185+
if (typeof globalThis.__tw_resolve === 'function') {
186+
let resolved = globalThis.__tw_resolve(id, base)
187+
if (resolved) {
188+
return Promise.resolve(resolved)
189+
}
190+
}
177191
return runResolver(jsResolver, id, base)
178192
}
179193

packages/@tailwindcss-standalone/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
"dist"
2626
],
2727
"dependencies": {
28+
"@tailwindcss/aspect-ratio": "^0.4.2",
2829
"@tailwindcss/cli": "workspace:^",
30+
"@tailwindcss/forms": "^0.5.9",
31+
"@tailwindcss/typography": "^0.5.15",
2932
"detect-libc": "1.0.3",
3033
"enhanced-resolve": "^5.17.1",
3134
"tailwindcss": "workspace:^"

packages/@tailwindcss-standalone/src/index.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ const localResolve = createRequire(import.meta.url).resolve
1212
globalThis.__tw_resolve = (id, baseDir) => {
1313
let isEmbeddedFileBase = baseDir === '/$bunfs/root' || baseDir?.includes(':/~BUN/root')
1414
const likelyEmbeddedFile =
15-
id === 'tailwindcss' || id.startsWith('tailwindcss/') || isEmbeddedFileBase
15+
id === 'tailwindcss' ||
16+
id.startsWith('tailwindcss/') ||
17+
id.startsWith('@tailwindcss/') ||
18+
isEmbeddedFileBase
1619

1720
if (!likelyEmbeddedFile) {
1821
return false
@@ -38,10 +41,25 @@ globalThis.__tw_resolve = (id, baseDir) => {
3841
case 'utilities':
3942
case 'utilities.css':
4043
return localResolve(utilitiesCss)
44+
case '@tailwindcss/forms':
45+
case '@tailwindcss/typography':
46+
case '@tailwindcss/aspect-ratio':
47+
return id
4148
default:
4249
return false
4350
}
4451
}
52+
globalThis.__tw_load = async (id) => {
53+
if (id.endsWith('@tailwindcss/forms')) {
54+
return require('@tailwindcss/forms')
55+
} else if (id.endsWith('@tailwindcss/typography')) {
56+
return require('@tailwindcss/typography')
57+
} else if (id.endsWith('@tailwindcss/aspect-ratio')) {
58+
return require('@tailwindcss/aspect-ratio')
59+
} else {
60+
return undefined
61+
}
62+
}
4563
globalThis.__tw_version = packageJson.version
4664
globalThis.__tw_readFile = async (path, encoding) => {
4765
// When reading a file from the `$bunfs`, we need to use the synchronous

packages/@tailwindcss-standalone/src/types.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ declare var __tw_resolve: undefined | ((id: string, base?: string) => string | f
88
declare var __tw_readFile:
99
| undefined
1010
| ((path: string, encoding: BufferEncoding) => Promise<string | undefined>)
11+
declare var __tw_load: undefined | ((path: string) => Promise<object | undefined>)

pnpm-lock.yaml

Lines changed: 66 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)