vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.62k stars 6.09k forks source link

[HMR] TailwindCSS do not compile new CSS when files with HMR changed #15460

Open KermanX opened 9 months ago

KermanX commented 9 months ago

Describe the bug

TailwindCSS does not compile new CSS when a file is modified and handled by HMR (e.g. a Vue SFC) in dev mode.

The class name of the element is updated by the Vue plugin via HMR, but Tailwind doesn't create a new rule for the new class name. So the new class name becomes useless.

There is a similar issue, which is about pug: https://github.com/vitejs/vite/issues/4588

And there is also a relative test (pug only): https://github.com/vitejs/vite-plugin-vue/blob/main/playground/tailwind/__tests__/tailwind.spec.ts.

I think it is an issue of Vite, not plugin-vue. Because this also happens to my web framework and its plugin (with HMR).

Reproduction

https://stackblitz.com/edit/vitejs-vite-8djtq2?file=src%2FApp.vue

Steps to reproduce

  1. install and dev
  2. The text "test" in the preview panel is blue
  3. modify App.vue: text-blue-400text-red-400
  4. The text "test" becomes black, instead of red, which means the .text-red-400 rule is not generated.

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.18.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 9.4.2 - /usr/local/bin/npm
    pnpm: 8.10.5 - /usr/local/bin/pnpm
  npmPackages:
    @vitejs/plugin-vue: ^4.5.2 => 4.6.0 
    vite: ^4.5.1 => 4.5.1

Used Package Manager

npm

Logs

Click to expand! ```shell VITE v4.5.1 ready in 2604 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h to show help 17:27:07 [vite] hmr update /src/App.vue ```

Validations

stackblitz[bot] commented 9 months ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

KermanX commented 9 months ago

I think maybe quite a few people (who use Vite+Vue+TailwindCSS) have encountered this but I couldn't find an issue about it. 😢

agm1984 commented 9 months ago

I'm having an issue with Tailwind also. I can't upgrade past Vite 4.5.1 because hot module reload causes the page to full reload every time I change CSS classes.

I tried to isolate the problem by creating a new repo, but it works as expected. I also copied half my project into the new repo and it still worked properly. I also tried a strange idea of copying the affected repo to another folder and running it. That one exhibits the problem also.

I see this in the terminal every time I change CSS class and see full page reload:

10:37:23 AM [vite] page reload src/pages/profile/Profile.vue (circular imports) (x2)

Currently frustrated because it works fine with v4.5.1 but i can't upgrade vite past that. I've spent a lot of time messing with packages but I can't get it working in this project.

  "dependencies": {
    "@unhead/vue": "^1.8.9",
    "@vuelidate/core": "^2.0.3",
    "@vuelidate/validators": "^2.0.4",
    "axios": "^1.6.2",
    "chart.js": "^4.4.1",
    "date-fns": "^2.30.0",
    "fuse.js": "^7.0.0",
    "lodash.clonedeep": "^4.5.0",
    "lodash.debounce": "^4.0.8",
    "maska": "^2.1.10",
    "path": "^0.12.7",
    "pinia": "^2.1.7",
    "primeicons": "^6.0.1",
    "primevue": "^3.45.0",
    "sortablejs": "^1.15.1",
    "sortablejs-vue3": "^1.2.11",
    "vite-plugin-pwa": "^0.17.4",
    "vue": "^3.3.11",
    "vue-router": "^4.2.5",
    "vue-toastification": "^2.0.0-rc.5",
    "vue3-draggable": "^2.0.9",
    "vue3-popper": "^1.5.0"
  },
  "devDependencies": {
    "@pinia/testing": "^0.1.3",
    "@vitejs/plugin-vue": "^4.6.1",
    "@vitest/coverage-v8": "^1.0.2",
    "@vue/test-utils": "^2.4.3",
    "autoprefixer": "^10.4.16",
    "c8": "^8.0.1",
    "eslint": "^8.55.0",
    "eslint-config-prettier": "^8.10.0",
    "eslint-plugin-vue": "^9.19.2",
    "jsdom": "^23.0.1",
    "postcss": "^8.4.32",
    "prettier": "^2.8.8",
    "tailwindcss": "^3.4.0",
    "unplugin-vue-components": "^0.26.0",
    "vite": "^5.0.10",
    "vite-plugin-eslint": "^1.8.1",
    "vitest": "^1.0.2"
  }
KermanX commented 9 months ago

@agm1984 I think maybe https://github.com/vitejs/vite/issues/15221 is more relative to your issue, rather than this one.

Also try this?

npm run dev --debug hmr
KermanX commented 9 months ago

I debugged and found these:

When a Vue file is modified, because it is self-accepting, and it has /index.html?html-proxy&direct&index=0.css as its importer, which is a CSS request, the following lines are executed.

https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/hmr.ts#L288-L293

