13

I've been upgrading my CRA project to TailwindCSS 3, but now CSS nesting no longer works. Upon starting the server, the console spits out:

(8:3) Nested CSS was detected, but CSS nesting has not been configured correctly.
Please enable a CSS nesting plugin *before* Tailwind in your configuration.
See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting

However, I don't see what must be done to correct this. I've tried setting up a plain CRA project with Tailwind (following this guide) just to make sure I have no conflicts, and still no success.

postcss.config.js:

module.exports = {
  plugins: {
    "tailwindcss/nesting": {},
    tailwindcss: {},
    autoprefixer: {},
  },
};

As you can see, I have added the nesting plugin before Tailwind. It appears to me as if the plugin isn't being detected whatsoever. I've also tried replacing it with postcss-nesting with same outcome.

Note: I've also tried using the array syntax with require('tailwind/nesting') like the guide suggests.

Interestingly, removing all plugins from postcss.config.js (or using a require that fails to resolve) still outputs the same error, implying that this file isn't needed to get Tailwind to load. Maybe I am missing something that causes the whole postcss.config.js file to not be loaded in the first place?


index.js:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";

ReactDOM.render(
  <React.StrictMode>
    <div className="a">
      aaa
      <div className="b">bbb</div>
    </div>
  </React.StrictMode>,
  document.getElementById("root")
);

index.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

.a {
  @apply text-blue-500;

  .b {
    @apply text-green-500;
  }
}

package.json: (omitted things for brevity)

{
  "name": "tailwindtest",
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "5.0.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.2",
    "postcss": "^8.4.5",
    "tailwindcss": "^3.0.12"
  }
}
Liam
  • 27,717
  • 28
  • 128
  • 190
