Skip to content

Commit

Permalink
Handle style exports condition when processing @imports (#934)
Browse files Browse the repository at this point in the history
* Refactor

* Support customizing directory of an opened completion document

* Add notes

* Resolve `style` exports field in postcss import

* Update changelog

* Add test

* Refactor

* Make sure the main `style` field is still supported
  • Loading branch information
thecrypticace committed Mar 26, 2024
1 parent 37c4b96 commit cf97d7a
Show file tree
Hide file tree
Showing 17 changed files with 134 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,6 @@ testFixture('v4/multi-config', [
testFixture('v4/workspaces', [
{ config: 'packages/admin/app.css' },
// { config: 'packages/shared/ui.css' }, // Should this be included?
// { config: 'packages/style-export/lib.css' }, // Should this be included?
{ config: 'packages/web/app.css' },
])
6 changes: 2 additions & 4 deletions packages/tailwindcss-language-server/src/project-locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import { CONFIG_GLOB, CSS_GLOB } from './lib/constants'
import { readCssFile } from './util/css'
import { Graph } from './graph'
import type { Message } from 'postcss'
import postcss from 'postcss'
import postcssImport from 'postcss-import'
import { type DocumentSelector, DocumentSelectorPriority } from './projects'
import { CacheMap } from './cache-map'
import { getPackageRoot } from './util/get-package-root'
import resolveFrom from './util/resolveFrom'
import { type Feature, supportedFeatures } from '@tailwindcss/language-service/src/features'
import { pathToFileURL } from 'node:url'
import { resolveCssImports } from './resolve-css-imports'

export interface ProjectConfig {
/** The folder that contains the project */
Expand Down Expand Up @@ -483,7 +482,6 @@ type ConfigEntry = {
content: ContentItem[]
}

let resolveImports = postcss([postcssImport()])
class FileEntry {
content: string | null
deps: Message[] = []
Expand All @@ -504,7 +502,7 @@ class FileEntry {

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

// Replace the file content with the processed CSS
Expand Down
1 change: 1 addition & 0 deletions packages/tailwindcss-language-server/src/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ export async function createProjectService(
originalConfig = { theme: {} }
} catch {
// TODO: Fall back to built-in v4 stuff
// TODO: Log errors? It might get noisy as people are editing their CSS though
enabled = false
state.enabled = false
return
Expand Down
24 changes: 24 additions & 0 deletions packages/tailwindcss-language-server/src/resolve-css-imports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import postcss from 'postcss'
import postcssImport from 'postcss-import'
import { createResolver } from './util/resolve'

const resolver = createResolver({
extensions: ['.css'],
mainFields: ['style'],
conditionNames: ['style'],
})

const resolveImports = postcss([
postcssImport({
resolve(id, basedir) {
let paths = resolver.resolveSync({}, basedir, id)
return paths
? paths
: id
},
}),
])

export function resolveCssImports() {
return resolveImports
}
16 changes: 16 additions & 0 deletions packages/tailwindcss-language-server/src/util/resolve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as fs from 'fs'
import {
CachedInputFileSystem,
ResolverFactory,
Resolver,
ResolveOptions,
} from 'enhanced-resolve-301'

export function createResolver(options: Partial<ResolveOptions> = {}): Resolver {
return ResolverFactory.createResolver({
fileSystem: new CachedInputFileSystem(fs, 4000),
useSyncFileSystemCalls: true,
conditionNames: ['node', 'require'],
...options,
})
}
26 changes: 6 additions & 20 deletions packages/tailwindcss-language-server/src/util/resolveFrom.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
import * as fs from 'fs'
import {
CachedInputFileSystem,
ResolverFactory,
Resolver,
ResolveOptions,
} from 'enhanced-resolve-301'
import { equal } from '@tailwindcss/language-service/src/util/array'
import { createResolver } from './resolve'

let pnpApi: any
let extensions = Object.keys(require.extensions)

function createResolver(options: Partial<ResolveOptions> = {}): Resolver {
return ResolverFactory.createResolver({
fileSystem: new CachedInputFileSystem(fs, 4000),
useSyncFileSystemCalls: true,
// cachePredicate: () => false,
conditionNames: ['node', 'require'],
extensions,
pnpApi,
...options,
})
function recreateResolver() {
return createResolver({ extensions, pnpApi })
}

let resolver = createResolver()
let resolver = recreateResolver()

export function setPnpApi(newPnpApi: any): void {
pnpApi = newPnpApi
resolver = createResolver()
resolver = recreateResolver()
}

export default function resolveFrom(from?: string, id?: string): string {
Expand All @@ -35,7 +21,7 @@ export default function resolveFrom(from?: string, id?: string): string {
let newExtensions = Object.keys(require.extensions)
if (!equal(newExtensions, extensions)) {
extensions = newExtensions
resolver = createResolver()
resolver = recreateResolver()
}

let result = resolver.resolveSync({}, from, id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import type { DesignSystem } from '@tailwindcss/language-service/src/util/v4'

import postcss from 'postcss'
import postcssImport from 'postcss-import'

const resolveImports = postcss([postcssImport()])
import { resolveCssImports } from '../../resolve-css-imports'

const HAS_V4_IMPORT = /@import\s*(?:'tailwindcss'|"tailwindcss")/
const HAS_V4_THEME = /@theme\s*\{/
Expand Down Expand Up @@ -36,7 +34,7 @@ export async function loadDesignSystem(
// Step 2: Use postcss to resolve `@import` rules in the CSS file
// TODO: What if someone is actively editing their config and introduces a syntax error?
// We don't want to necessarily throw away the knowledge that we have a v4 project.
let resolved = await resolveImports.process(css, { from: filepath })
let resolved = await resolveCssImports().process(css, { from: filepath })

// Step 3: Take the resolved CSS and pass it to v4's `loadDesignSystem`
let design = tailwindcss.__unstable__loadDesignSystem(resolved.css) as DesignSystem
Expand Down
2 changes: 2 additions & 0 deletions packages/tailwindcss-language-server/tests/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ async function init(fixture: string): Promise<FixtureContext> {
},
} as DidOpenTextDocumentParams)

// If opening a document stalls then it's probably because this promise is not being resolved
// This can happen if a document is not covered by one of the selectors because of it's URI
await initPromise

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ function buildCompletion(c) {
triggerKind: 1,
},
settings,
dir = '',
}) {
let textDocument = await c.openDocument({ text, lang, settings })
let textDocument = await c.openDocument({ text, lang, settings, dir })

return c.sendRequest('textDocument/completion', {
textDocument,
Expand Down Expand Up @@ -552,3 +553,42 @@ withFixture('v4/basic', (c) => {
})
})
})

withFixture('v4/workspaces', (c) => {
let completion = buildCompletion(c)

test('@import resolution supports exports.style', async ({ expect }) => {
let result = await completion({
dir: 'packages/web',
lang: 'html',
text: '<div class=""></div>',
position: { line: 0, character: 12 },
})

let items = [
result.items.find((item) => item.label === 'bg-beet'),
result.items.find((item) => item.label === 'bg-orangepeel'),
result.items.find((item) => item.label === 'bg-style-main'),
]

let resolved = await Promise.all(items.map((item) => c.sendRequest('completionItem/resolve', item)))

expect(resolved[0]).toEqual({
...items[0],
detail: 'background-color: #8e3b46;',
documentation: '#8e3b46',
})

expect(resolved[1]).toEqual({
...items[1],
detail: 'background-color: #ff9f00;',
documentation: '#ff9f00',
})

expect(resolved[2]).toEqual({
...items[2],
detail: 'background-color: #8e3b46;',
documentation: '#8e3b46',
})
})
})

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,3 @@
@theme {
--color-beet: #8e3b46;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@private/style-export",
"exports": {
".": {
"style": "./lib.css"
},
"./theme": "./theme.css"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@theme {
--color-orangepeel: #ff9f00;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@theme {
--color-style-main: #8e3b46;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@private/style-main-field",
"style": "./lib.css"
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
@import 'tailwindcss';
@import '@private/shared/ui.css';
@import '@private/style-export';
@import '@private/style-export/theme';
@import '@private/style-main-field';

@theme {
--color-potato: #907a70;
}
1 change: 1 addition & 0 deletions packages/vscode-tailwindcss/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Fix hovers and CSS conflict detection in Vue `<style lang="sass">` blocks (#930)
- Add support for `<script type="text/babel">` (#932)
- Show pixel equivalents in completions and hovers of the theme() helper (#935)
- Handle `style` exports condition when processing `@import`s (#934)

## 0.10.5

Expand Down

0 comments on commit cf97d7a

Please sign in to comment.