vitejs / vite

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

App keeps refreshing with log: `Server connection lost polling for restart` #4259

Closed mattiaz9 closed 2 years ago

mattiaz9 commented 3 years ago

Describe the bug

In certain situation the app keeps refreshing indefinitely giving this log in console: server connection lost polling for restart.

I'm using vite 2.4.2 with https, react and typescript.

Reproduction

I noticed this happen in this 2 situations:

  1. Using Brave with a CORS extension enabled on the page (in my case is CORS Unblock). Weirdly using Chrome with the same Chromium version and same extension doesn't cause the problem
  2. Running vite with the --host flag and accessing it with my phone (Safari on iOS 14) via the shared url: https://192.168.1.xxx:3000. Removing the https option "solves" the problem on iOS.

System Info

System:
    OS: macOS 11.4
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 808.27 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
Binaries:
    Node: 14.17.3 - /usr/local/bin/node
    Yarn: 1.22.5 - /usr/local/bin/yarn
    npm: 6.14.13 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
Browsers:
    Brave Browser: 91.1.26.74
    Chrome: 91.0.4472.114
    Firefox: 88.0.1
    Safari: 14.1.1

Used Package Manager

yarn

Logs

No response

Validations

dmx974 commented 3 years ago

Got the same problem on 2.3.7 as well. It can be reproduced if you have hmr.host set to localhost in your vite.config.js

...
  server: {
    hmr: {
      protocol: 'ws',
      host: 'localhost'
    }
  },
...

Solution: Remove the whole hmr key in your vite.config.js I personally think the host option doesn't make any sense.

it should be something like this:

...
  server: {
    hmr: {
      protocol: 'ws',
      port: 3000
    }
  },
...

@to vitejs devs: maybe on iOS, you should detect we've set localhost for hmr.host and prevent the flicking / constant page refresh / or ignore the hmr.host: 'localhost'.

The good news is that I got 15000 pageviews on Google Analytics in a few seconds, it make me feel my app is super successful ;-)

mattiaz9 commented 3 years ago

@dmx374 I haven't set hmr.host. I tried with a blank vite + typescript + react project and got the same problem. The only params I set are server.https.key & server.https.cert.

I'm wondering if the certificate has something to do with it. I used the following command to crete it: mkcert -key-file ssl/key.pem -cert-file ssl/cert.pem localhost

jceipek commented 3 years ago

I can reproduce this locally in vite 2.4.3 with the latest versions of Safari, Google Chrome, and Microsoft Edge with a vanilla yarn create vite (no react) altered by adding the following vite.config.ts:

import { defineConfig, ConfigEnv } from 'vite';

export default defineConfig((_configEnv: ConfigEnv) => {
    return {
        server: {
            port: 3000,
            strictPort: true,
            hmr: {
                port: 9000
            },
        },
        base: './'    
    }
});
mrweiner commented 3 years ago

Are y'all running your projects in docker containers? When I run the server in docker I experience this issue and hot reload is also broken. When I run the server locally, though, instead of in a container, I don't get this error and hot reload works as expected.

mattiaz9 commented 3 years ago

@mrweiner I personally don't, I run it locally.

jceipek commented 3 years ago

@mrweiner My minimal reproduction involved no Docker containers, but I first experienced it in conjunction with Docker, which motivated me to find a minimal reproduction.

pzmosquito commented 3 years ago

I'm having the same issue (vite 2.4.4). I run the vite server in a docker container, and use a reverse proxy to route the HTTPS traffic to this container. I already set server.hmr.clientPort: 443, but the app keeps refreshing. I even tried server.hmr: false to disable hmr entirely, still the same issue.

Doeke commented 3 years ago

Also started having this problem, but only in Chrome, not in Firefox. Changing the various server.hmr settings has no effect. I even downgraded to vite 2.1.5 but still the problem occurs. I think maybe Chrome made a change that causes the websocket to lose connection? Can anyone confirm this works in other browsers with default hmr settings?

weeblr commented 3 years ago

Hi Just chiming in, same issue, no proxy, no docker. Tested various server.hmr combinations, including setting server.host to a named host (ie company.dev) with an associated certificate, added to the browser trusted list.

The websocket connection keeps failing. I am using current Edge but also tested in Chrome.

NB: all is well with same setup under HTTP.

patak-dev commented 3 years ago

Would you test your projects using vite@2.5.0-beta.1 ?

mattiaz9 commented 3 years ago

@patak-js I have the same problem described above and now I also get this error:

