diff --git a/CHANGELOG.md b/CHANGELOG.md index 13acdc3183d1..43725914687e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure color opacity modifiers work with OKLCH colors ([#14741](https://github.com/tailwindlabs/tailwindcss/pull/14741)) - Ensure changes to the input CSS file result in a full rebuild ([#14744](https://github.com/tailwindlabs/tailwindcss/pull/14744)) - Add `postcss` as a dependency of `@tailwindcss/postcss` ([#14750](https://github.com/tailwindlabs/tailwindcss/pull/14750)) +- Ensure loading stylesheets via the `?raw` and `?url` static asset query works when using the Vite plugin ([#14716](https://github.com/tailwindlabs/tailwindcss/pull/14716)) - _Upgrade (experimental)_: Migrate `flex-grow` to `grow` and `flex-shrink` to `shrink` ([#14721](https://github.com/tailwindlabs/tailwindcss/pull/14721)) - _Upgrade (experimental)_: Minify arbitrary values when printing candidates ([#14720](https://github.com/tailwindlabs/tailwindcss/pull/14720)) - _Upgrade (experimental)_: Ensure legacy theme values ending in `1` (like `theme(spacing.1)`) are correctly migrated to custom properties ([#14724](https://github.com/tailwindlabs/tailwindcss/pull/14724)) diff --git a/integrations/vite/index.test.ts b/integrations/vite/index.test.ts index f56575c1a8ec..89814ccc6168 100644 --- a/integrations/vite/index.test.ts +++ b/integrations/vite/index.test.ts @@ -504,3 +504,64 @@ test( }) }, ) + +test( + `does not interfere with ?raw and ?url static asset handling`, + { + fs: { + 'package.json': json` + { + "type": "module", + "dependencies": { + "@tailwindcss/vite": "workspace:^", + "tailwindcss": "workspace:^" + }, + "devDependencies": { + "vite": "^5.3.5" + } + } + `, + 'vite.config.ts': ts` + import tailwindcss from '@tailwindcss/vite' + import { defineConfig } from 'vite' + + export default defineConfig({ + build: { cssMinify: false }, + plugins: [tailwindcss()], + }) + `, + 'index.html': html` + + + + `, + 'src/index.js': js` + import url from './index.css?url' + import raw from './index.css?raw' + `, + 'src/index.css': css`@import 'tailwindcss';`, + }, + }, + async ({ spawn, getFreePort }) => { + let port = await getFreePort() + await spawn(`pnpm vite dev --port ${port}`) + + await retryAssertion(async () => { + // We have to load the .js file first so that the static assets are + // resolved + await fetch(`http://localhost:${port}/src/index.js`).then((r) => r.text()) + + let [raw, url] = await Promise.all([ + fetch(`http://localhost:${port}/src/index.css?raw`).then((r) => r.text()), + fetch(`http://localhost:${port}/src/index.css?url`).then((r) => r.text()), + ]) + + expect(firstLine(raw)).toBe(`export default "@import 'tailwindcss';"`) + expect(firstLine(url)).toBe(`export default "/src/index.css"`) + }) + }, +) + +function firstLine(str: string) { + return str.split('\n')[0] +} diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts index abb13a613f26..9571342cdbda 100644 --- a/packages/@tailwindcss-vite/src/index.ts +++ b/packages/@tailwindcss-vite/src/index.ts @@ -5,6 +5,8 @@ import { Features, transform } from 'lightningcss' import path from 'path' import type { Plugin, ResolvedConfig, Rollup, Update, ViteDevServer } from 'vite' +const SPECIAL_QUERY_RE = /[?&](raw|url)\b/ + export default function tailwindcss(): Plugin[] { let servers: ViteDevServer[] = [] let config: ResolvedConfig | null = null @@ -261,9 +263,12 @@ function getExtension(id: string) { function isPotentialCssRootFile(id: string) { let extension = getExtension(id) let isCssFile = - extension === 'css' || - (extension === 'vue' && id.includes('&lang.css')) || - (extension === 'astro' && id.includes('&lang.css')) + (extension === 'css' || + (extension === 'vue' && id.includes('&lang.css')) || + (extension === 'astro' && id.includes('&lang.css'))) && + // Don't intercept special static asset resources + !SPECIAL_QUERY_RE.test(id) + return isCssFile } diff --git a/playgrounds/vite/package.json b/playgrounds/vite/package.json index 846b96252efd..a5a953a14cc8 100644 --- a/playgrounds/vite/package.json +++ b/playgrounds/vite/package.json @@ -19,7 +19,6 @@ "@types/react": "^18.3.9", "@types/react-dom": "^18.3.1", "bun": "^1.1.29", - "vite": "catalog:", - "vite-plugin-handlebars": "^2.0.0" + "vite": "catalog:" } } diff --git a/playgrounds/vite/src/animate.js b/playgrounds/vite/src/animate.js deleted file mode 100644 index 0a5617399262..000000000000 --- a/playgrounds/vite/src/animate.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('tailwindcss-animate') diff --git a/playgrounds/vite/src/app.tsx b/playgrounds/vite/src/app.tsx index 285bd41439de..8ec50298951f 100644 --- a/playgrounds/vite/src/app.tsx +++ b/playgrounds/vite/src/app.tsx @@ -1,11 +1,7 @@ -import { Foo } from './foo' - export function App() { return (

Hello World

- -
) } diff --git a/playgrounds/vite/src/bar.tsx b/playgrounds/vite/src/bar.tsx deleted file mode 100644 index 1efa2c004851..000000000000 --- a/playgrounds/vite/src/bar.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export function Bar() { - return ( -
-

Bar

-
- ) -} diff --git a/playgrounds/vite/src/foo.tsx b/playgrounds/vite/src/foo.tsx deleted file mode 100644 index 60ec68b5517e..000000000000 --- a/playgrounds/vite/src/foo.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Bar } from './bar' - -export function Foo() { - return ( -
-

Foo

- -
- ) -} diff --git a/playgrounds/vite/src/forms.js b/playgrounds/vite/src/forms.js deleted file mode 100644 index f288ddfa0763..000000000000 --- a/playgrounds/vite/src/forms.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@tailwindcss/forms') diff --git a/playgrounds/vite/src/app.css b/playgrounds/vite/src/index.css similarity index 50% rename from playgrounds/vite/src/app.css rename to playgrounds/vite/src/index.css index adbd8e19f9b0..d4b5078586e2 100644 --- a/playgrounds/vite/src/app.css +++ b/playgrounds/vite/src/index.css @@ -1,2 +1 @@ @import 'tailwindcss'; -@plugin "./plugin.js"; diff --git a/playgrounds/vite/src/index.html b/playgrounds/vite/src/index.html index d4b60a84a8fe..858e0cf2fccf 100644 --- a/playgrounds/vite/src/index.html +++ b/playgrounds/vite/src/index.html @@ -4,7 +4,6 @@ ≈ Playground -
diff --git a/playgrounds/vite/src/main.tsx b/playgrounds/vite/src/main.tsx index b8df681f3d23..6b81fa9158cb 100644 --- a/playgrounds/vite/src/main.tsx +++ b/playgrounds/vite/src/main.tsx @@ -2,6 +2,8 @@ import React from 'react' import ReactDOM from 'react-dom/client' import { App } from './app' +import './index.css' + ReactDOM.createRoot(document.getElementById('app')!).render( diff --git a/playgrounds/vite/src/plugin.js b/playgrounds/vite/src/plugin.js deleted file mode 100644 index 0852126714ec..000000000000 --- a/playgrounds/vite/src/plugin.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = function ({ addVariant }) { - addVariant('inverted', '@media (inverted-colors: inverted)') - addVariant('hocus', ['&:focus', '&:hover']) -} diff --git a/playgrounds/vite/src/typography.js b/playgrounds/vite/src/typography.js deleted file mode 100644 index 711af27f791f..000000000000 --- a/playgrounds/vite/src/typography.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@tailwindcss/typography') diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a13e857113a4..ba225832c5a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -435,9 +435,6 @@ importers: vite: specifier: 'catalog:' version: 5.4.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6) - vite-plugin-handlebars: - specifier: ^2.0.0 - version: 2.0.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6) packages: @@ -1941,11 +1938,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true - has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -2352,9 +2344,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - next@14.1.0: resolution: {integrity: sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==} engines: {node: '>=18.17.0'} @@ -3007,11 +2996,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - uglify-js@3.19.1: - resolution: {integrity: sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A==} - engines: {node: '>=0.8.0'} - hasBin: true - unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -3039,9 +3023,6 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-plugin-handlebars@2.0.0: - resolution: {integrity: sha512-+J3It0nyhPzx4nT1I+fnWH+jShTEXzm6X0Tgsggdm9IYFD7/eJ6a3ROI13HTe0CVoyaxm/fPxH5HDAKyfz7T0g==} - vite@5.4.0: resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -3133,9 +3114,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -4739,15 +4717,6 @@ snapshots: graceful-fs@4.2.11: {} - handlebars@4.7.8: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.1 - has-bigints@1.0.2: {} has-flag@3.0.0: {} @@ -5088,8 +5057,6 @@ snapshots: natural-compare@1.4.0: {} - neo-async@2.6.2: {} - next@14.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 14.1.0 @@ -5486,7 +5453,8 @@ snapshots: source-map: 0.6.1 optional: true - source-map@0.6.1: {} + source-map@0.6.1: + optional: true source-map@0.8.0-beta.0: dependencies: @@ -5761,9 +5729,6 @@ snapshots: typescript@5.5.4: {} - uglify-js@3.19.1: - optional: true - unbox-primitive@1.0.2: dependencies: call-bind: 1.0.7 @@ -5805,20 +5770,6 @@ snapshots: - supports-color - terser - vite-plugin-handlebars@2.0.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6): - dependencies: - handlebars: 4.7.8 - vite: 5.4.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - terser - vite@5.4.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6): dependencies: esbuild: 0.21.5 @@ -5920,8 +5871,6 @@ snapshots: word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0