Skip to content

UnexpectedToken(Function("--spacing")) with .\[--anchor-gap\:--spacing\(3\)\] { css #1100

@qknight

Description

@qknight

I want to use tailwind for CSS with cargo-leptos and i hit an issue with the generated CSS.

I first thought it is a cargo-leptos issue so I filed this ticket: leptos-rs/cargo-leptos#599

Anyway, I will repeat the important things here again, so you don't have to read two tickets!

setup

  1. Started with https://github.com/leptos-rs/cargo-leptos?tab=readme-ov-file#features from a https://github.com/leptos-rs/start-axum-workspace
  2. by default this uses sass and i updated the Cargo.toml with:
# The tailwind input file.
#
# Optional, Activates the tailwind build
tailwind-input-file = "style/style.css"

# The tailwind config file.
#
# Optional, defaults to "tailwind.config.js" which if is not present
# is generated for you
tailwind-config-file = "tailwind.config.js"

The files like style/style.css and tailwind.config.js are in place and valid and I can run the tailwindcss command by hand without any issues.

style/style.css

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

/* https://stackoverflow.com/questions/5110833/css-how-to-print-a-table-with-background-color-without-print-settings-changes */
body{
  -webkit-print-color-adjust:exact !important;
  print-color-adjust:exact !important;
}

tailwind.config.js

const colors = require("tailwindcss/colors");
const homedir = require("os").homedir();
const path = require("path");

module.exports = {
  content: ["./frontend/src/**/*.rs"],
  plugins: [
    require("@tailwindcss/forms"),
    require("@tailwindcss/typography"),
    require("@tailwindplus/elements"),
  ],
  theme: {
  },
};

The command is:

tailwindcss --input style/style.css --config tailwind.config.js --output /home/nixos/planicus/target/tmp/tailwind.css

This is usually executed by cargo-leptos automatically.

Image

using cargo leptos serve

now i want to develop with this setup and so i call a trunk like software:

  1. cargo leptos serve
  2. it calls various things and then tailwindcss --input style/style.css --config tailwind.config.js --output /home/nixos/planicus/target/tmp/tailwind.css
  3. after tailwindcss has finished, cargo-leptos reads /home/nixos/planicus/target/tmp/tailwind.css and puts it into the StyleSheet::parse(&source, ParserOptions::default()).unwrap(); to later minify it.

But it turns out that lightningcss fails with parsing the css in test_tailwind_css, I've extended tests/test_custom_parser.rs, see below:

I assume this is valid CSS as it is produced by the tailwind binary I also used with trunk before I tried to convert my code-base to cargo-leptos with SSR.

generated tailwind.css

Here is some lines from the generated tailwind.css file:

.filter {
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}

.transition {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

.\[--anchor-gap\:--spacing\(3\)\] {
  --anchor-gap: var(--spacing(3));
}

.\[appearance\:textfield\] {
  -webkit-appearance: textfield;
     -moz-appearance: textfield;
          appearance: textfield;
}

/* https://stackoverflow.com/questions/5110833/css-how-to-print-a-table-with-background-color-without-print-settings-changes */

body{
  -webkit-print-color-adjust:exact !important;
  print-color-adjust:exact !important;
}

.time-grid {
  display: grid;
  grid-template-columns: 60px repeat(7, 1fr);
  grid-template-rows: 40px repeat(15, 60px);
  /* header + 15 hours */
}

test to reproduce it

fn test_parse(source: &str) {
  let mut stylesheet = StyleSheet::parse(&source, ParserOptions::default()).unwrap();
  assert_eq!(1,2);
}

#[test]
fn test_tailwind_css() {
  test_parse(
    r#"
    .\[--anchor-gap\:--spacing\(3\)\] {
      --anchor-gap: var(--spacing(3));
    }
  "#
  )
}
test test_tailwind_css ... FAILED

failures:

---- test_tailwind_css stdout ----
thread 'test_tailwind_css' panicked at tests/test_custom_parser.rs:12:77:
called `Result::unwrap()` on an `Err` value: Error { kind: UnexpectedToken(Function("--spacing")), loc: Some(ErrorLocation { filename: "", line: 2, column: 25 }) }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    test_tailwind_css

test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

related

#1018

cargo-leptos vs. trunk

it seems that both projects are using lightningcss:

cargo-leptos: lightningcss = { version = "1.0.0-alpha.67", features = ["browserslist"] }
trunk: lightningcss = "=1.0.0-alpha.65" (this is used by minify-html = "0.15.0")

after some trunk source code reading this was discovered:

  1. trunk src/pipelines/mod.rs calls src/processing/minify.rs for minimizing the css in
  2. minify_css(bytes: Vec<u8>) -> Vec<u8> returns the bytes uncompressed if compression failed or compressed. there is a warning and i have to check if there was a warning printed somewhere.

seems trunk executed the minify_css successfully as https://planicus.eu/style-3798f67b665eb67.css is minified and it contains the gap\:--spacing\(3\)\] sequence.

a plausible explanation is this:

Running trunk serve -v --release in the old setup would let tailwindcss do the:

tailwindcss args args=["--input", "/home/nixos/planicus_wip/src/style.css", "--output", "/home/nixos/planicus_wip/dist/.stage/style.css", "--minify"]

Image

gpt4 says

This is valid in Tailwind CSS (for arbitrary properties/selectors), but not normal/valid CSS syntax. Here, you're encoding the actual property name and its value (--anchor-gap: --spacing(3)) into the selector using backslash escapes.

Why the Error Occurs
lightningcss's parser expects a valid CSS selector, where class names are "normal" identifiers, possibly allowing some escaping.
Tailwind's arbitrary selectors use a syntax (like .\[--anchor-gap\:--spacing\(3\)\]) that pushes the boundaries of CSS parsing.
When parsing, lightningcss encounters --spacing(3) inside the class selector, and interprets this as a "function token" instead of part of a (strange) class name.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions