vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
68.14k stars 6.14k forks source link

HMR not working with symlinked directory on Windows opened from symlink path #16176

Open StefanOctavian opened 7 months ago

StefanOctavian commented 7 months ago

Describe the bug

I moved a folder that I keep all my projects in from drive D to drive C because I needed more space on C and in order not to have to change my habits of opening the folder and working with it, I created a symlink to it at the old path on drive C.

I added the resolve.preserveSymlinks: true option to vite.config.ts in one of my Vite + React + Typescript projects. But now, if I navigate to the project directory through the symlink (by cd-ing into it or in VSCode going to Open Recent, but NOT Open Folder and navigating the explorer as that seems to actually bypass the symlink and actually open the folder on drive D), hmr won't work anymore and any change to any file always triggers a full-page reload

The workaround is to just cd directly into the folder at its actual location, not through the symlink, but I want to avoid that. An even better workaround is using Open Folder in VSCode since it looks like it skips symlinks and goes straight to the real folder

Reproduction

https://github.com/StefanOctavian/vite-hmr-symlink-bug-example

Steps to reproduce

Clone the repo somewhere at some/path1, preferebly on another drive other than C Open an elevated command prompt Navigate to some/path2 on drive C Run mklink /D symlink some/path1 Open a new terminal and run cd some/path2/symlink Run npm install Run npm run dev Open the first link in the Vite output Change any file in src and test hmr

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (8) x64 Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz
    Memory: 7.67 GB / 15.80 GB
  Binaries:
    Node: 18.14.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 9.3.1 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Chromium (122.0.2365.80)
    Internet Explorer: 11.0.19041.3636

Used Package Manager

npm

Logs

No response

Validations

sapphi-red commented 7 months ago

I wasn't able to reproduce.

I cloned the reproduction to D:\vite-hmr-symlink-bug-example-main and linked to C:\Users\green\Downloads\symlink. Started the dev server and changed this line, Vite ran HMR and the screen was updated correctly.

StefanOctavian commented 7 months ago

@sapphi-red Did you follow exactly the steps I provided to start the dev server? As I said, the issue only manifests when starting the dev server explicitly through the symlink and also you need to use the native Windows mklink command to create the link (not WSL or Git Bash)

sapphi-red commented 7 months ago

Yes, I tried it with both cmd and powershell.

vaites commented 6 months ago

I found this issue using Vite with Laravel. In my case, Vite does not compile CSS/JS if launched from symlinked folder, but works well if launched from real path.

An easy way to check this is using Laravel Breeze:

composer create-project laravel/laravel:^11.0 example-app
cd example-app
composer require laravel/breeze
php artisan breeze:install
npm run dev 

To serve Laravel, run php artisan serve and see no styles because app.css is not compiled.

My paths are:

Using this vite.config.js file solves the problem:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    resolve: {
        preserveSymlinks: true,
    },
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
});
EmperorArthur commented 6 months ago

I've found the problem happens to me only on the server restarting itself, from say modifying the "vite.config.ts" file.

Likely Cause

Similar to #10802

Copying/Pasting my notes from there.

Originally thought there was a Node bug, but it's really a naming/documentation issue causing confusion.

The problem is the promises based version of "realpath" is really for "realpath.native"! It's mentioned in the documentation but it's easy to overlook.

fs.realpath('T:', (e,r) => console.log(r)) // Gives "T:\\"
fs.realpath.native('T:', (e,r) => console.log(r)) // Gives "\\\\ServerName\\\MountedDirectory"
fs.realpathSync('T:') // Gives "T:\\"
fs.realpathSync.native('T:') // Gives "\\\\ServerName\\\MountedDirectory"

// The problem
await fs.promises.realpath('T:') // Gives "\\\\ServerName\\\MountedDirectory"