Skip to content

Resolve @import in core #14446

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

Merged
merged 51 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
d0ade6f
Add `@import` resolver
philipp-spiess Sep 10, 2024
e5768a1
Add bench
philipp-spiess Sep 11, 2024
fa14f54
Parse @import params
philipp-spiess Sep 11, 2024
911f2f0
wip
philipp-spiess Sep 17, 2024
e3b067d
Make tests pass again
philipp-spiess Sep 18, 2024
89f9db6
Add context node to AST
philipp-spiess Sep 18, 2024
3f065c1
Make resolvers return a new base
philipp-spiess Sep 18, 2024
ed5070e
Handle relative paths in imported files
philipp-spiess Sep 18, 2024
75e888b
Reanem API to loadModule/loadStylesheet
philipp-spiess Sep 19, 2024
9853d47
Fix config resolver to keep track of proper bases
philipp-spiess Sep 19, 2024
fa4b781
Fix css function tests
philipp-spiess Sep 19, 2024
bd605bb
Fix tailwindcss/src/index.test.ts tests
philipp-spiess Sep 19, 2024
0d0c0e6
Fix compat/config.test.ts
philipp-spiess Sep 19, 2024
51f7c55
Fix screens-config.test.ts
philipp-spiess Sep 19, 2024
45e7db3
Work around plugin-api.test.ts changes for now
philipp-spiess Sep 19, 2024
0c4de34
Fix node API by using require.resolve over path.resolve, whoops/
philipp-spiess Sep 19, 2024
615cc99
Fix @tailwindcss/postcss
philipp-spiess Sep 19, 2024
58657bf
Update @tailwindcss/vite
philipp-spiess Sep 19, 2024
87c0bed
Update @tailwindcss/cli
philipp-spiess Sep 19, 2024
3d563c6
Fix linter issues
philipp-spiess Sep 19, 2024
d57dcf3
Remove accidentially commited file
philipp-spiess Sep 19, 2024
d8f5b0a
Use async resolver APIs to avoid blocking core
philipp-spiess Sep 19, 2024
71df1a7
Remove @tailwindcss/internal-postcss-fix-relative-paths
philipp-spiess Sep 19, 2024
cff95a7
Fix type error in plugin-api tests
philipp-spiess Sep 19, 2024
edb1d47
Fix TypeScript issues
philipp-spiess Sep 19, 2024
a11cd80
Cleanup @import resolver
philipp-spiess Sep 19, 2024
4d60a61
Fix context node issue
philipp-spiess Sep 19, 2024
8cc9143
Avoid second walk when resolving `@import`
philipp-spiess Sep 20, 2024
2529aa9
Don't check for `@import` before doing the `@import` walk
philipp-spiess Sep 20, 2024
224ea66
Remove leftover export
philipp-spiess Sep 20, 2024
8124823
Make context nodes transparent in walks
philipp-spiess Sep 20, 2024
fba81c2
Remove leftover context node in buildImportNodes
philipp-spiess Sep 20, 2024
a7d98ad
Add \`resourceHint\` to loadModule callback
philipp-spiess Sep 20, 2024
31ff3eb
Revert screwup
philipp-spiess Sep 20, 2024
8ffad46
Handle recursion
philipp-spiess Sep 20, 2024
b8fbe56
Improve spec compliance
philipp-spiess Sep 20, 2024
026c30c
Add a test case for imports starting with `/`.
philipp-spiess Sep 20, 2024
19ab40d
Move noramlizePath into node lib
philipp-spiess Sep 20, 2024
c733587
revert change in postcss fixture
philipp-spiess Sep 20, 2024
03a3bbc
Move `base` into compiler options
philipp-spiess Sep 20, 2024
2d541e9
Update all plugin-api tests to use `loadModule`
thecrypticace Sep 20, 2024
b59ccc9
Remove .only
philipp-spiess Sep 20, 2024
0dd3a38
Add changelog entry
philipp-spiess Sep 20, 2024
b06d194
Add comment regarding recursion
philipp-spiess Sep 23, 2024
69f4ffc
Gate out http/https resources
philipp-spiess Sep 23, 2024
ecdf002
Make `@import url(...)` pass-through
philipp-spiess Sep 23, 2024
0763a25
Clean up tests
philipp-spiess Sep 23, 2024
e6ee1dc
Change context type
philipp-spiess Sep 23, 2024
2174a5a
Remove `//`
philipp-spiess Sep 23, 2024
8afbcdc
Avoid two-pass resolution for some cases
philipp-spiess Sep 23, 2024
9dd29d0
Don't use regex for case-insensitive string comparisons
philipp-spiess Sep 23, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Disallow negative bare values in core utilities and variants ([#14453](https://github.com/tailwindlabs/tailwindcss/pull/14453))
- Preserve explicit shadow color when overriding shadow size ([#14458](https://github.com/tailwindlabs/tailwindcss/pull/14458))
- Preserve explicit transition duration and timing function when overriding transition property ([#14490](https://github.com/tailwindlabs/tailwindcss/pull/14490))
- Change the implementation for `@import` resolution to speed up initial builds ([#14446](https://github.com/tailwindlabs/tailwindcss/pull/14446))

## [4.0.0-alpha.24] - 2024-09-11

Expand Down
80 changes: 80 additions & 0 deletions integrations/postcss/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,86 @@ test(
},
)

test(
'production build with `postcss-import` (string)',
{
fs: {
'package.json': json`{}`,
'pnpm-workspace.yaml': yaml`
#
packages:
- project-a
`,
'project-a/package.json': json`
{
"dependencies": {
"postcss": "^8",
"postcss-cli": "^10",
"postcss-import": "^16",
"tailwindcss": "workspace:^",
"@tailwindcss/postcss": "workspace:^"
}
}
`,
'project-a/postcss.config.js': js`
module.exports = {
plugins: {
'postcss-import': {},
'@tailwindcss/postcss': {},
},
}
`,
'project-a/index.html': html`
<div
class="underline 2xl:font-bold hocus:underline inverted:flex"
></div>
`,
'project-a/plugin.js': js`
module.exports = function ({ addVariant }) {
addVariant('inverted', '@media (inverted-colors: inverted)')
addVariant('hocus', ['&:focus', '&:hover'])
}
`,
'project-a/tailwind.config.js': js`
module.exports = {
content: ['../project-b/src/**/*.js'],
}
`,
'project-a/src/index.css': css`
@import 'tailwindcss/utilities';
@config '../tailwind.config.js';
@source '../../project-b/src/**/*.html';
@plugin '../plugin.js';
`,
'project-a/src/index.js': js`
const className = "content-['a/src/index.js']"
module.exports = { className }
`,
'project-b/src/index.html': html`
<div class="flex" />
`,
'project-b/src/index.js': js`
const className = "content-['b/src/index.js']"
module.exports = { className }
`,
},
},
async ({ root, fs, exec }) => {
await exec('pnpm postcss src/index.css --output dist/out.css', {
cwd: path.join(root, 'project-a'),
})

await fs.expectFileToContain('project-a/dist/out.css', [
candidate`underline`,
candidate`flex`,
candidate`content-['a/src/index.js']`,
candidate`content-['b/src/index.js']`,
candidate`inverted:flex`,
candidate`hocus:underline`,
])
},
)

test(
'production build (ESM)',
{
Expand Down
6 changes: 0 additions & 6 deletions packages/@tailwindcss-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,6 @@
"lightningcss": "catalog:",
"mri": "^1.2.0",
"picocolors": "^1.0.1",
"postcss-import": "^16.1.0",
"postcss": "^8.4.41",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"@types/postcss-import": "^14.0.3",
"internal-postcss-fix-relative-paths": "workspace:^"
}
}
104 changes: 20 additions & 84 deletions packages/@tailwindcss-cli/src/commands/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import watcher from '@parcel/watcher'
import { compile } from '@tailwindcss/node'
import { clearRequireCache } from '@tailwindcss/node/require-cache'
import { Scanner, type ChangedContent } from '@tailwindcss/oxide'
import fixRelativePathsPlugin from 'internal-postcss-fix-relative-paths'
import { Features, transform } from 'lightningcss'
import { existsSync, readFileSync } from 'node:fs'
import { existsSync } from 'node:fs'
import fs from 'node:fs/promises'
import path from 'node:path'
import postcss from 'postcss'
import atImport from 'postcss-import'
import type { Arg, Result } from '../../utils/args'
import { Disposables } from '../../utils/disposables'
import {
Expand All @@ -19,7 +16,6 @@ import {
println,
relative,
} from '../../utils/renderer'
import { resolveCssId } from '../../utils/resolve'
import { drainStdin, outputFile } from './utils'

const css = String.raw
Expand Down Expand Up @@ -83,17 +79,13 @@ export async function handle(args: Result<ReturnType<typeof options>>) {

let start = process.hrtime.bigint()

// Resolve the input
let [input, cssImportPaths] = await handleImports(
args['--input']
? args['--input'] === '-'
? await drainStdin()
: await fs.readFile(args['--input'], 'utf-8')
: css`
@import 'tailwindcss';
`,
args['--input'] ?? base,
)
let input = args['--input']
? args['--input'] === '-'
? await drainStdin()
: await fs.readFile(args['--input'], 'utf-8')
: css`
@import 'tailwindcss';
`

let previous = {
css: '',
Expand Down Expand Up @@ -128,7 +120,7 @@ export async function handle(args: Result<ReturnType<typeof options>>) {

let inputFile = args['--input'] && args['--input'] !== '-' ? args['--input'] : process.cwd()
let inputBasePath = path.dirname(path.resolve(inputFile))
let fullRebuildPaths: string[] = cssImportPaths.slice()
let fullRebuildPaths: string[] = []

function createCompiler(css: string) {
return compile(css, {
Expand All @@ -143,12 +135,7 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
let compiler = await createCompiler(input)
let scanner = new Scanner({
detectSources: { base },
sources: compiler.globs.map(({ origin, pattern }) => ({
// Ensure the glob is relative to the input CSS file or the config file
// where it is specified.
base: origin ? path.dirname(path.resolve(inputBasePath, origin)) : inputBasePath,
pattern,
})),
sources: compiler.globs,
})

// Watch for changes
Expand Down Expand Up @@ -196,30 +183,24 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
// Clear all watchers
cleanupWatchers()

// Collect the new `input` and `cssImportPaths`.
;[input, cssImportPaths] = await handleImports(
args['--input']
? await fs.readFile(args['--input'], 'utf-8')
: css`
@import 'tailwindcss';
`,
args['--input'] ?? base,
)
// Read the new `input`.
let input = args['--input']
? args['--input'] === '-'
? await drainStdin()
: await fs.readFile(args['--input'], 'utf-8')
: css`
@import 'tailwindcss';
`
clearRequireCache(resolvedFullRebuildPaths)
fullRebuildPaths = cssImportPaths.slice()
fullRebuildPaths = []

// Create a new compiler, given the new `input`
compiler = await createCompiler(input)

// Re-scan the directory to get the new `candidates`
scanner = new Scanner({
detectSources: { base },
sources: compiler.globs.map(({ origin, pattern }) => ({
// Ensure the glob is relative to the input CSS file or the
// config file where it is specified.
base: origin ? path.dirname(path.resolve(inputBasePath, origin)) : inputBasePath,
pattern,
})),
sources: compiler.globs,
})

// Scan the directory for candidates
Expand Down Expand Up @@ -367,51 +348,6 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) {
}
}

function handleImports(
input: string,
file: string,
): [css: string, paths: string[]] | Promise<[css: string, paths: string[]]> {
// TODO: Should we implement this ourselves instead of relying on PostCSS?
//
// Relevant specification:
// - CSS Import Resolve: https://csstools.github.io/css-import-resolve/

if (!input.includes('@import')) {
return [input, [file]]
}

return postcss()
.use(
atImport({
resolve(id, basedir) {
let resolved = resolveCssId(id, basedir)
if (!resolved) {
throw new Error(`Could not resolve ${id} from ${basedir}`)
}
return resolved
},
load(id) {
// We need to synchronously read the file here because when bundled
// with bun, some of the ids might resolve to files inside the bun
// embedded files root which can only be read by `node:fs` and not
// `node:fs/promises`.
return readFileSync(id, 'utf-8')
},
}),
)
.use(fixRelativePathsPlugin())
.process(input, { from: file })
.then((result) => [
result.css,

// Use `result.messages` to get the imported files. This also includes the
// current file itself.
[file].concat(
result.messages.filter((msg) => msg.type === 'dependency').map((msg) => msg.file),
),
])
}

function optimizeCss(
input: string,
{ file = 'input.css', minify = false }: { file?: string; minify?: boolean } = {},
Expand Down
1 change: 0 additions & 1 deletion packages/@tailwindcss-cli/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ export default defineConfig({
clean: true,
minify: true,
entry: ['src/index.ts'],
noExternal: ['internal-postcss-fix-relative-paths'],
})
1 change: 1 addition & 0 deletions packages/@tailwindcss-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"tailwindcss": "workspace:^"
},
"dependencies": {
"enhanced-resolve": "^5.17.1",
"jiti": "^2.0.0-beta.3"
}
}
Loading