[vite] Internal server error: Unexpected token } in JSON at position 542
Plugin: vite:esbuild
  File: /.../vite-project/src/main.tsx

I'm not sure what it could be.

pzmosquito commented 3 years ago

Would you test your projects using vite@2.5.0-beta.1 ?

just tried it, still no luck.

pzmosquito commented 3 years ago

UPDATE: tried 2.5.0-beta.2, same issue

pzmosquito commented 3 years ago

UPDATE: I was able to resolve the issue by setting the hmr.port to 443 since my vite container is behind a SSL proxy. I thought it should be the hmr.clientPort option, but obviously it was not. This works on both 2.4.4 and 2.5.0-beta.*

Doeke commented 3 years ago

I was not able to resolve it with any of the suggestions. The only temporary fix was npm ci and that only works until the first time hotreload is triggered. What's more, I am not having this problem in Firefox, only in Chrome on linux. Very confusing.

vfonic commented 3 years ago

@pzmosquito can you please share your full config?

I've managed to get this to not reload. The WS never connects, but at least it doesn't reload and I can use non-built/non-minified JS/TS(x) files.

server: {
    // host: '0.0.0.0',
    // https: true,
    hmr: {
      host: 'ad345ds2.ngrok.io',
      // port: 443,
      // protocol: 'wss',
    },
  },

Uncommenting https or port makes Vite enter the endless reloading loop.

PS I'm using ngrok tunnel.

pzmosquito commented 3 years ago

@pzmosquito can you please share your full config?

I've managed to get this to not reload. The WS never connects, but at least it doesn't reload and I can use non-built/non-minified JS/TS(x) files.

server: {
    // host: '0.0.0.0',
    // https: true,
    hmr: {
      host: 'ad345ds2.ngrok.io',
      // port: 443,
      // protocol: 'wss',
    },
  },

Uncommenting https or port makes Vite enter the endless reloading loop.

PS I'm using ngrok tunnel.

import path from "path";
import { defineConfig } from "vite";
import reactRefresh from "@vitejs/plugin-react-refresh";

export default defineConfig({
    mode: "development",
    resolve: {
        alias: {
            _: path.resolve(__dirname, "src"),
        },
    },
    plugins: [
        reactRefresh(),
    ],
    clearScreen: false,
    server: {
        host: "0.0.0.0",
        port: 3000,
        strictPort: true,
        hmr: {
            port: 443,
        },
    },
});
FossPrime commented 2 years ago

In CodeSandbox traffic is routed to port 3000 from an SSL proxy on port 443. Vite will by default look for port 3000, instead of port 443. The only configuration needed to make it work was changing the HMR port.

server: {
    hmr: {
      port: 443
    }
  }

Working codesandbox: https://codesandbox.io/s/vite-hmr-fix-4259-h6c2l?file=/vite.config.ts:180-227

vfonic commented 2 years ago

I tried all of the above solutions and finally found a solution that works for me. 🎉

Here's what works for me:

  1. I start ngrok ngrok http 3000
  2. I use ngrok to load my website in an iframe (this is needed in my case because my website is loaded within a third-party website and I can only configure my website url that they will show to users in an iframe)
  3. I start localtunnel npm package that I install globally: npm install -g localtunnel
  4. I use localtunnel to listen for WebSocket connections on port 3036: lt --port=3036

So in my case:

mattrossman commented 2 years ago

@vfonic what is the significance of port 3036 -- how did you determine or specify that it's for Vite's HMR traffic? What did you do with the tunnel URL produced by localtunnel? Maybe sharing your full config would help. Trying to better understand the setup for using Vite behind Ngrok.

vfonic commented 2 years ago

@mattrossman that's the port that I've set the vite to run on in vite.json:

{
  "all": {
    "sourceCodeDir": "app/javascript",
    "watchAdditionalPaths": []
  },
  "development": {
    "autoBuild": true,
    "publicOutputDir": "vite-dev",
    "port": 3036
  },
  "test": {
    "autoBuild": true,
    "publicOutputDir": "vite-test"
  }
}

This is the default setup that vite_ruby gem creates. I believe it's set to this port in order to avoid using the same port number that rails server uses for backend.

catboy1006 commented 2 years ago

I solved the problem,you need fix Charles -> SSL PRoxying Settings -> *:443 8641287C-201E-4B68-802A-D32EF21FBDF0

aflansburg commented 2 years ago

I experienced this same issue when building with docker. In the container my app runs on port 3000, however, as I have another app running on that port on my local I am using 3001 as my host port. From my docker-compose.yml for my Svelte+Vite app:

  web-frontend:
    build:
      context: ./svelte-vite-frontend-dock
      dockerfile: Dockerfile
    volumes:
      - ./svelte-vite-frontend-dock:/usr/src/app
      - /usr/src/app/node_modules
    ports:
      - 3001:3000
      - 24678:24678

Clues above in posts regarding people using reverse proxies made me realize that I needed to add this to my vite.config.js file:

server: {
    hmr: {
      clientPort: 3001,
    },
  },

This immediately fixed my issue.

blakeyi commented 2 years ago

@pzmosquito can you please share your full config? I've managed to get this to not reload. The WS never connects, but at least it doesn't reload and I can use non-built/non-minified JS/TS(x) files.

server: {
    // host: '0.0.0.0',
    // https: true,
    hmr: {
      host: 'ad345ds2.ngrok.io',
      // port: 443,
      // protocol: 'wss',
    },
  },

Uncommenting https or port makes Vite enter the endless reloading loop. PS I'm using ngrok tunnel.

import path from "path";
import { defineConfig } from "vite";
import reactRefresh from "@vitejs/plugin-react-refresh";

export default defineConfig({
    mode: "development",
    resolve: {
        alias: {
            _: path.resolve(__dirname, "src"),
        },
    },
    plugins: [
        reactRefresh(),
    ],
    clearScreen: false,
    server: {
        host: "0.0.0.0",
        port: 3000,
        strictPort: true,
        hmr: {
            port: 443,
        },
    },
});

need to set strictPort=true, thanks a lot

vfonic commented 2 years ago

There are two issues that talk about similar/the same issue. This one and Vite HMR is unusable behind reverse proxies with random port numbers for client.

I posted my config there, so here it is here as well:

Ahhh, well you could try my setup. It works, but uses two tunnels. Here's how I configured everything:

vite.config.ts:

// ...
export default defineConfig({
// ...
  server: {
    hmr: {
      host: `some-ngrok-subdomain.loca.lt`,
      port: 443,
    },
  },
// ...

package.json:

"devDependencies": {
  "localtunnel": "2.0.1",
  "ngrok": "^4.2.2"
}

And then I start everything:

./node_modules/.bin/lt --subdomain=some-ngrok-subdomain --port=3036
./node_modules/.bin/ngrok http -subdomain=some-ngrok-subdomain
Damato commented 2 years ago

Happy to report for gitpod.io users who faced the same issue as the dev environments are likewise hosted in containers, changing the hrm.port to 443 solved the issue immediately.

vite.config.ts:

// ...
export default defineConfig({
// ...
  server: {
    hmr: {
      port: 443,
    },
  },
// ...

Edit: happy to report this works without specifying the host.

pulkitvyas08 commented 2 years ago

None of the methods mentioned here worked when using nginx and localhost:3000

abrin commented 2 years ago

I think I got this working with NGINX (vite 2.7.1):

in your nginx config add an explicit mapping for the socket connection:

  location /sockjs-node {
      proxy_pass http://frontend;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
      # And now all the stuff from above, again.
      proxy_set_header    Host                localhost;
      proxy_set_header    X-Real-IP           $remote_addr;
      proxy_set_header    X-Forwarded-Host    localhost;
      proxy_set_header    X-Forwarded-Server  localhost;
      proxy_set_header    X-Forwarded-Proto   $scheme;
      proxy_set_header    X-Forwarded-For     $remote_addr;
      proxy_redirect off;
      proxy_connect_timeout 90s;
      proxy_read_timeout 90s;
      proxy_send_timeout 90s;
  }

then in the vite.config.js do something similar for the HMR section:

   hmr: {
      // Internal port (in container same as sveltekit port).
      port: 8000,
      host: "localhost",

      // External port (Docker host)
      clientPort: 8000,
      path: "/sockjs-node/",
    },

I also had to add this to the docker file running Vite (which I don't like, but seemed to work):

RUN mkdir node_modules/.vite
RUN chmod a+w node_modules/.vite
pulkitvyas08 commented 2 years ago

Thanks for the quick reply but it doesn't seem to work

bluwy commented 2 years ago

Maybe related https://github.com/vitejs/vite/issues/6068

datacas commented 2 years ago

Hi,

I'm developing in localhost with Docker, and for me, the valid config is:

export default defineConfig({
  server: {
    host: true,
    port: 5000    
  },
....
}

Or try to use ssl with mkcert (https://github.com/FiloSottile/mkcert#installation)

I hope it helps.

ckilb commented 2 years ago

I'm quite sure this is not related to Docker nor ngrok. My app is running locally and I had the same issue- if I enable a CORS extension my app was constantly refreshing.

If you experience the same have a look into your web developer tools console logs and enable "Preserve logs" - you may see error messages like WebSocket connection to 'ws://localhost:xxxx/' failed.

What was working for me is to not open my app via "http://localhost:xxx..." but "http://127.0.0.1:xxx...." instead - no config change necessary.

If you don't like to use "http://127.0.0.1..." in your URL for some reason it may also work if you change your hmr config to use 127.0.0.1 as a specific host like this:

server: { hmr: { host: '127.0.0.1' } },

benj56 commented 2 years ago

Same issue with Electron v17. Super annoying to debug as inside of Electron you cannot read the logs in the console because it constantly reloads. In the electron main process you only get something like:

[electron] [43218:0323/171253.916748:ERROR:ssl_client_socket_impl.cc(995)] handshake failed; returned -1, SSL error code 1, net_error -202

Took a while for me to connect this issue with the vite websocket. After commeting out the reload in the Vite client at the socket close listener, I could at least see the logs in the Electron renderer. Interestingly, changing the protocol in hmr: { protocol: 'ws' } did not change the SSL error, it would fail to connect to ws://localhost:3000 all the same.

Using a valid certificate for vite, with the help of vite-plugin-mkcert fixed the issue. So does app.commandLine.appendSwitch('ignore-certificate-errors'); in Electron.

The biggest issue is debugging this as initially there seems to be no indication this issue is connected to Vite without being able to see the console. I guess the root cause might be Electron, but maybe we can also do something to prevent endless reloading on Vite's site?

benjaminmiles commented 2 years ago

Because I wanted to achieve a local-to-git-to-codesandbox flow, here is how I got Vite working for both local development and CodeSandbox without the refresh issue.

1) Add an extra dev script with a new sandbox mode. I called it sandbox:

  "scripts": {
    "dev": "vite --host",
    "sandbox": "APP_ENV=sandbox vite",
    "build": "vite build",
    "preview": "vite preview"
  },

2) Set vite.config.js to pick up on that accordingly (avoiding the clientPort from local dev):

{
  server: process.env.APP_ENV === "sandbox" ? { hmr: { clientPort: 443 } } : {};
}

3) Create a codesandbox.config.json config for the new startScript:

{
  "container": {
    "startScript": "sandbox"
  }
}

Working sandbox: https://codesandbox.io/s/react-three-fiber-vite-starter-r1tgld

Git repo:
https://github.com/benjaminmiles/react-three-vite

martinszeltins commented 2 years ago

I am experiencing this issue with 2.9.1 inside a docker container.

UPDATE: This solved the issue for me, I changed hmr.port to hmr.clientPort in vite.config.js

Here is my git diff

    hmr: {
-     port: 14365
+     clientPort: 14365
    }
robots4life commented 2 years ago

@aflansburg https://github.com/vitejs/vite/issues/4259#issuecomment-999092118 Could you kindly be asked to post your entire docker-compose setup with Nginx conf, Node and latest SvelteKit working and its config with the Vite websockets ?

Likewise anyone else that works with a Docker environment and got the websockets working with a Node app through Nginx, it would be great to be able to have a look at how you have set up things to work, thank you.

martinszeltins commented 2 years ago

@aflansburg #4259 (comment) Could you kindly be asked to post your entire docker-compose setup with Nginx conf, Node and latest SvelteKit working and its config with the Vite websockets ?

Likewise anyone else that works with a Docker environment and got the websockets working with a Node app through Nginx, it would be great to be able to have a look at how you have set up things to work, thank you.

Sure thing, this is my setup / config, hope this helps.

docker-compose.yaml

version: '3.7'

services:

  # Node for client app
  vue-symfony-scaffolding-client-node:
    container_name: vue-symfony-scaffolding-client-node
    build: docker/containers/client-node
    restart: unless-stopped
    stdin_open: true                # Needed for HMR
    environment:
      - CHOKIDAR_USEPOLLING=true    # Needed for HMR
    ports:
      - 14365:3000
    volumes:
      - ./app/client:/var/www
    networks:
      - app-network

  # Nginx for server app
  vue-symfony-scaffolding-server-nginx:
    container_name: vue-symfony-scaffolding-server-nginx
    build: docker/containers/server-nginx
    restart: unless-stopped
    ports:
      - 13100:80
    volumes:
      - ./app/server:/var/www
      - ./docker/containers/server-nginx/etc/nginx/conf.d:/etc/nginx/conf.d
    depends_on:
      - vue-symfony-scaffolding-server-php
      - vue-symfony-scaffolding-server-mysql
    networks:
      - app-network

  # PHP for server app
  vue-symfony-scaffolding-server-php:
    build: docker/containers/server-php
    container_name: vue-symfony-scaffolding-server-php
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: php
      SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
      - ./app/server:/var/www
    networks:
      - app-network
    depends_on:
      - vue-symfony-scaffolding-server-mysql

  # MySQL for server app
  vue-symfony-scaffolding-server-mysql:
    image: mysql:8.0
    container_name: vue-symfony-scaffolding-server-mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: unless-stopped
    tty: true
    ports:
      - "34472:3306"
    volumes:
      - dbdata:/var/lib/mysql/
    environment:
      MYSQL_ROOT_PASSWORD: wGgfBcJzfSer2mLgh5Na5QKaZ
      MYSQL_DATABASE: vue_symfony_scaffolding
    networks:
      - app-network

  # Node websocket server
  vue-symfony-scaffolding-websocket:
    container_name: vue-symfony-scaffolding-websocket
    build: docker/containers/websockets
    restart: always
    stdin_open: true                # Needed for HMR
    environment:
      - CHOKIDAR_USEPOLLING=true    # Needed for HMR
    ports:
      - 46295:46295
    volumes:
      - ./websocket:/var/www
    networks:
      - app-network

# Networks
networks:
  app-network:
    driver: bridge

# Volumes
volumes:
  dbdata:
    driver: local

Here is my vite.config.ts:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'url'
import Components from 'unplugin-vue-components/vite'

export default defineConfig(({ command }) => {
    return {
        plugins: [
            vue({ reactivityTransform: true }),
            Components({}),
        ],

        base: (command === 'build') ? './' : '/',

        resolve: {
            alias: {
                '@': fileURLToPath(new URL('./src', import.meta.url)),
                '@img': fileURLToPath(new URL('./src/assets/img', import.meta.url)),
            },
        },

        server: {
            host: true,

            hmr: {
                clientPort: 14365
            }
        }
    }
})

And my Nginx config (these may not be the actual port numbers used):

server {
    listen 80;

    server_name app.booking-jojo.com;

    client_max_body_size 100M;

    location /ws/ {
        proxy_pass http://localhost:46295;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /api/ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_pass http://localhost:41166/;
    }

    location / {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_pass http://localhost:47344;
    }
}
aflansburg commented 2 years ago

@aflansburg #4259 (comment) Could you kindly be asked to post your entire docker-compose setup with Nginx conf, Node and latest SvelteKit working and its config with the Vite websockets ?

Likewise anyone else that works with a Docker environment and got the websockets working with a Node app through Nginx, it would be great to be able to have a look at how you have set up things to work, thank you.

Hi sorry for the delay. My project is public monorepo and can be seen here. I haven't been able to work on it as of late, but essentially components are:

kfoon commented 2 years ago

I experienced this same issue when building with docker. In the container my app runs on port 3000, however, as I have another app running on that port on my local I am using 3001 as my host port. From my docker-compose.yml for my Svelte+Vite app:

  web-frontend:
    build:
      context: ./svelte-vite-frontend-dock
      dockerfile: Dockerfile
    volumes:
      - ./svelte-vite-frontend-dock:/usr/src/app
      - /usr/src/app/node_modules
    ports:
      - 3001:3000
      - 24678:24678

Clues above in posts regarding people using reverse proxies made me realize that I needed to add this to my vite.config.js file:

server: {
    hmr: {
      clientPort: 3001,
    },
  },

This immediately fixed my issue.

setting the clientPort if you using docker fix my issue

robots4life commented 2 years ago

If anyone is interested, I am using Devilbox for local "remote" development and have thus everything in containers and the host is left clean. Here is an example setup with SvelteKit and NGINX proxy. https://github.com/robots4life/devilskit

sapphi-red commented 2 years ago

Closing as https://github.com/vitejs/vite/pull/8650 covers most reported cases here. Please try 3.0.0-beta.1. If it is still not working with 3.0.0-beta.1, please create a discussion or a issue.