Skip to content

Commit

Permalink
Hoist @import nodes to the top in the project locator
Browse files Browse the repository at this point in the history
This ensures project initialization can proceed far enough that Tailwind CSS itself should attempt to initalize. It also means we can reliably detect this case and show an error in the console.
  • Loading branch information
thecrypticace committed Jan 9, 2025
1 parent 009c0c5 commit 85b1042
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,39 @@ import { Resolver } from '../resolver'

export function resolveCssImports({
resolver,
loose = false,
}: {
resolver: Resolver
loose?: boolean
}) {
return postcss([
// Hoist imports to the top of the file
{
postcssPlugin: 'hoist-at-import',
Once(root, { result }) {
if (!loose) return

let hoist: postcss.AtRule[] = []
let seenImportsAfterOtherNodes = false

for (let node of root.nodes) {
if (node.type === 'atrule' && (node.name === 'import' || node.name === 'charset')) {
hoist.push(node)
} else if (hoist.length > 0 && (node.type === 'atrule' || node.type === 'rule')) {
seenImportsAfterOtherNodes = true
}
}

root.prepend(hoist)

if (!seenImportsAfterOtherNodes) return

console.log(
`hoist-at-import: The file '${result.opts.from}' contains @import rules after other at rules. This is invalid CSS and may cause problems with your build.`,
)
},
},

postcssImport({
async resolve(id, base) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,11 @@ testFixture('v4/path-mappings', [
],
},
])

testFixture('v4/invalid-import-order', [
//
{
config: 'tailwind.css',
content: ['{URL}/package.json'],
},
])
11 changes: 7 additions & 4 deletions packages/tailwindcss-language-server/src/project-locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,9 @@ class FileEntry {

async resolveImports(resolver: Resolver) {
try {
let result = await resolveCssImports({ resolver }).process(this.content, { from: this.path })
let result = await resolveCssImports({ resolver, loose: true }).process(this.content, {
from: this.path,
})
let deps = result.messages.filter((msg) => msg.type === 'dependency')

deps = deps.filter((msg) => {
Expand All @@ -630,9 +632,10 @@ class FileEntry {

// Replace the file content with the processed CSS
this.content = result.css
} catch {
// TODO: Errors here should be surfaced in tests and possibly the user in
// `trace` logs or something like that
} catch (err) {
console.debug(`Unable to resolve imports for ${this.path}.`)
console.debug(`This may result in failure to locate Tailwind CSS projects.`)
console.error(err)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@layer base {
:root {
font-family: sans-serif;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@layer base {
:root {
--foo: red;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"tailwindcss": "^4.0.0-beta.6"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@import 'tailwindcss';

/*
* This is invalid in this position because some `@import`s are not at the top of the file.
* We don't want project discovery to fail so we hoist them up and then warn in the console.
*/
@variant dark (&:where(.dark, .dark *));

@import './a.css';
@import './b.css';

@theme {
--color-primary: #c0ffee;
}

0 comments on commit 85b1042

Please sign in to comment.