[Oxide] Add built-in @import processing support (#11239)
* run PostCSS relative to test file The PostCSS `from` was always set to the `tests/util/run` file with the current test name as a query param to make it unique. However, that results in issues with relative file paths because they are now relative to this file instead of the actual test file. Luckily, `expect.getState()` exposes the `testPath` value that points to the current test file itself. * add built in `@import` processing + additional features such that you can use `@tailwind` and `@config` directives before the `@import` at rule which isn't normally allowed. However "@tailwind" in a way is an `@import` and `@config` in a way is a `@charset` which can be used before the `@import` at rule. * drop partial normalizeTailwindDirectives when in the Oxide engine This will now be handled by Tailwind from a higher level, so the core doesn't have to worry about normalizing this anymore since it will always be normalized right now. * add `handleImportAtRules` to CLI * update changelog * scope `import processing` to the oxide engine * update Changelog * use direct comparison We don't need the `startsWith` check anymore because the contents of the comment will be the actual value we expect.
This commit is contained in:
parent
0e171fd2dd
commit
f49b054b7d
11 changed files with 170 additions and 63 deletions
|
|
@ -17,9 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
|
||||
- Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966))
|
||||
- [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399))
|
||||
- Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205))
|
||||
- [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399))
|
||||
- [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221))
|
||||
- [Oxide] Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239))
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
33
src/lib/handleImportAtRules.js
Normal file
33
src/lib/handleImportAtRules.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import postcss from 'postcss'
|
||||
|
||||
const TAILWIND = Symbol()
|
||||
|
||||
export function handleImportAtRules(postcssImport = require('postcss-import')) {
|
||||
let RESTORE_ATRULE_COMMENT = '__TAILWIND_RESTORE__'
|
||||
let atRulesToRestore = ['tailwind', 'config']
|
||||
|
||||
return [
|
||||
(root) => {
|
||||
root.walkAtRules((rule) => {
|
||||
if (!atRulesToRestore.includes(rule.name)) return rule
|
||||
|
||||
rule.after(
|
||||
postcss.comment({
|
||||
text: RESTORE_ATRULE_COMMENT,
|
||||
raws: { [TAILWIND]: { rule } },
|
||||
})
|
||||
)
|
||||
rule.remove()
|
||||
})
|
||||
},
|
||||
postcssImport(),
|
||||
(root) => {
|
||||
root.walkComments((rule) => {
|
||||
if (rule.text === RESTORE_ATRULE_COMMENT) {
|
||||
rule.after(rule.raws[TAILWIND].rule)
|
||||
rule.remove()
|
||||
}
|
||||
})
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
@ -10,30 +10,32 @@ export default function normalizeTailwindDirectives(root) {
|
|||
applyDirectives.add(atRule)
|
||||
}
|
||||
|
||||
if (atRule.name === 'import') {
|
||||
if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'base'
|
||||
} else if (
|
||||
atRule.params === '"tailwindcss/components"' ||
|
||||
atRule.params === "'tailwindcss/components'"
|
||||
) {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'components'
|
||||
} else if (
|
||||
atRule.params === '"tailwindcss/utilities"' ||
|
||||
atRule.params === "'tailwindcss/utilities'"
|
||||
) {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'utilities'
|
||||
} else if (
|
||||
atRule.params === '"tailwindcss/screens"' ||
|
||||
atRule.params === "'tailwindcss/screens'" ||
|
||||
atRule.params === '"tailwindcss/variants"' ||
|
||||
atRule.params === "'tailwindcss/variants'"
|
||||
) {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'variants'
|
||||
if (!__OXIDE__) {
|
||||
if (atRule.name === 'import') {
|
||||
if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'base'
|
||||
} else if (
|
||||
atRule.params === '"tailwindcss/components"' ||
|
||||
atRule.params === "'tailwindcss/components'"
|
||||
) {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'components'
|
||||
} else if (
|
||||
atRule.params === '"tailwindcss/utilities"' ||
|
||||
atRule.params === "'tailwindcss/utilities'"
|
||||
) {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'utilities'
|
||||
} else if (
|
||||
atRule.params === '"tailwindcss/screens"' ||
|
||||
atRule.params === "'tailwindcss/screens'" ||
|
||||
atRule.params === '"tailwindcss/variants"' ||
|
||||
atRule.params === "'tailwindcss/variants'"
|
||||
) {
|
||||
atRule.name = 'tailwind'
|
||||
atRule.params = 'variants'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { loadConfig } from '../../../lib/load-config'
|
|||
import getModuleDependencies from '../../../lib/getModuleDependencies'
|
||||
import type { Config } from '../../../../types'
|
||||
import { validateConfig } from '../../../util/validateConfig'
|
||||
import { handleImportAtRules } from '../../../lib/handleImportAtRules'
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -75,39 +76,6 @@ async function loadPostCssPlugins(customPostCssPath) {
|
|||
return [beforePlugins, afterPlugins, config.options]
|
||||
}
|
||||
|
||||
function loadBuiltinPostcssPlugins() {
|
||||
let postcss = loadPostcss()
|
||||
let IMPORT_COMMENT = '__TAILWIND_RESTORE_IMPORT__: '
|
||||
return [
|
||||
[
|
||||
(root) => {
|
||||
root.walkAtRules('import', (rule) => {
|
||||
if (rule.params.slice(1).startsWith('tailwindcss/')) {
|
||||
rule.after(postcss.comment({ text: IMPORT_COMMENT + rule.params }))
|
||||
rule.remove()
|
||||
}
|
||||
})
|
||||
},
|
||||
loadPostcssImport(),
|
||||
(root) => {
|
||||
root.walkComments((rule) => {
|
||||
if (rule.text.startsWith(IMPORT_COMMENT)) {
|
||||
rule.after(
|
||||
postcss.atRule({
|
||||
name: 'import',
|
||||
params: rule.text.replace(IMPORT_COMMENT, ''),
|
||||
})
|
||||
)
|
||||
rule.remove()
|
||||
}
|
||||
})
|
||||
},
|
||||
],
|
||||
[],
|
||||
{},
|
||||
]
|
||||
}
|
||||
|
||||
let state = {
|
||||
/** @type {any} */
|
||||
context: null,
|
||||
|
|
@ -266,7 +234,9 @@ export async function createProcessor(args, cliConfigPath) {
|
|||
|
||||
let [beforePlugins, afterPlugins, postcssOptions] = includePostCss
|
||||
? await loadPostCssPlugins(customPostCssPath)
|
||||
: loadBuiltinPostcssPlugins()
|
||||
: [[], [], {}]
|
||||
|
||||
beforePlugins.unshift(...handleImportAtRules(loadPostcssImport()))
|
||||
|
||||
if (args['--purge']) {
|
||||
log.warn('purge-flag-deprecated', [
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import setupTrackingContext from './lib/setupTrackingContext'
|
|||
import processTailwindFeatures from './processTailwindFeatures'
|
||||
import { env } from './lib/sharedState'
|
||||
import { findAtConfigPath } from './lib/findAtConfigPath'
|
||||
import { handleImportAtRules } from './lib/handleImportAtRules'
|
||||
|
||||
module.exports = function tailwindcss(configOrPath) {
|
||||
return {
|
||||
|
|
@ -13,6 +14,7 @@ module.exports = function tailwindcss(configOrPath) {
|
|||
console.time('JIT TOTAL')
|
||||
return root
|
||||
},
|
||||
...(__OXIDE__ ? handleImportAtRules() : []),
|
||||
function (root, result) {
|
||||
// Use the path for the `@config` directive if it exists, otherwise use the
|
||||
// path for the file being processed
|
||||
|
|
|
|||
1
tests/import-processing-a.css
Normal file
1
tests/import-processing-a.css
Normal file
|
|
@ -0,0 +1 @@
|
|||
@tailwind utilities;
|
||||
5
tests/import-processing-b.css
Normal file
5
tests/import-processing-b.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@layer utilities {
|
||||
.foo {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
5
tests/import-processing-c.css
Normal file
5
tests/import-processing-c.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@tailwind utilities;
|
||||
|
||||
.foo {
|
||||
color: red;
|
||||
}
|
||||
9
tests/import-processing-c.js
Normal file
9
tests/import-processing-c.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
module.exports = {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
{
|
||||
raw: `<div class="foo underline" />`,
|
||||
},
|
||||
],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
79
tests/import-processing.test.js
Normal file
79
tests/import-processing.test.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import { html, css, run, crosscheck } from './util/run'
|
||||
|
||||
crosscheck(({ oxide, stable }) => {
|
||||
stable.test.todo('Import processing is an oxide engine feature')
|
||||
oxide.describe('import processing', () => {
|
||||
it('should be possible to import another css file', async () => {
|
||||
let config = {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
{
|
||||
raw: html`<div class="underline" />`,
|
||||
},
|
||||
],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
|
||||
let input = css`
|
||||
@import './import-processing-a.css';
|
||||
`
|
||||
|
||||
let result = await run(input, config)
|
||||
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
it('should be possible to import another css file after @tailwind directive', async () => {
|
||||
let config = {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
{
|
||||
raw: html`<div class="foo underline" />`,
|
||||
},
|
||||
],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
|
||||
let input = css`
|
||||
@tailwind utilities;
|
||||
|
||||
@import './import-processing-b.css';
|
||||
`
|
||||
|
||||
let result = await run(input, config)
|
||||
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.foo {
|
||||
color: red;
|
||||
}
|
||||
`)
|
||||
})
|
||||
|
||||
it('should be possible to add @config before @import statements', async () => {
|
||||
let input = css`
|
||||
@config "./import-processing-c.js";
|
||||
@import './import-processing-c.css';
|
||||
`
|
||||
|
||||
let result = await run(input)
|
||||
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.foo {
|
||||
color: red;
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -17,18 +17,18 @@ export let map = JSON.stringify({
|
|||
globalThis.__OXIDE__ = env.ENGINE === 'oxide'
|
||||
|
||||
export function run(input, config, plugin = tailwind) {
|
||||
let { currentTestName } = expect.getState()
|
||||
let { currentTestName, testPath } = expect.getState()
|
||||
|
||||
return postcss(plugin(config)).process(input, {
|
||||
from: `${path.resolve(__filename)}?test=${currentTestName}`,
|
||||
from: `${path.resolve(testPath)}?test=${currentTestName}`,
|
||||
})
|
||||
}
|
||||
|
||||
export function runWithSourceMaps(input, config, plugin = tailwind) {
|
||||
let { currentTestName } = expect.getState()
|
||||
let { currentTestName, testPath } = expect.getState()
|
||||
|
||||
return postcss(plugin(config)).process(input, {
|
||||
from: `${path.resolve(__filename)}?test=${currentTestName}`,
|
||||
from: `${path.resolve(testPath)}?test=${currentTestName}`,
|
||||
map: {
|
||||
prev: map,
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue