Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Vite issues with SolidStart #16052

Merged
merged 7 commits into from
Jan 30, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Only generate positive `grid-cols-*` and `grid-rows-*` utilities ([#16020](https://github.com/tailwindlabs/tailwindcss/pull/16020))
- Ensure we process Tailwind CSS features when only using `@reference` or `@variant` ([#16057](https://github.com/tailwindlabs/tailwindcss/pull/16057))
- Refactor gradient implementation to work around [prettier/prettier#17058](https://github.com/prettier/prettier/issues/17058) ([#16072](https://github.com/tailwindlabs/tailwindcss/pull/16072))
- Vite: Ensure hot-reloading works with SolidStart setups ([#16052](https://github.com/tailwindlabs/tailwindcss/pull/16052))
- Vite: Fix a crash when starting the development server in SolidStart setups ([#16052](https://github.com/tailwindlabs/tailwindcss/pull/16052))

## [4.0.1] - 2025-01-29

108 changes: 108 additions & 0 deletions integrations/vite/solidstart.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { candidate, css, fetchStyles, js, json, retryAssertion, test, ts } from '../utils'

const WORKSPACE = {
'package.json': json`
{
"type": "module",
"dependencies": {
"@solidjs/start": "^1",
"solid-js": "^1",
"vinxi": "^0",
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
}
}
`,
'jsconfig.json': json`
{
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "solid-js"
}
}
`,
'app.config.js': ts`
import { defineConfig } from '@solidjs/start/config'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
vite: {
plugins: [tailwindcss()],
},
})
`,
'src/entry-server.jsx': js`
// @refresh reload
import { createHandler, StartServer } from '@solidjs/start/server'

export default createHandler(() => (
<StartServer
document={({ assets, children, scripts }) => (
<html lang="en">
<head>{assets}</head>
<body>
<div id="app">{children}</div>
{scripts}
</body>
</html>
)}
/>
))
`,
'src/entry-client.jsx': js`
// @refresh reload
import { mount, StartClient } from '@solidjs/start/client'

mount(() => <StartClient />, document.getElementById('app'))
`,
'src/app.jsx': js`
import './app.css'
export default function App() {
return <h1 class="underline">Hello world!</h1>
}
`,
'src/app.css': css`@import 'tailwindcss';`,
}

test(
'dev mode',
{
fs: WORKSPACE,
},
async ({ fs, spawn, expect }) => {
let process = await spawn('pnpm vinxi dev', {
env: {
TEST: 'false', // VERY IMPORTANT OTHERWISE YOU WON'T GET OUTPUT
NODE_ENV: 'development',
Comment on lines +75 to +76
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

},
})

let url = ''
await process.onStdout((m) => {
let match = /Local:\s*(http.*)\//.exec(m)
if (match) url = match[1]
return Boolean(url)
})

await retryAssertion(async () => {
let css = await fetchStyles(url)
expect(css).toContain(candidate`underline`)
})

await retryAssertion(async () => {
await fs.write(
'src/app.jsx',
js`
import './app.css'
export default function App() {
return <h1 class="underline font-bold">Hello world!</h1>
}
`,
)

let css = await fetchStyles(url)
expect(css).toContain(candidate`underline`)
expect(css).toContain(candidate`font-bold`)
})
},
)
28 changes: 10 additions & 18 deletions packages/@tailwindcss-vite/src/index.ts
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ export default function tailwindcss(): Plugin[] {
)
})

function scanFile(id: string, content: string, extension: string, isSSR: boolean) {
function scanFile(id: string, content: string, extension: string) {
for (let dependency of IGNORED_DEPENDENCIES) {
// We validated that Vite IDs always use posix style path separators, even on Windows.
// In dev build, Vite precompiles dependencies
@@ -83,26 +83,16 @@ export default function tailwindcss(): Plugin[] {
}

if (updated) {
invalidateAllRoots(isSSR)
invalidateAllRoots()
}
}

function invalidateAllRoots(isSSR: boolean) {
function invalidateAllRoots() {
for (let server of servers) {
let updates: Update[] = []
for (let [id, root] of roots.entries()) {
for (let [id] of roots.entries()) {
let module = server.moduleGraph.getModuleById(id)
if (!module) {
// Note: Removing this during SSR is not safe and will produce
// inconsistent results based on the timing of the removal and
// the order / timing of transforms.
if (!isSSR) {
Comment on lines -96 to -99
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure why this is safe to do this unconditionally. Is it just because we are never removing any roots anymore?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're no longer calling roots.delete(id) so this check can be removed too, not sure I understand your question correctly tho? 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm being a dumb dumb, carry on.

// It is safe to remove the item here since we're iterating on a copy
// of the keys.
roots.delete(id)
}
continue
}
if (!module) continue

roots.get(id).requiresRebuild = false
server.moduleGraph.invalidateModule(module)
@@ -113,7 +103,6 @@ export default function tailwindcss(): Plugin[] {
timestamp: Date.now(),
})
}

if (updates.length > 0) {
server.hot.send({ type: 'update', updates })
}
@@ -210,12 +199,15 @@ export default function tailwindcss(): Plugin[] {

// Scan all non-CSS files for candidates
transformIndexHtml(html, { path }) {
scanFile(path, html, 'html', isSSR)
// SolidStart emits HTML chunks with an undefined path and the html content of `\`.
if (!path) return

scanFile(path, html, 'html')
},
transform(src, id, options) {
let extension = getExtension(id)
if (isPotentialCssRootFile(id)) return
scanFile(id, src, extension, options?.ssr ?? false)
scanFile(id, src, extension)
},
},