Skip to content
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

Error: Expected an opening square bracket (using postcss-purgecss and postcss-preset-env) #1190

Closed
yassinedoghri opened this issue Oct 26, 2019 · 11 comments

Comments

@yassinedoghri
Copy link

I've encountered this error when trying to build styles for production. I have a create-react-app with tailwindcss and postcss. I'm not sure where the problem lies exactly but I've boiled it down to this config to recreate it:

package.json:

{
  ...
  "scripts": {
    "build:css": "postcss src/tailwind.css -o src/index.css",
    ...
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not op_mini all"
  ],
  "devDependencies": {
    "@fullhuman/postcss-purgecss": "^1.3.0",
    "postcss-cli": "^6.1.3",
    "postcss-preset-env": "^6.7.0",
    "tailwindcss": "^1.1.3"
  }
}

postcss.config.js

const purgecss = require("@fullhuman/postcss-purgecss")({
  // paths to all of the template files in the project
  content: ["./src/**/*.html", "./src/**/*.tsx", "./public/**/*.html"],

  // default extractor including tailwind's special characters
  defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
});

module.exports = {
  plugins: [
    require("tailwindcss"),
    require("postcss-preset-env")({ stage: 1 }),
    ...(process.env.NODE_ENV === "production" ? [purgecss] : [])
  ]
};

tailwind.config.js
⚠️ The error arises whenever responsive and focus-within variants are added together to a property.

module.exports = {
  theme: {
    extend: {}
  },
  variants: {
    backgroundColor: ["responsive", "focus-within"]
  },
  plugins: []
};

I get this error when building the styles for a production environment (so with purgecss enabled):
yarn build:css --env=production

$ postcss src/tailwind.css -o src/index.css --env=production
{ Error: Expected an opening square bracket.
    at tailwind-build-error\src\tailwind.css:5:1
    at Root._error (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\parser.js:160:16)
    at Root.error (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\selectors\root.js:43:19)
    at Parser.error (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\parser.js:726:21)
    at Parser.expected (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\parser.js:1113:19)
    at Parser.missingSquareBracket (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\parser.js:740:17)
    at Parser.parse (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\parser.js:1090:14)
    at Parser.loop (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\parser.js:1023:12)
    at new Parser (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\parser.js:150:10)
    at Processor._root (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\processor.js:55:18)
    at Processor._runSync (tailwind-build-error\node_modules\purgecss\node_modules\postcss-selector-parser\dist\processor.js:102:21)
  postcssNode:
   Rule {
     raws: { before: '\n\n  ', after: '\n  ' },
     type: 'rule',
     nodes: [ [Declaration] ],
     selector: '.sm\\[focus-within]\\:bg-transparent[focus-within]',
     lastEach: 53,
     indexes: {},
     source: { start: [Object], input: [Input], end: [Object] },
     parent:
      AtRule {
        raws: [Object],
        name: 'media',
        params: '(min-width: 640px)',
        type: 'atrule',
        nodes: [Array],
        parent: [Root],
        lastEach: 46,
        indexes: [Object],
        _autoprefixerDisabled: false,
        _autoprefixerPrefix: false,
        _autoprefixerGridStatus: false },
     _autoprefixerDisabled: false,
     _autoprefixerGridStatus: false } }
error Command failed with exit code 1.

So, I've checked the generated css, and some of it appears to be broken:

.sm\[focus-within]\:bg-transparent[focus-within] {
    background-color: transparent;
}

I've created a repo with the minimal config displaying the error: https://github.com/yassinedoghri/tailwind-build-error

@adamwathan
Copy link
Member

Hey thanks for the excellently constructed issue!

I looked into this and the source of the problem appears to be a bug in the postcss-focus-within plugin used by postcss-preset-env.

It is duplicating your focus-within selectors and replacing the pseudo-class (:focus-within) with an attribute selector ([focus-within]). That results in duplicate declarations like this:

.focus-within\:bg-transparent[focus-within] {
  background-color: transparent;
}

.focus-within\:bg-transparent:focus-within {
  background-color: transparent;
}

The problem is it's also replacing the focus-within part of the class name in responsive selectors:

  .md\[focus-within]\:bg-transparent[focus-within] {
    background-color: transparent;
  }

  .md\:focus-within\:bg-transparent:focus-within {
    background-color: transparent;
  }

This is because the plugin is naively doing a search and replace on :focus-within, which is ignoring the fact that the : in the class name is escaped, and should not be replaced with an attribute selector:

https://github.com/jonathantneal/postcss-focus-within/blob/master/index.js#L3