Magnus Bull
  • 1,027
  • 1
  • 10
  • 21
  • Doesn't your package.json should include [@tailwindcss/nesting](https://www.npmjs.com/package/@tailwindcss/nesting) ? – Clément Baconnier Jan 11 '22 at 11:39
  • @ClémentBaconnier According to the link in the error: `It’s included directly in the tailwindcss package itself, so to use it all you need to do is add it to your PostCSS configuration, somewhere before Tailwind` – Magnus Bull Jan 11 '22 at 11:42
  • I have no idea then, I have never done that before. I found a similar issue [#5896](https://github.com/tailwindlabs/tailwindcss/issues/5896) Also the pulls that are relevant: [#5489](https://github.com/tailwindlabs/tailwindcss/pull/5489) and [#6011](https://github.com/tailwindlabs/tailwindcss/pull/6011) – Clément Baconnier Jan 11 '22 at 12:23
  • From my previous github link, based on adam's [#5896](https://github.com/tailwindlabs/tailwindcss/issues/5896#issuecomment-954635065) comment and the [detect-nesting.test.js](https://github.com/tailwindlabs/tailwindcss/blob/b140f27203b55ea722f205bb92566ca66629a448/tests/detect-nesting.test.js) file, I think it safe to assume that tailwind does not expect nested CSS. Even if you remove the plugin, it would warn with that error message. In my opinion, it means that somehow, the `postcss-nested` or `tailwindcss/nesting` plugin did not worked or partially worked, right? – Clément Baconnier Jan 11 '22 at 12:49
  • @ClémentBaconnier I agree that the `tailwind` at-rules are not meant to be nested. My intention is to use nested `apply` at-rules, which is supported and worked fine in Tailwind 2. The issue is that they have a guide on how to achieve this for v3 but that guide isn't working for me. – Magnus Bull Jan 11 '22 at 13:39
  • I understand that. I tried to give you an input to help you debugging and find a solution and perhaps submitting an issue to tailwindlabs. As I understand how it's working; the plugins work like a pipeline and `tailwindcss/nesting` should translate the nested css input to inline css, then passing the inline css output to `tailwindcss`, and so on. Per my last comment, I assume that something is not translated by `tailwindcss/nesting` or `postcss-nested`. Perhaps you could try withtout `apply` at-rules to see if it's working, If not, it _could_ be degression to report, assuming the doc is right. – Clément Baconnier Jan 11 '22 at 17:48
  • 1
    @ClémentBaconnier I appreciate your inputs, they certainly help. I'm afraid the issue remains with just a single class selector within another, so the at-rules aren't directly related. What I've found out though is that Create React App v5, which was recently released, has Tailwind officially supported and as a dependency. Perhaps the issue is that this version is overriding the one I've installed, and that my configs are never loaded for a related reason. – Magnus Bull Jan 11 '22 at 20:14
  • I have the same problem and couldnt find a solution. I think the tailwind doesnt react postcss config file and always the same error. I tried different solutions but it didnt change so I convert my nested css to css because I spent 2 days unfortunately. – Günay Gültekin Apr 12 '22 at 07:31

3 Answers3

11

This is mostly just bad news.

Create React App's Tailwind support means that they will detect tailwind.config.js in the project and add tailwindcss to their existing postcss configuration. Source in CRA

The guide that Tailwind offers on their site creates a dummy postcss.config.js - Making changes in this file does not change the actual postcss configuration. (misleading if anything)

This is a known issue currently - Github discussion on Tailwind support PR between Adam Wathan (Tailwind founder) and Ian Sutherland (CRA maintainer). But it does not seem like there is an intention to be fixed soon.

If you want to use nesting (or any PostCSS plugin really) is to eject from CRA using:

npm run eject

After ejecting you can find CRA's postcss configuration in config/webpack.config.js - look for postcss-loader. Editing the configuration there can enable any postcss features.

PS: Look out for postcss-preset-env in the default configuration while enabling nesting. Tailwind requires you to edit configuration if this is present.

Agney
  • 18,522
  • 7
  • 57
  • 75
  • 1
    Great detective work, thanks. I had a suspicion something funky was going on. I even joined the Tailwind Discord server to ask a few times without any clear answers (although I never directed it at Adam himself). Luckily I can wait with using nesting and see if they update CRA, so I prefer that over ejecting. – Magnus Bull Feb 04 '22 at 13:58
  • Thanks for this, it helped a lot. Based on your answer, I published a fork of create-react-app to enable use of tailwind/nesting without ejecting https://github.com/facebook/create-react-app/pull/11717#issuecomment-1106839187 – Ryan Berckmans Apr 22 '22 at 20:36
2

I use CRA and to fix the issue I used postinstall to run a script after npm install or yarn. The script is changing the web pack config of CRA after all dependencies are installed(a temporary solution of cause). You can find the web pack config in node_modules/react-scripts/config/webpack.config.js. The script adds my postcss packages to the actual CRA web pack config.

WHY? CRA does not respect any postcss config in your repo

Have also a look at this comment to see how you should use postinstall https://github.com/facebook/create-react-app/issues/2133#issuecomment-347574268.

I also added tailwindcss/nesting before tailwindcss because tailwind is throwing a warning when it sees any nested css. The warning was blocking my CI since CI=true in CRA means all warnings are treated as errors.

Here is the script that is running in my repo.

FILE="node_modules/react-scripts/config/webpack.config.js"

function replace {
  TARGET_FILE=$1
  PATTERN_TO_FIND=$2
  VALUE_FOR_REPLACEMENT=$3

  OLD_FILE_CONTENT=$(cat "$TARGET_FILE")  # we need to collect the content of the file so we can overwrite it in the next command
  echo "$OLD_FILE_CONTENT" | sed -e "s/$PATTERN_TO_FIND/$VALUE_FOR_REPLACEMENT/g" > "$TARGET_FILE"
}

# add postcss-nesting
replace "$FILE" "'postcss-flexbugs-fixes'," "'postcss-flexbugs-fixes','postcss-nesting',"

# add tailwind/nesting
replace "$FILE" "'tailwindcss'," "'tailwindcss\/nesting', 'tailwindcss',"
aricma
  • 21
  • 1
  • 1
  • 5
0

acording to @aricma answer, is easier if you create a script.js file on parent directory (same as package.json) and add this on package.json

  "scripts": { 
    "postinstall": "node script.js",
    ...
  }

and this on script.js

const fs = require('fs');

fs.readFile('node_modules/react-scripts/config/webpack.config.js', 'utf8', (err, data) => {
  if (err) {
    return console.log(err);
  }
  const result = data.replace("'postcss-flexbugs-fixes',", "'postcss-flexbugs-fixes','postcss-nesting',").replace("'tailwindcss',", "'tailwindcss/nesting', 'tailwindcss',");

  fs.writeFile('node_modules/react-scripts/config/webpack.config.js', result, 'utf8', (err) => {
    if (err) {
      return console.log(err);
    }
    return console.log(true);
  });
  return console.log(true);
});