Skip to content

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

Closed
@wongjn

Description

@wongjn

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions