Jordan Pittman cdc851d3f8
Don't inline all env vars in Standalone CLI (#19391)
Fixes #19389

We inlined env vars in the Standalone CLI because we use some custom
patches + env vars to ensure that only the appropriate `glibc` / `musl`
binaries are included for Lightning CSS and Parcel Watcher for Linux
builds.

The build happens to run on a macOS Github CI machine though so
`NODE_PATH` was getting inlined as the string:
```
/Users/runner/work/tailwindcss/tailwindcss/node_modules/.pnpm/bun@1.3.0/node_modules/bun/bin/node_modules
```

I don't think there's a reason for `NODE_PATH` to work on the Standalone
CLI (and it didn't work because of the above bug *anyway*) so I've done
a few things here:
1. The build setup now uses `Bun.build(…)` which now supports compiling
binaries. This speeds up the build process a bit.
2. We're no longer inlining all env vars. We selectively inline only a
few using `define`.
3. I've explicitly disabled the extra `NODE_PATH` support in
`@tailwindcss/node` when building with the Standalone CLI.
4. The `__tw_readFile` hack is now gone. Async FS APIs were not
originally able to read embedded files but that changed in Bun v1.2.3
making the hack unnecessary.
5. A few more env vars are now inlined + a plugin to simplify the Oxide
loading code when bundled.
6. A plugin + env vars prevents bundling WASI build as it's not
necessary for the Standalone CLI.

I want to find a way to get rid of `__tw_resolve` and `__tw_load` but
don't want to change too much in this PR so I haven't looked into it
yet.
2025-12-08 11:23:20 -05:00

101 lines
3.2 KiB
TypeScript

import { createRequire } from 'node:module'
import packageJson from 'tailwindcss/package.json'
import indexCss from 'tailwindcss/index.css' with { type: 'file' }
import preflightCss from 'tailwindcss/preflight.css' with { type: 'file' }
import themeCss from 'tailwindcss/theme.css' with { type: 'file' }
import utilitiesCss from 'tailwindcss/utilities.css' with { type: 'file' }
const localResolve = createRequire(import.meta.url).resolve
globalThis.__tw_resolve = (id, baseDir) => {
let isEmbeddedFileBase = baseDir === '/$bunfs/root' || baseDir?.includes(':/~BUN/root')
const likelyEmbeddedFile =
id === 'tailwindcss' ||
id.startsWith('tailwindcss/') ||
id.startsWith('@tailwindcss/') ||
isEmbeddedFileBase
if (!likelyEmbeddedFile) {
return false
}
id = id.startsWith('tailwindcss/')
? id.slice(12)
: isEmbeddedFileBase && id.startsWith('./')
? id.slice(2)
: id
switch (id) {
case 'index':
case 'index.css':
case 'tailwindcss':
return localResolve(indexCss)
case 'theme':
case 'theme.css':
return localResolve(themeCss)
case 'preflight':
case 'preflight.css':
return localResolve(preflightCss)
case 'utilities':
case 'utilities.css':
return localResolve(utilitiesCss)
case '@tailwindcss/forms':
case '@tailwindcss/typography':
case '@tailwindcss/aspect-ratio':
return id
default:
return false
}
}
globalThis.__tw_load = async (id) => {
if (id.endsWith('@tailwindcss/forms')) {
return require('@tailwindcss/forms')
} else if (id.endsWith('@tailwindcss/typography')) {
return require('@tailwindcss/typography')
} else if (id.endsWith('@tailwindcss/aspect-ratio')) {
return require('@tailwindcss/aspect-ratio')
} else {
return undefined
}
}
globalThis.__tw_version = packageJson.version
// We use a plugin to make sure that the JS APIs are bundled with the standalone
// CLI and can be imported inside configs and plugins
Bun.plugin({
name: 'bundle-tailwindcss-apis',
target: 'bun',
async setup(build) {
// These imports must be static strings otherwise they won't be bundled
let bundled = {
tailwindcss: await import('tailwindcss'),
'tailwindcss/colors': await import('tailwindcss/colors'),
'tailwindcss/colors.js': await import('tailwindcss/colors'),
'tailwindcss/plugin': await import('tailwindcss/plugin'),
'tailwindcss/plugin.js': await import('tailwindcss/plugin'),
'tailwindcss/package.json': await import('tailwindcss/package.json'),
'tailwindcss/lib/util/flattenColorPalette': await import(
'tailwindcss/lib/util/flattenColorPalette'
),
'tailwindcss/lib/util/flattenColorPalette.js': await import(
'tailwindcss/lib/util/flattenColorPalette'
),
'tailwindcss/defaultTheme': await import('tailwindcss/defaultTheme'),
'tailwindcss/defaultTheme.js': await import('tailwindcss/defaultTheme'),
}
for (let [id, exports] of Object.entries(bundled)) {
build.module(id, () => ({
loader: 'object',
exports: {
...exports,
__esModule: true,
},
}))
}
},
})
await import('../../@tailwindcss-cli/src/index.ts')