However, it does nothing effective because propagateUpdate returns at https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/hmr.ts#L312, and the return value is ignored.

agm1984 commented 9 months ago

Hmm, I did npm run dev --debug hmr and it says

(!) Could not auto-determine entry point from rollupOptions or html files and there are no explicit optimizeDeps.include patterns. Skipping dependency pre-bundling.

And the app is not running properly. I can't access it. My vite config is on port 3000 but the one that loads is on port 5173 and it doesn't work on that port, probably because it skipped dependency pre-bundling.

KermanX commented 9 months ago

@agm1984 I'm sorry. The command I provided is wrong. It should be pnpm run dev --debug hmr or npm run dev -- --debug hmr.

And I think maybe you're having a different problem than this issue. It might be better to create a new issue with minimal reproduction.

bluwy commented 9 months ago

@agm1984 That's a different issue and perhaps you're interested in https://github.com/vitejs/vite/pull/15118 instead.

@KermanX If I move the @tailwind code into it's own CSS file and import through a JS file, it works. From what I can tell, your current setup doesn't work because the <style> tag is plainly transpiled to CSS, and there's no JS code that handles what to do when HMR should apply. That is unless Vite injects one, but the current expected behaviour for now is to force a full reload.

As to why a full reload didn't happen, I'm not really sure but it could be related to https://github.com/vitejs/vite/pull/15229, where we explicitly didn't want a full reload to happen for tailwind for circular imports. I suppose we always expected Tailwind code to exist in their own CSS file for better HMR anyways.

KermanX commented 9 months ago

From what I can tell, your current setup doesn't work because the <style> tag is plainly transpiled to CSS, and there's no JS code that handles what to do when HMR should apply.

I think it is reasonable to make HMR work with <style> tag in index.html. Because when using TailwindCSS, there likely are no more or very few CSS rules than the three @tailwind directives, so a styles.css seems to be spare. Also, it is more consistent in design.


As to why a full reload didn't happen, I'm not really sure but it could be related to #15229, where we explicitly didn't want a full reload to happen for tailwind for circular imports.

I think if HMR is intended to not work with <style> tag in index.html, maybe the return value I’ve mentioned in https://github.com/vitejs/vite/issues/15460#issuecomment-1872434083 should not be ignored, in order to trigger a full reload. But I am not sure.

Danones commented 9 months ago

Hey 👋

I have just created the #15516 issue when afterwards I noticed yours @KermanX

I am using Remix + Vite + Tailwind as tech stack and noticed that in my case, the CSS class actually reaches the browser css file but nothing is applied. Which in your case it seems like the class isnt created at all.

KermanX commented 9 months ago

@Danones I think the two issues are different.

My issue is that Vite doesn't trigger a TailwindCSS re-run when putting the @tailwind directives inside index.html.

In your issue, TailwindCSS re-runs after the file is changed (because you run the TailwindCSS compiler in a new process in watch mode), which I think may be a problem with how Vite (or maybe Remix plugin) handles modified CSS.

bluwy commented 9 months ago

I think if HMR is intended to not work with <style> tag in index.html, maybe the return value I’ve mentioned in #15460 (comment) should not be ignored, in order to trigger a full reload. But I am not sure.

I don't think that return value will fix the issue you're seeing, but it does look strange that the value is ignored. Seems like it's being called to only mutate boundaries.

For a fix, we could:

  1. Special case CSS that are directly referenced from HTML files to force a full reload. I can reproduce the no-HMR issue if I use @import and updating the imported file too.
  2. Re-work CSS handling in HTML files so they have HMR. That likely means refactoring this code, which is a little complex.
Danones commented 9 months ago

@Danones I think the two issues are different.

My issue is that Vite doesn't trigger a TailwindCSS re-run when putting the @tailwind directives inside index.html.

In your issue, TailwindCSS re-runs after the file is changed (because you run the TailwindCSS compiler in a new process in watch mode), which I think may be a problem with how Vite (or maybe Remix plugin) handles modified CSS.

You are right @KermanX and I was aware of that. Just wanted to leave a comment to make aware of a similar issue.

I have found what was causing my issue but I am afraid the solution isn't optimal. Seems to be related with hydration issues, if you have any extensions on your browser, those issues seem to break the styles. Updating to

"react": "^18.3.0-next-fccf3a9fb-20230213",
"react-dom": "^18.3.0-next-fccf3a9fb-20230213"

seems to fix the issue for now but because I am using this on my company project I will have to wait for this to be more stable in order to move forward

agm1984 commented 8 months ago

Sorry for a bump but I just noticed this in the release notes:

feat(hmr): reload for circular imports only if error (#15118) (6ace32b), closes https://github.com/vitejs/vite/issues/15118

This might fix my issue that I described up in this thread. I will try V5 again as soon as 5.1 gets out of beta.