Skip to content
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

Using pug with vite+tailwindcss in JIT mode causes HMR to not detect changes in new css compiled classes #4588

Closed
7 tasks done
gbea opened this issue Aug 12, 2021 · 8 comments · Fixed by #6987
Closed
7 tasks done

Comments

@gbea
Copy link

gbea commented Aug 12, 2021

Describe the bug

The HMR seems to have a different behavior between regular HTML and pug templates in vue sfc.

When using Tailwind in JIT mode, the HTML template works well and the HMR picks up when tailwind has recompiled the index.css.
But when using a pug template, the HMR only detects a change in the vue file (so the content and the classes are updated) but it does not detect a change in the index.css, and the classes are not applied.

A page reload, or any modification to the index.css (even through a html template), allows us to eventually see the styles.

Reproduction

https://github.com/gbea/vite-pug-tailwind-JIT-bug

System Info

System:
    OS: macOS 12.0
    CPU: (8) x64 Apple M1
    Memory: 54.15 MB / 16.00 GB
    Shell: 4.4.23 - /nix/store/f3g6c2ds4izkzfhfg6p9xi6ac86ys7qp-bash-interactive-4.4-p23/bin/bash
  Binaries:
    Node: 14.17.2 - /nix/store/zj1sqykb3s5a0fakm94qwz7fg6g2zxpm-nodejs-14.17.2/bin/node
    npm: 6.14.13 - /nix/store/zj1sqykb3s5a0fakm94qwz7fg6g2zxpm-nodejs-14.17.2/bin/npm
  Browsers:
    Brave Browser: 91.1.26.67
    Chrome: 92.0.4515.131
    Firefox: 90.0.2
    Safari: 15.0
  npmPackages:
    @vitejs/plugin-vue: 1.4.0 => 1.4.0
    vite: 2.4.4 => 2.4.4

Used Package Manager

npm

Logs

No response

Validations

@y1d7ng
Copy link
Contributor

y1d7ng commented Aug 12, 2021

Tailwind JIT may register any file as a dependency to a CSS file, these include the .vue file where the html template and pug template are located. When the .vue file is updated, not only the corresponding module will be updated, but also the css will be updated.

for (const importer of node.importers) {
if (isCSSRequest(importer.url) && !currentChain.includes(importer)) {
propagateUpdate(importer, boundaries, currentChain.concat(importer))
}
}

But the .vue of the pug template will generate a module of TestPug.vue?vue&type=template&lang.js. This module is not dependent to css, and its isSelfAccepting is true, so modifying the pug template will only request this module again, and will not update css.

@Shinigami92 Shinigami92 added bug: upstream Bug in a dependency of Vite and removed pending triage labels Aug 12, 2021
@gbea
Copy link
Author

gbea commented Aug 25, 2021

If I explicitely add ./src/components/TestPug.vue?vue&type=template&lang.js to tailwind.config.js purge list, the index.css is indeed reloaded, and it behaves as intended. It's not very practical, but it could be a temporary fix for me.

I had a look at the way tailwind registers the purge list with postcss. If I understand correctly, in order to fix this bug we would need to do the same thing (https://github.com/postcss/postcss/blob/main/docs/guidelines/plugin.md#31-use-messages-to-specify-dependencies) at the creation of the virtual module ending with ?vue&type=template&lang.js

I am not familiar at all with this project, would this place be the right to do so?

const src = template.src || descriptor.filename
const srcQuery = template.src ? `&src` : ``
const attrsQuery = attrsToQuery(template.attrs, 'js', true)
const query = `?vue&type=template${srcQuery}${attrsQuery}`
const request = JSON.stringify(src + query)
const renderFnName = ssr ? 'ssrRender' : 'render'
return {
code: `import { ${renderFnName} as _sfc_${renderFnName} } from ${request}`,
map: undefined
}

@masterkain
Copy link

masterkain commented Aug 31, 2021

I have the same issue however with a slightly different behavior, when I change some css classes in the pug template sometimes the changes are picked up and sometimes I need a full page refresh (95% of the times)

  "scripts": {
    "dev": "TAILWIND_MODE=watch vite",

there's this TAILWIND_MODE=watch that does trigger a full page reload on change, kinda annoying, but given we have to do it anyway...

this is especially troublesome because since it doesn't fail 100% of the time you are always unsure if the css changes you made are being taken into account or not.

@masterkain
Copy link

out of desperation I reverted some views back to normal html files and I have the same issue.

@RobinMalfait
Copy link

Hey Tailwind maintainer here!

I just tried to debug this issue and I think (unless I'm missing something) that this is a Vite issue and not a Tailwind issue: tailwindlabs/tailwindcss#6340 (comment)

The TL;DR of my comment is, if you have this postcss.config.js file:

module.exports = {
  plugins: [
    /* This is a new plugin, unrelated to Tailwind */
    function (root) {
      console.log('A change happened!')
      return root
    },


    /* Other plugins in the chain */
    require('tailwindcss'),
    require('autoprefixer')
  ]
}

Then you will notice that the log is called when you change the TestHtml.vue file, but it is not called when you make a change in TestPug.vue.

Since PostCSS is never called again, Tailwind is not called and doesn't know about this change.

@lubomirblazekcz
Copy link
Contributor

i had a similiar problem with .twig files that are compiled manually outside vite, and I managed to hack it this way

const reloadTailwind = {
    name: 'reload-tailwind',
    transformIndexHtml(html) {
        return html.replace('tailwind.css', 'tailwind.css?v=' + new Date().getTime())
    }
}

@songololo
Copy link

Unfortunately none of these workarounds is working for me, and a related bug #5270 means that I can't manually access import.meta.hot to run import.meta.hot.invalidate() (assuming this forces a reload).

I was hoping to use something to this effect:

const reloadTailwind = () => {
  return {
    name: 'reload-tailwind',
    apply: 'serve',
    handleHotUpdate(context) {
      console.log(context.modules)
      console.log(import.meta.hot)
      // doesn't work:
      import.meta.hot.invalidate()
      return context
    },
  }
}

@char101
Copy link

char101 commented Apr 23, 2022

Manual modification based on above pull request is to edit node_modules/@vitejs/plugin-vue/dist/index.js, search for !templateModule (there is only one match) and replace the containing code block with these lines

    if (!templateModule) {
      affectedModules.add(mainModule);
    } else if (mainModule && !affectedModules.has(mainModule)) {
      const styleImporters = [...mainModule.importers].filter((m) => /\.css/.test(m.url));
      styleImporters.forEach((m) => affectedModules.add(m));
    }

@github-actions github-actions bot locked and limited conversation to collaborators May 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants