Skip to content

Vue static vdom stringifier breaks PostCSS in Nuxt Production build #16358

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

Closed
wongjn opened this issue Feb 7, 2025 · 1 comment · Fixed by #16631
Closed

Vue static vdom stringifier breaks PostCSS in Nuxt Production build #16358

wongjn opened this issue Feb 7, 2025 · 1 comment · Fixed by #16631
Labels

Comments

@wongjn
Copy link
Contributor

wongjn commented Feb 7, 2025

What version of Tailwind CSS are you using?

v4.0.4

What build tool (or framework if it abstracts the build tool) are you using?

[email protected]

What version of Node.js are you using?

v20.11.0

What browser are you using?

N/A

What operating system are you using?

Ubuntu 20.04.6 LTS (in Windows Subsystem for Linux)

Reproduction URL

https://github.com/wongjn/tailwind-nuxt

Describe your issue

See my original debugging journey at #15818 (reply in thread)

Perhaps related to #16133 in terms of HTML entity encoding causing the issue.

When you have a template with enough elements with props on them, i.e:

<script setup lang="ts">
const includedFeatures = ["Foo", "Bar", "Baz"];
</script>

<template>
  <main class="" lang="de">
    <div class="">
      <div class="">
        <div class="">
          <div class="">
            <img class="" src="" alt="" />
          </div>
        </div>
      </div>
    </div>
  </main>
</template>

It passes a threshold in Vue's compiler to compile the template as a "static" VNode:

import { defineComponent as _defineComponent } from 'vue'
import { createElementVNode as _createElementVNode, createStaticVNode as _createStaticVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = {
  class: "",
  lang: "de"
}


export default /*@__PURE__*/_defineComponent({
  __name: 'index',
  setup(__props) {

const includedFeatures = ["Foo", "Bar", "Baz"];

return (_ctx: any,_cache: any) => {
  return (_openBlock(), _createElementBlock("main", _hoisted_1, _cache[0] || (_cache[0] = [
    _createStaticVNode("<div class=\\"\\"><div class=\\"\\"><div class=\\"\\"><div class=\\"\\"><img class=\\"\\" src=\\"\\" alt=\\"\\"></div></div></div></div>", 1)
  ])))
}
}

})

However, if we have a valid Tailwind class in there:

 <div class="">
-  <div class="">
+  <div class="after:content-['']">
     <img class="" src="" alt="" />

Then Vue compiles it to (snipped for brevity):

return (_ctx: any,_cache: any) => {
  return (_openBlock(), _createElementBlock("main", _hoisted_1, _cache[0] || (_cache[0] = [
    _createStaticVNode("<div class=\\"\\"><div class=\\"\\"><div class=\\"after:content-[&#39;&#39;]\\"><div class=\\"\\"><img class=\\"\\" src=\\"\\" alt=\\"\\"></div></div></div></div>", 1)
  ])))
}
}

Notice the after:content-[&#39;&#39;]. Since this is a module in Vite's module graph, this gets scanned for class candidates by Tailwind. It sees after:content-[&#39;&#39;] as a valid class and generates a rule for it:

.after\:content-\[\&\#39\;\&\#39\;\] {
  &::after {
    content: var(--tw-content);
    --tw-content: &#39;&#39;;
    content: var(--tw-content);
  }
}

And then when the default PostCSS pipeline in Nuxt runs on this, it errors out:

 ERROR  Nuxt Build Error: [vite:css] [postcss] /path/to/project/assets/css/main.css:128:24: Unknown word                                                                                  nuxi 11:01:10 PM
file: /path/to/project/assets/css/main.css:128:23

    file: assets/css/main.css:128:23
    at Input.error (node_modules/postcss/lib/input.js:109:16)
    at Parser.unknownWord (node_modules/postcss/lib/parser.js:593:22)
    at Parser.other (node_modules/postcss/lib/parser.js:435:12)
    at Parser.parse (node_modules/postcss/lib/parser.js:470:16)
    at parse (node_modules/postcss/lib/parse.js:11:12)
    at new LazyResult (node_modules/postcss/lib/lazy-result.js:133:16)
    at Processor.process (node_modules/postcss/lib/processor.js:53:14)
    at compileCSS (node_modules/vite/dist/node/chunks/dep-M1IYMR16.js:48784:59)
    at async Object.transform (node_modules/vite/dist/node/chunks/dep-M1IYMR16.js:48039:11)
    at async transform (node_modules/rollup/dist/es/shared/node-entry.js:19787:16)
@philipp-spiess
Copy link
Member

@wongjn Hey! I'm not really sure what caused this but we've landed some bigger changes in the Vite plugin now that I validated against your repro and it will ensure that the class name is correctly picked up since the files are now read form the file system directly for scanning 👍 Thanks!!

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

Successfully merging a pull request may close this issue.

2 participants