diff --git a/src/lib/normalizeTailwindDirectives.js b/src/lib/normalizeTailwindDirectives.js index 274773051680..4d09f96806f5 100644 --- a/src/lib/normalizeTailwindDirectives.js +++ b/src/lib/normalizeTailwindDirectives.js @@ -1,10 +1,15 @@ import log from '../util/log' export default function normalizeTailwindDirectives(root) { - let tailwindDirectives = new Set() - let layerDirectives = new Set() + const tailwindDirectives = new Set() + const layerDirectives = new Set() + const applyDirectives = new Set() root.walkAtRules((atRule) => { + if (atRule.name === 'apply') { + applyDirectives.add(atRule) + return + } if (atRule.name === 'import') { if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") { atRule.name = 'tailwind' @@ -74,5 +79,5 @@ export default function normalizeTailwindDirectives(root) { } } - return tailwindDirectives + return { tailwindDirectives, layerDirectives, applyDirectives } } diff --git a/src/lib/setupTrackingContext.js b/src/lib/setupTrackingContext.js index d4015c5bf59e..4cf7b3cc48c1 100644 --- a/src/lib/setupTrackingContext.js +++ b/src/lib/setupTrackingContext.js @@ -112,19 +112,19 @@ function resolveChangedFiles(candidateFiles, fileModifiedMap) { // source path), or set up a new one (including setting up watchers and registering // plugins) then return it export default function setupTrackingContext(configOrPath) { - return ({ tailwindDirectives, registerDependency }) => { + return ({ tailwindDirectives, registerDependency, applyDirectives }) => { return (root, result) => { let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = getTailwindConfig(configOrPath) let contextDependencies = new Set(configDependencies) - // If there are no @tailwind rules, we don't consider this CSS file or it's dependencies - // to be dependencies of the context. Can reuse the context even if they change. + // If there are no @tailwind or @apply rules, we don't consider this CSS file or it's + // dependencies to be dependencies of the context. Can reuse the context even if they change. // We may want to think about `@layer` being part of this trigger too, but it's tough // because it's impossible for a layer in one file to end up in the actual @tailwind rule // in another file since independent sources are effectively isolated. - if (tailwindDirectives.size > 0) { + if (tailwindDirectives.size > 0 || applyDirectives.size > 0) { // Add current css file as a context dependencies. contextDependencies.add(result.opts.from) @@ -147,12 +147,12 @@ export default function setupTrackingContext(configOrPath) { let candidateFiles = getCandidateFiles(context, tailwindConfig) - // If there are no @tailwind rules, we don't consider this CSS file or it's dependencies - // to be dependencies of the context. Can reuse the context even if they change. + // If there are no @tailwind or @apply rules, we don't consider this CSS file or it's + // dependencies to be dependencies of the context. Can reuse the context even if they change. // We may want to think about `@layer` being part of this trigger too, but it's tough // because it's impossible for a layer in one file to end up in the actual @tailwind rule // in another file since independent sources are effectively isolated. - if (tailwindDirectives.size > 0) { + if (tailwindDirectives.size > 0 || applyDirectives.size > 0) { let fileModifiedMap = getFileModifiedMap(context) // Add template paths as postcss dependencies. diff --git a/src/lib/setupWatchingContext.js b/src/lib/setupWatchingContext.js index 1ee1eaf3094e..1787c4243561 100644 --- a/src/lib/setupWatchingContext.js +++ b/src/lib/setupWatchingContext.js @@ -229,19 +229,19 @@ function resolveChangedFiles(context, candidateFiles) { // source path), or set up a new one (including setting up watchers and registering // plugins) then return it export default function setupWatchingContext(configOrPath) { - return ({ tailwindDirectives, registerDependency }) => { + return ({ tailwindDirectives, registerDependency, applyDirectives }) => { return (root, result) => { let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = getTailwindConfig(configOrPath) let contextDependencies = new Set(configDependencies) - // If there are no @tailwind rules, we don't consider this CSS file or it's dependencies - // to be dependencies of the context. Can reuse the context even if they change. + // If there are no @tailwind or @apply rules, we don't consider this CSS file or it's + // dependencies to be dependencies of the context. Can reuse the context even if they change. // We may want to think about `@layer` being part of this trigger too, but it's tough // because it's impossible for a layer in one file to end up in the actual @tailwind rule // in another file since independent sources are effectively isolated. - if (tailwindDirectives.size > 0) { + if (tailwindDirectives.size > 0 || applyDirectives.size > 0) { // Add current css file as a context dependencies. contextDependencies.add(result.opts.from) @@ -299,7 +299,7 @@ export default function setupWatchingContext(configOrPath) { registerDependency({ type: 'dependency', file: touchFile }) } - if (tailwindDirectives.size > 0) { + if (tailwindDirectives.size > 0 || applyDirectives.size > 0) { for (let changedContent of resolvedChangedContent(context, candidateFiles)) { context.changedContent.push(changedContent) } diff --git a/src/processTailwindFeatures.js b/src/processTailwindFeatures.js index 8a6d22dae744..fc0314d15561 100644 --- a/src/processTailwindFeatures.js +++ b/src/processTailwindFeatures.js @@ -12,10 +12,11 @@ import { issueFlagNotices } from './featureFlags' export default function processTailwindFeatures(setupContext) { return function (root, result) { - let tailwindDirectives = normalizeTailwindDirectives(root) + const { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root) - let context = setupContext({ + const context = setupContext({ tailwindDirectives, + applyDirectives, registerDependency(dependency) { result.messages.push({ plugin: 'tailwindcss', diff --git a/tests/apply.test.js b/tests/apply.test.js index c74bb2875f5d..c50cf3707ee5 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -774,3 +774,38 @@ it('should not apply unrelated siblings when applying something from within atru `) }) }) + +it('should be possible to apply user css without tailwind directives', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .bop { + color: red; + } + .bar { + background-color: blue; + } + .foo { + @apply absolute bar bop; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bop { + color: red; + } + .bar { + background-color: blue; + } + .foo { + position: absolute; + color: red; + background-color: blue; + } + `) + }) +})