facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.66k stars 26.81k forks source link

ParserError when dividing a CSS variable by a negative number #10880

Open Flonk opened 3 years ago

Flonk commented 3 years ago

Describe the bug

Dividing a CSS variable by a negative number yields a ParserError during production builds. Live preview works ok.

Which terms did you search for in User Guide?

ParserError, CSS variables

Environment

Environment Info:

  current version of create-react-app: 4.0.3
  running from <snip>\create-react-app

  System:
    OS: Windows 10 10.0.19042
    CPU: (16) x64 Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz
  Binaries:
    Node: 15.5.1 - C:\Program Files\nodejs\node.EXE
    Yarn: Not Found
    npm: 7.9.0 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: Not Found
    Edge: Spartan (44.19041.906.0), Chromium (90.0.818.46)
    Internet Explorer: 11.0.19041.1
  npmPackages:
    react: ^17.0.2 => 17.0.2
    react-dom: ^17.0.2 => 17.0.2
    react-scripts: 4.0.3 => 4.0.3
  npmGlobalPackages:
    create-react-app: Not Found

Steps to reproduce

  1. Create a fresh react app with npx create-react-app --template typescript
  2. Add the following css to App.css:
    .App-logo {
    --size: -10px;
    width: calc(var(--size)/-2);
    }
  3. run npm run build

Expected behavior

The build should compile successfully, since live preview works as expected.

Actual behavior

PS C:\<snip>\cra> npm run build

> cra@0.1.0 build
> react-scripts build

Creating an optimized production build...
Failed to compile.

./src/App.css
ParserError: Syntax Error at line: 1, column 18

Etc

If either var(--size) is replaced by some constant, or the expression is rewritten as calc(-1/2 * var(--size)), the problem disappears.

totymedli commented 3 years ago

Problem and Error

I can confirm this. The following rules will cause an error during npm run build (react-scripts build)

--bs-gutter-y:0;
margin-top:calc(var(--bs-gutter-y)*-1)

The error is:

ParserError: Syntax Error at line: 1, column 25

BTW the rule is not in line 1 column 25, so it is totally misleading.

Solutions

This code is from Bootstrap 5.0.2 which has the spaces (even in the minified version) so my assumption is that somewhere, the script minifies it again and removes the spaces. This could explain why it works in dev mode, where presumably there is no minification.

Also, check out this related Stack Overflow question.

fewlme commented 3 years ago

Thanks for the solutions @totymedli but where can you change those ? I'm importing bootstrap from my main scss file (so I can change all the default variables and create my own theme, etc) like this @import "~bootstrap/scss/bootstrap"; No clue where to change the -1 fix... I looked in all the @import from the main bootstrap.scss file... Thanks for your help

yudielcurbelo commented 3 years ago

I'm having something similar.

This does not work. margin-top: calc(var(--#{$variable-prefix}gutter-y) * -1);

But this works. margin-top: calc(var(--#{$variable-prefix}gutter-y) * (-1));

Also using Bootstrap.

fewlme commented 3 years ago

Found the fix : In boostrap/scss/mixins/_grid.scss

Change :

  margin-top: calc(var(--#{$variable-prefix}gutter-y) * -1); // stylelint-disable-line function-disallowed-list
  margin-right: calc(var(--#{$variable-prefix}gutter-x) * -.5); // stylelint-disable-line function-disallowed-list
  margin-left: calc(var(--#{$variable-prefix}gutter-x) * -.5); // stylelint-disable-line function-disallowed-list

with

  margin-top: calc(-1*var(--#{$variable-prefix}gutter-y)); // stylelint-disable-line function-disallowed-list
  margin-right: calc(-.5*var(--#{$variable-prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
  margin-left: calc(-.5*var(--#{$variable-prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
totymedli commented 3 years ago

@fewlme You are editing a 3rd party library. That works only if you add the dependency directly to your project. If it is inside node_modules you can't do this. So this is more of a workaround.

fewlme commented 3 years ago

True @totymedli, it's more a hack until I npm update the hell out of it :) but I can now build my react app without the parserError

nex3 commented 2 years ago

Sass recently added additional features for calc() which includes more aggressively minifying whitespace in calc() expressions. Note that the problematic expression calc(var(--bs-gutter-y)*-1) is valid CSS. To quote Values and Units Level 4:

(The * and / operators can be used without white space around them.)

It seems like some other tool is parsing Sass's output and choking on this valid CSS, which is likely a bug in that tool.

tcchau commented 2 years ago

Just adding another workaround: moving the literal values to the front of the expression seems to avoid any problems caused by minification or other processing, e.g.

calc( -1 * var(--bs-gutter-y))

Merely adding whitespace in front of the minus sign in the literals was not sufficient for me.

For reference, I am using react-scripts 4.0.3, sass 1.45.2, and CSS modules.

I found the idea for this workaround from: https://issueexplorer.com/issue/react-bootstrap/react-bootstrap/6039

kclay commented 2 years ago

This can be resolved if using bootstrap 5.1.0 with the following patch

bootstrap+5.1.0.patch

put this in patches/bootstrap+5.1.0.patch and adjust your package.json to have the following

{
   "scripts":{
      "postinstall":"patch-package"
   },
   "devDependencies":{
      "patch-package":"^6.4.7"
   }
}