Vite: Fix issues when loading files via static asset queries (#14716)
Fixes: #14558 This PR fixes an issue where our Vite plugin would crash when trying to load stylesheets via certain static asset query parameters: ```ts import raw from './style.css?raw' import url from './style.css?url' ``` The proper behavior for our extension is to _not touch these file at all_. The `?raw` identifier should never transform anything and the `?url` one will emit a module which points to the asset URL. However, if that URL is loaded as a stylesheet, another transform hook is called and the file is properly transformed. I verified this in the Vite setup and have added an integration test ensuring these two features work as expected. I've also greatly reduced the complexity of the Vite playground to make it easier to set up examples like this in the future.
This commit is contained in:
parent
557ed8ccec
commit
d59f1b3e5d
15 changed files with 75 additions and 88 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
<head>
|
||||
<script type="module" src="./src/index.js"></script>
|
||||
</head>
|
||||
`,
|
||||
'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]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('tailwindcss-animate')
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
import { Foo } from './foo'
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<div className="m-3 p-3 border">
|
||||
<h1 className="text-blue-500">Hello World</h1>
|
||||
<button className="hocus:underline">Click me</button>
|
||||
<Foo />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
export function Bar() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-red-500 underline">Bar</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { Bar } from './bar'
|
||||
|
||||
export function Foo() {
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-blue-500">Foo</h2>
|
||||
<Bar />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('@tailwindcss/forms')
|
||||
|
|
@ -1,2 +1 @@
|
|||
@import 'tailwindcss';
|
||||
@plugin "./plugin.js";
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>≈ Playground</title>
|
||||
<link rel="stylesheet" href="./app.css" />
|
||||
</head>
|
||||
<body class="h-full">
|
||||
<div id="app"></div>
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
module.exports = function ({ addVariant }) {
|
||||
addVariant('inverted', '@media (inverted-colors: inverted)')
|
||||
addVariant('hocus', ['&:focus', '&:hover'])
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('@tailwindcss/typography')
|
||||
55
pnpm-lock.yaml
generated
55
pnpm-lock.yaml
generated
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue