tailwindcss icon indicating copy to clipboard operation
tailwindcss copied to clipboard

Deleting an SVG asset causes a Vite HMR crash while processing `@import "tailwindcss"`

Open geomaster opened this issue 8 months ago • 2 comments

What version of Tailwind CSS are you using?

tailwindcss v4.1.1, @tailwindcss/vite v4.1.1

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

Vite v6.2.5

What version of Node.js are you using?

v22.13.1

What browser are you using?

N/A (Issue occurs in Vite dev server during HMR)

What operating system are you using?

Linux 6.13.7-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 13 Mar 2025 18:12:00 +0000 x86_64 GNU/Linux

Reproduction URL

https://github.com/geomaster/vite-tailwind-v4-svg-delete-repro

Describe your issue

When using Tailwind CSS v4 via @import "tailwindcss"; in index.css and the @tailwindcss/vite plugin, the Vite development server crashes during Hot Module Replacement (HMR) if an asset (e.g., an SVG imported via standard ?url import) is deleted.

Steps to Reproduce:

  1. Clone the reproduction repository: git clone https://github.com/geomaster/vite-tailwind-v4-svg-delete-repro
  2. Install dependencies: pnpm install
  3. Start the Vite dev server: pnpm dev
  4. In another terminal, run the following command while the dev server is running:
    sed -i '/import iconUrl from/d' src/App.tsx && sed -i '/<img src={iconUrl}/d' src/App.tsx && rm src/assets/icon.svg && echo "Triggered bug sequence."
    
    (This removes the JS import, the usage in JSX, and then deletes the SVG file)
  5. Observe the terminal running pnpm dev.

Observed Behavior:

The Vite dev server crashes with an ENOENT: no such file or directory error trying to open the deleted SVG file. The error trace points to the vite:css-analysis plugin and mentions the src/index.css file, even though src/index.css does not directly reference the SVG via url():

[plugin:vite:css-analysis] ENOENT: no such file or directory, open '/home/geomaster/Projects/test/vite-tailwind4-asset-delete-repro/src/assets/icon.svg'

/home/geomaster/Projects/test/vite-tailwind4-asset-delete-repro/src/index.css

    at async open (node:internal/fs/promises:638:25)
    at async Object.readFile (node:internal/fs/promises:1242:14)
    at async fileToDevUrl (file:///home/geomaster/Projects/test/vite-tailwind4-asset-delete-repro/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/vite/dist/node/chunks/dep-Pj_jxEzN.js:13597:21)
    at async TransformPluginContext.transform (file:///home/geomaster/Projects/test/vite-tailwind4-asset-delete-repro/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/vite/dist/node/chunks/dep-Pj_jxEzN.js:48876:27)
    at async EnvironmentPluginContainer.transform (file:///home/geomaster/Projects/test/vite-tailwind4-asset-delete-repro/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/vite/dist/node/chunks/dep-Pj_jxEzN.js:47680:18)
    at async loadAndTransform (file:///home/geomaster/Projects/test/vite-tailwind4-asset-delete-repro/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/vite/dist/node/chunks/dep-Pj_jxEzN.js:41327:27)
    at async viteTransformMiddleware (file:///home/geomaster/Projects/test/vite-tailwind4-asset-delete-repro/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/vite/dist/node/chunks/dep-Pj_jxEzN.js:42807:24

Expected Behavior:

The Vite dev server should handle the file deletion gracefully via HMR without crashing. The component using the deleted asset should update (likely showing an error or missing image in the browser), but the server itself should remain running.

Important Notes:

  • This crash does not occur if the @import "tailwindcss"; line is removed from src/index.css.
  • This crash does not occur when using Tailwind CSS v3 (with @tailwind directives and the PostCSS plugin setup) under the same conditions.
  • The issue seems independent of how the SVG is imported (tested with standard ?url import here, originally found with vite-plugin-svgr).

geomaster avatar Apr 03 '25 16:04 geomaster

Some things I noticed while testing:

First: it doesn't matter how long it takes you to delete the asset after deleting the reference to it. It doesn't even matter if you restart the server in between. It only matters that you referenced the asset at one point, and the asset no longer exists. Though, restarting the server while the asset is deleted will fix it.

Secondly: restoring the asset will get the server to function again without having to restart it. Though deleting the asset will break the server again. And, if you restore the asset while the server is off, the server will still break if you delete it again.

MoperMop avatar Apr 11 '25 03:04 MoperMop

I looked into this issue and here’s what I found so far: the issue seems to originate around here; the code is reusing an instance of the Scanner that still contains a reference to the SVG that was deleted.

My understanding of the Rust code is limited, but it seems that once SVGs are stored in the file property, there’s no mechanism to remove them when the file no longer exists. Am I missing something?

Also worth noting: importing the SVG in App.tsx isn’t necessary. After the initial scan, deleting any SVG files will break Vite’s HMR.

Hope this helps!

(For cross-reference, the issue is also referenced on vite side here: https://github.com/vitejs/vite/issues/19786)

pguilbert avatar Jun 09 '25 17:06 pguilbert