The fix will be similar to what was done on the postcss-selector-not plugin a while back here:

csstools/postcss-selector-not#11

I'll open an issue on that plugin but in the mean time if you aren't actually using the polyfill you can just disable that plugin in postcss-preset-env in your postcss.config.js file:

const purgecss = require("@fullhuman/postcss-purgecss")({
  // paths to all of the template files in the project
  content: ["./src/**/*.html", "./src/**/*.tsx", "./public/**/*.html"],

  // default extractor including tailwind's special characters
  defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
});

module.exports = {
  plugins: [
    require("tailwindcss"),
    require("postcss-preset-env")({
      stage: 1,
      features: {
        'focus-within-pseudo-class': false
      }
    }),
    ...(process.env.NODE_ENV === "production" ? [purgecss] : [])
  ]
};

@adamwathan
Copy link
Member

adamwathan commented Oct 26, 2019

Opened issue on the plugin repo, will try to fix myself soon if I can:

csstools/postcss-focus-within#3

Closing here since it's not something we can fix from inside Tailwind but thanks for helping us discover this and track it down.

@yassinedoghri
Copy link
Author

Awesome, thank you for the fast reply! And thank you for your work on Tailwind :)

@shawnhansen
Copy link

I have the same exact issue on a Statamic v3 project (which uses Laravel Mix). Is there a way to apply this fix with Mix?

Error: Expected an opening square bracket.
at <input css 3>:81370:3

@ARRIOLALEO
Copy link

i had similar issue i solved adding purge: ['./components//*.{js,ts,jsx,tsx}', './pages//*.{js,ts,jsx,tsx}'], to my tailwind.config.js after that i was able to build my app

@hieu-nv
Copy link

hieu-nv commented Feb 10, 2021

i had similar issue i solved adding purge: ['./components//*.{js,ts,jsx,tsx}', './pages//*.{js,ts,jsx,tsx}'], to my tailwind.config.js after that i was able to build my app

It seems that tailwindcss classes is removed.

I solved by using:

purge: ["./src/**/*.html", "./src/**/*.js", "./src/**/*.jsx", "./public/**/*.html"],

@lhall-amphibee
Copy link

It's working with @hieu-nv 's solution, but what is it actually doing ?

@guydumais
Copy link

guydumais commented Feb 18, 2021

None of the solutions mentioned above worked for me. Here's the code in postcss.config.js that fix it using Next.js 10 and React 17:

module.exports = {
  plugins: {
    'postcss-flexbugs-fixes': {},
    'postcss-preset-env': {
      autoprefixer: {
        flexbox: 'no-2009',
      },
      stage: 3,
      features: {
        'custom-properties': false,
      },
    },
    '@fullhuman/postcss-purgecss': {
      content: [
          './pages/**/*.{js,jsx,ts,tsx}',
          './components/**/*.{js,jsx,ts,tsx}'
      ],
      defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || [],
      safelist: ["html", "body"]
    },
    'tailwindcss': {}
  }
}

guydumais added a commit to guydumais/nextjs-multilanguage-website that referenced this issue Feb 18, 2021
FIX for Error: Expected an opening square bracket (using postcss-purgecss and postcss-preset-env)
tailwindlabs/tailwindcss#1190 (comment)
@croxton
Copy link

croxton commented Feb 19, 2021

I have the same exact issue on a Statamic v3 project (which uses Laravel Mix). Is there a way to apply this fix with Mix?

Error: Expected an opening square bracket.
at <input css 3>:81370:3

For Laravel Mix you can disable the focus-within-pseudo-class feature after addign Tailwind as a PostCSS plugin. e.g.:

const postCssPlugins = [

    /**
     * 🎨 Styles: Tailwind CSS
     */
    require('tailwindcss')('./tailwind.config.js'),

    /**
     * 🎨 Styles: Polyfills
     * Postcss preset env lets you use pre-implemented css features
     * See https://cssdb.org/ for supported features
     * https://github.com/csstools/postcss-preset-env#readme
     */
    require("postcss-preset-env")({
        stage: 1,
        features: {
            'focus-within-pseudo-class': false
        }
    }),
];
mix.options({ postCss: postCssPlugins });

@doublejosh
Copy link

🤦 This also happens if you have two require("postcss-preset-env") in the same array.

@barhouum7
Copy link

i had similar issue i solved adding purge: ['./components//*.{js,ts,jsx,tsx}', './pages//*.{js,ts,jsx,tsx}'], to my tailwind.config.js after that i was able to build my app

Thanks so much, just saved my day with this solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants