43081j / postcss-lit

PostCSS syntax for extracting CSS from template literals inside JS/TS files
84 stars 6 forks source link

Output not same as postcss-preset-env playground #50

Open adrianbruntonsagecom opened 7 months ago

adrianbruntonsagecom commented 7 months ago

It appears the output of a postcss lit component is not as expected when using the postcss CLI. Replication available here: https://github.com/adrianbruntonsagecom/postcss-lit-preset-env-issue

Clone repo: git clone https://github.com/adrianbruntonsagecom/postcss-lit-preset-env-issue.git

Install dependencies: npm i

Run postcss CLI in root directory on standard css file requiring browser prefixes & de-nesting. npx postcss input.css -o output.css

This matches the expected output from postcss-preset-env playground.

Now change directories to the components directory contaning a postcss file with the same settings as the one in the root, but additionally containing postcss-lit syntax: cd components

Run postcss CLI on the example lit component npx postcss input.ts -o output.ts

See below for what it outputs - the CSS nesting is incorrect:

  static override styles = css`
    .button {
      -moz-columns: 3;
      columns: 3;
    }
&:focus,
      &:active {
        outline: none;
      }
  `;

Expected result:

  static override styles = css`
.button {
      -moz-columns: 3;
           columns: 3;
    }
.button:focus,
      .button:active {
        outline: none;
      }
  `;

Interestingly, it does work if the nested styles aren't compounded: This would work:

.button {
      &:focus {
        outline: none;
      }
}

But this doesn't:

.button {
      &:focus,
      &:active {
        outline: none;
      }
}
egfx-notifications commented 5 days ago

So, I had the same issue and decided to investigate.

The root cause was introduced here https://github.com/43081j/postcss-lit/pull/19/commits/d3ac5b31193e1c2312bd3d92bc96da035618abc2

locationCorrectionWalker() traverses the nodes before PostCSS does its actual processing. As far as I understood this it is only used to correct indentation of source code. Unfortunately it does this by saving the indented version as litSelector for later, then in rawValue() in the stringifier it simply picks up this version again and replaces the node's selector value with litSelector, thus nullifying all changes done by PostCSS.

This could be mitigated easily by escaping in case the selector contains a &, but this would be a very narrow scoped workaround for this specific issue. I very much doubt the overall feasibility of replacing any result of PostCSS with a previously saved value after the fact. Can this indentation correction not happen just before stringifying the result of whatever PostCSS was configured to do? At the very least this should be something one can opt out of. I do not care much about indentation as I run PostCSS as part of the build step and no human will read the output anyway. I do care very much that what PostCSS did is not reverted in the Stringifier.