Repository: tailwindlabs/tailwindcss (TypeScript)

Issue:
Compilation error for rule reusing important selector within a layer and using @apply
**What version of Tailwind CSS are you using?**

v3.3.3  
Reproduced on current play.tailwindcss.com version

**What build tool (or framework if it abstracts the build tool) are you using?**

vite v4.4.9  
postcss v8.4.29

**What version of Node.js are you using?**

v18.17.0

**What browser are you using?**

N/A

**What operating system are you using?**

Ubuntu

**Reproduction URL**

https://play.tailwindcss.com/xsicGQjVTh

**Describe your issue**

When using a selector in the `important` configuration option, adding a class using that same selector within a layer and using `@apply` causes a compilation error.

e.g.

```js
// config
{
  important: '.a-class',
}

// css
@layer base {
  .a-class {
    @apply font-bold;
  }
}
```

The crash seems to happen in [applyImportantSelector.js](https://github.com/tailwindlabs/tailwindcss/blob/d32228628ed45941a3ca1d2ca9d946d72c0d0cfa/src/util/applyImportantSelector.js#L10) because `sel.nodes` is an empty array, and it is assumed `sel.nodes[0]` is defined.

Either not using `@apply` or moving out of the `@layer` block makes this work as expected.


Hints:

Patch:
diff --git a/src/lib/expandApplyAtRules.js b/src/lib/expandApplyAtRules.js
--- a/src/lib/expandApplyAtRules.js
+++ b/src/lib/expandApplyAtRules.js
@@ -553,6 +553,13 @@ function processApply(root, context, localCache) {
                 ? parent.selector.slice(importantSelector.length)
                 : parent.selector
 
+            // If the selector becomes empty after replacing the important selector
+            // This means that it's the same as the parent selector and we don't want to replace it
+            // Otherwise we'll crash
+            if (parentSelector === '') {
+              parentSelector = parent.selector
+            }
+
             rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate)
 
             // And then re-add it if it was removed


Test patch:
diff --git a/tests/apply.test.js b/tests/apply.test.js
--- a/tests/apply.test.js
+++ b/tests/apply.test.js
@@ -2081,3 +2081,55 @@ test('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => {
     `)
   })
 })
+
+test('should not break replacing important selector when the same as the parent selector (pseudo)', async () => {
+  let config = {
+    important: ':root',
+    content: [],
+  }
+
+  let input = css`
+    @tailwind components;
+    @layer components {
+      :root {
+        @apply flex;
+      }
+    }
+  `
+
+  let result = await run(input, config)
+
+  expect(result.css).toMatchFormattedCss(css`
+    :root {
+      display: flex;
+    }
+  `)
+})
+
+test('should not break replacing important selector when the same as the parent selector (class)', async () => {
+  let config = {
+    important: '.foo',
+    content: [
+      {
+        raw: html` <div class="foo"></div> `,
+      },
+    ],
+  }
+
+  let input = css`
+    @tailwind components;
+    @layer components {
+      .foo {
+        @apply flex;
+      }
+    }
+  `
+
+  let result = await run(input, config)
+
+  expect(result.css).toMatchFormattedCss(css`
+    .foo {
+      display: flex;
+    }
+  `)
+})