kit: Endless reloading by start svelte-kit it with VS Code Remote-SSH terminal

Describe the bug

Endless reloading by start it from VS Code Remote-SSH terminal: npm run dev -- --open (open localhost:3000 on local computer and svelte is running on remote)

Termorary solution: With --host it works great: npm run dev -- --host --open (open 111.222.333.444:3000 (server ip) on local computer and svelte is running on remote)

Other projects works fine on the same server with same VS Code Remote-SSH, sapper-template, for example. Problem (for me) only with SvelteKit now.

Logs Please include browser console and server logs around the time this bug occurred.

To Reproduce

  1. Open VS Code
  2. Install Remote-SSH (if it doesn’t exist)
  3. Connect to you remote server with Remote-SSH
  4. pnpm init svelte@next my-app
  5. pnpm i
  6. npm run dev -- --open

Expected behavior Work on VS Code Remote-SSH with port forwarding without endless reloading.

Stacktraces If you have a stack trace to include, we recommend putting inside a <details> block for the sake of the thread’s readability:

Stack trace

image

[vite] connecting...
content.js:1 Uncaught (in promise) Error: Unexpected token u in JSON at position 0
    at A (content.js:1)
A @ content.js:1
Promise.then (async)
(anonymous) @ content.js:1
(anonymous) @ content.js:1
t @ content.js:1
(anonymous) @ content.js:1
(anonymous) @ content.js:1
client:184 WebSocket connection to 'ws://localhost:24678/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
(anonymous) @ client:184
client:340 [vite] server connection lost. polling for restart...
(index):1 Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: http://localhost:3001/src/routes/index.svelte?import
start.js:1024 Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: http://localhost:3001/src/routes/$layout.svelte?import
async function (async)
start @ start.js:1018
(anonymous) @ (index):222

Information about your SvelteKit Installation:

Diagnostics
  • The output of npx envinfo --system --npmPackages svelte,@sveltejs/kit,vite --binaries --browsers

    System: OS: Linux 4.15 Ubuntu 18.04.4 LTS (Bionic Beaver) CPU: (2) x64 Intel Xeon E3-12xx v2 (Ivy Bridge, IBRS) Memory: 98.10 MB / 984.89 MB Container: Yes Shell: 4.4.20 - /bin/bash

    Binaries: Node: 14.16.1 - /usr/local/bin/node Yarn: 2.0.0-rc.27 - ~/.npm-global/bin/yarn npm: 6.13.7 - ~/.npm-global/bin/npm

    npmPackages: @sveltejs/kit: next => 1.0.0-next.80 svelte: ^3.29.0 => 3.37.0

  • Your browser

    Chrome 88.0.4324.150 (Official), (64 bit)

Severity Not critical, but it is incrase REPL from 1 second to 8 seconds 😦 if i use the solution with adding --host as additional parameter.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 14
  • Comments: 47 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Thank you very much for your help! 😊

I got it working 🥳 I have following setup on my local machine:

  • Nginx as a gateway (Port 443)
  • SvelteKit behind the gateway (Port 3000)
  • An API server behind the gateway (Port 8080)

If you have a similar setup, here is what you need to do:

1. Adjust your nginx.conf


events {}
http {                                                                                                                               
     server {
         listen       443 ssl http2;                                                                                                  
                                                                                                  
         # Better set absolute paths to those two files                                                                                        ssl_certificate      ssl/localhost.crt;                                                                                      
         ssl/localhost.crt
         ssl/localhost.key;                                                                                                                                                                                                                                     ssl_session_cache    shared:SSL:1m;                                                                                          
         ssl_session_timeout  5m;                                                                                                                                                                                                                                           
         ssl_ciphers  HIGH:!aNULL:!MD5;                                                                                                        ssl_prefer_server_ciphers  on;                                                                                               
         
         # Important for HMR over websockets                                                                                          
         proxy_set_header Upgrade $http_upgrade;                                                                                      
         proxy_set_header Connection 'Upgrade';                                                                                       
         proxy_set_header Host $host;                                                                                                 
                                                                                                                                      
         location / {                                                                                                                 
           proxy_pass http://localhost:3000;                                                                                          
         }                                                                                                                            
                                                                                                                                      
         # Set this if you have a (node.js) server running for handling API calls                                                     
         location /api {                                                                                                              
           proxy_pass http://localhost:8080;                                                                                          
         }                                                                                                                            
     }                                                                                                                                
 }

Make sure to adjust the paths to your certificate and private key file. If you want to create a self-signed certificate for local testing, you can use this command:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt

Don’t forget to reload your config after you have done the changes:

sudo nginx -s reload

2. Adjust your svelte.config.js

    kit: {
        ...
        vite: {
            server: {
                hmr: {
                    port: 443
                }
            }
        },
    }
  1. Enjoy HMR on https://localhost

Just restart SvelteKit and you are good to go:

npm run dev -- --open

From now on you should only use https://localhost, because http://localhost:3000 won’t work with HMR.

*Thanks again everyone for your help ❤️

I think next.169 broke something in relation to this. When I upgraded to next.169 this afternoon, the websocket could not be reached anymore and the page would endlessly reload. I reverted back to next.164 and everything is working again as intended.

Here are my svelte config file and docker compose file. Again, this works with next.164 but does not work with next.169:

svelte.config.js

import preprocess from 'svelte-preprocess';

import adapter from '@sveltejs/adapter-static';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    // Consult https://github.com/sveltejs/svelte-preprocess
    // for more information about preprocessors
    preprocess: preprocess(),
    kit: {
        adapter: adapter(),
        ssr: false,
        target: '#svelte',
        vite: {
            server: {
                https: {
                    key: '/certs/key.pem',
                    cert: '/certs/cert.pem'
                },
                hmr: {
                    protocol: 'wss',
                    port: 24678
                }
            }
        }
    }
};

export default config;

docker-compose.yml

  ui:
    container_name: ui
    image: ui-${UI_MODE}
    build:
      context: ../ui
      dockerfile: Dockerfile.${UI_MODE}
    restart: always
    ports:
      - 24678:24678
    volumes:
      - ../ui/src/:/app/src
      - ../ui/static:/app/static
      - ./configs/certs/mycert.pem:/certs/cert.pem
      - ./configs/certs/mycert-key.pem:/certs/key.pem
    tty: true

I just want to inform that this is still happening on @sveltejs/kit@1.0.0-next.96

And opening port 24678 is working as a workaround

Hi everyone,

Mostly leaving this for future readers, but I believe I have found a fix for people using sveltekit behind a TLS reverse proxy, with no local/native TLS in sveltekit it self.

If you were previously running a config setting protocol, host, etc, you must strip the config down to just this:

		vite: {
			server: {
				hmr: {
					clientPort: 443
				}
			}
		},

This fixed the issue for me, and sveltekit no longer loops infinitely. It seems like you no longer have to specify the host, local port, or protocol.

My setup:

  • sveltekit running in a container on kubernetes
  • TLS traffic handled by a reverse proxy outside of the container
  • TLS traffic forwarded to port 3000 of the sveltekit container port

I hope this helps!

I made some tests on “@sveltejs/kit”: “1.0.0-next.169/170”/ “@sveltejs/adapter-node”: “1.0.0-next.49”.

// svelte.config.js
kit: {
    adapter: node(),
    target: '#svelte',
    ssr: false,
    hostHeader: 'X-Forwarded-Host',
    vite: {
      server: {
        hmr: {
          host: 'localhost',
          protocol: 'ws',
          port: 3001
        }
      }
....
  }
# docker-compose.yaml
  frontend:
    image: frontend-0.0.151
    user: node
    working_dir: /home/node/app
    volumes:
      - ./frontend:/home/node/app
    command: npm run dev
    ports:
      - '3001:3001'
    networks:
      - frontend

response for ws://localhost:3001/ using “@sveltejs/kit”: “1.0.0-next.168”/ “@sveltejs/adapter-node”: “1.0.0-next.48”. It’s working correctly.

<anonymous>
https://localhost/@vite/client:186:16
InnerModuleEvaluation self-hosted:2381:31
InnerModuleEvaluation self-hosted:2381:31
InnerModuleEvaluation index.svelte:80:24
InnerModuleEvaluation index.svelte:124:13
evaluation self-hosted:2332:24 

Response for ws://localhost:3001/ using “@sveltejs/kit”: “1.0.0-next.170”/ “@sveltejs/adapter-node”: “1.0.0-next.49”. The browser reloading after this request.

<anonymous>
client.ts:28:15
InnerModuleEvaluation self-hosted:2381:31
InnerModuleEvaluation self-hosted:2381:31
InnerModuleEvaluation self-hosted:2381:31
InnerModuleEvaluation self-hosted:2381:31
evaluation self-hosted:2332:24 

The browser always reload after it try to access ws://localhost:3001/ using svelte.kt 169 or 170. Using 168 it don’t reload.

My frontend container is behind haproxy with self sign certificate. Only the port 3001 is open for vite without certificate.

I’m not accessing via SSH but via normal browser.

What was changed in Vite/Svelte from 168 to 169 version?

Thank you for the help.

Using Devilbox - Docker remote environment, it works with this simple config, running npm run dev -- --https --host 0.0.0.0 and going to https://app.loc:3000 instead of just https://app.loc (there I get a 403). Also for the generated cert from Vite for localhost an exception has to be allowed once.

/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		// hydrate the <div id="svelte"> element in src/app.html
		target: '#svelte',
		vite: {
			server: {
				host: '0.0.0.0'
			}
		}
	}
};

export default config;

What confused me was that SvelteKit did work just fine with HMR under https://app.loc/ without having a port number in the URL in the past. So a change in the way HRM is done must/could have been introduced in Vite or SvelteKit.

Being able to tell Vite to use the cert from https://app.loc instead of making a new one for localhost on start could possibly fix this issue. There is an option for vite.server.hmr.server where I assume this could be solved however the option does not seem to work with a self signed cert so far.

import { readFileSync } from 'fs';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		// hydrate the <div id="svelte"> element in src/app.html
		target: '#svelte',
		vite: {
			server: {
				host: '0.0.0.0'
			},
			hmr: {
				server: {
					https: {
						key: readFileSync('app.loc.key'),
						cert: readFileSync('app.loc.crt')
					}
				}
			}
		}
	}
};

export default config;

I’m having this issue using WSL2 and Nginx as a reverse proxy with https and custom domain (http://localhost:3000 -> https://svltkt.local).

Opening the ports and using --host as suggested above works for host IP but not custom domain added the C:\Windows\System32\drivers\etc\hosts. Any suggestions?

Ahh, finally. The endless reload has taken a break.

pnpm dev -- --open on @sveltejs/kit 1.0.0-next.301 and a svelte.config.js with:

	kit: {
		// hydrate the <div id="svelte"> element in src/app.html
		// target: '#svelte'
		vite: {
			server: {
				hmr: {
					port: 3000,
					clientPort: 3001
				}
			}
		}
	}

local: Windows 8.1 VS Code Remote client, remote: Slackware 15 (headless), Node 16 (Remote, as in 7000 Km 😄 )

I have been able to get rid of this issue and keep HMR when running through Docker Compose in WSL2 behind Traefik with the following setup:

docker-compose.dev.yml

...
services:
  ...
  client:
    build:
      context: "./client"
      target: dev
    container_name: client
    volumes:
      - "./client/src/:/usr/src/app/src/"
      - "/usr/src/app/node_modules"
    expose:
      - 3000
      - 24678
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.client.entrypoints=web"
      - "traefik.http.routers.client.rule=PathPrefix(`/`)"
      - "traefik.http.services.client.loadbalancer.server.port=3000"
    networks:
      - traefik-proxy

client/Dockerfile

FROM node:14.17.0-alpine AS base

WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . /usr/src/app
EXPOSE 3000
EXPOSE 24678

FROM base AS dev
ENV CHOKIDAR_USEPOLLING=true
CMD ["npm", "run", "dev"]

client/package.json

{
...
  "scripts": {
    ...
    "dev": "svelte-kit dev --host 0.0.0.0",
  },
  "devDependencies": {
    ...
    "@sveltejs/kit": "^1.0.0-next.195",
    "svelte": "^3.44.0",
  }
}

client/svelte.config.js

const config = {
  ...
  kit: {
    ...
    vite: {
      server: {
        watch: {
          usePolling: true
        },
        hmr: {
          protocol: 'ws',
          host: 'localhost',
          port: 80
        }
      }
    }
  }
}

The site is then available on http://localhost.

@YugoCode

server {
    listen 80;
    gzip on;

    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/index.html /200/index.html =404;
    }
}

I’m running nginx and the svelte app in Docker.

svelte config:

import preprocess from 'svelte-preprocess';
import adapter from '@sveltejs/adapter-static';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    preprocess: preprocess(),
    kit: {
        adapter: adapter(),
        ssr: false,
        target: '#svelte',
        vite: {
            server: {
                hmr: {
                    port: 80,
                    clientPort: 443
                }
            }
        }
    }
};

export default config;

Dockerfile for svelte app:

FROM node:16-alpine AS build

RUN mkdir -p /app

WORKDIR /app

COPY . .
RUN npm install

EXPOSE 80/tcp

CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "80"]

Container config (docker-compose):

  ui:
    container_name: ui
    image: ui-${UI_MODE}
    build:
      context: ../ui
      dockerfile: Dockerfile.${UI_MODE}
    restart: always
    volumes:
      - ../ui/src/:/app/src
      - ../ui/static:/app/static
      - ./configs/certs/mycert.pem:/certs/cert.pem
      - ./configs/certs/mycert-key.pem:/certs/key.pem
    tty: true

This was a bug I fixed (at least mostly) in Vite 2.9, so I’m not sure we necessarily need an FAQ as it wasn’t really user confusion, but a bug

Okay, finally I found the trick.

So I don’t even know how it works before version next 169… But if you use a reverse proxy and/or containers to run SvelteKit The ports it should be same (in my case at least) with the SvelteKit running port. In my case in the docker it’s run on the port 3000, and map to 3001 host port and i have a reverse proxy in front of it, and runs on port 80 and pass to 3001.

This config solved the problem for me. (http)

        vite: {
            server: {
                hmr: {
                    // Internal port (in container same as sveltekit port).
                    port: 3000,
                    // External port (Docker host)
                    clientPort: 3001
                }
            }
        },

Got the same error using traefik + https with mkcert.

After many tests and configurations, this solved the endless reload:

// "@sveltejs/adapter-node": "^1.0.0-next.51",
// "@sveltejs/kit": "^1.0.0-next.174",
// "svelte": "^3.43.0",
// svelte.config.js
      server: {
        hmr: {
          host: 'localhost',
          protocol: 'wss',
          port: 443
        }
      }

Ref.: https://github.com/vitejs/vite/issues/1653#issuecomment-816188959

Just to mention: I had the same problem with a custom domain. As soon as I tried to invoke the application with a custom domain, it started reloading the page every 2-5 seconds. HMR-port was open as stated above, no ports were blocked by some firewall, it even happened when I started it locally with pnpm dev (having the --host-switch as well).
What helped in my case was the plugin vite-plugin-host, which explicitly mentions to enable a custom domain in dev as well. Once imported and configured in the svelte.config.js, also the custom domain worked fine.

working example of nginx vhost via wsl2 image

@JBusillo I’m on 1.0.0-next.114. Still doesn’t work for custom domains (<http:https>://svltkt.local). <http:https>://localhost:3000 works as expected.

@GreenRobot777 – Are you opening up both your application port (default: 3000) and the websocket port (default 24678) on your remote server? This has been suggested as a “workaround” – which really is a misstatement. It’s absolutely necessary to manually open those ports, as the browser client (running on the local server) needs to connect to those ports to support HMR. SvelteKit can’t alter your system’s firewall settings. This necessity applies to Docker containers, too. I’ve tested it on my local and remote servers with the default HMR port (24678) and again with an override (3334).

// svelte.config.js to override the default HMR port from 24678 to 3334
/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		// hydrate the <div id="svelte"> element in src/app.html
		target: '#svelte',
		vite: {
			server: {
				hmr: {
					port: 3334,
				}
			}
		}
	}
};

export default config;

You also need to specify --host, otherwise it will only accept connections from your remote server’s localhost, not from your “external” local server.

For me, I changed svelte.config.js as described above, then executed commands 1 through 5 in your Reproduction instructions, then:

sudo ufw allow 3333          # My prod server already uses 3000 for another app, so I had to use another port
sudo ufw allow 3334          # Testing Vite's HMR port override feature.
npx svelte-kit dev --host --port 3333

If you just want to use the default ports, omit changing your svelte.config.js, and run:

sudo ufw allow 3000          
sudo ufw allow 24678
npx svelte-kit dev --host 

I hope I understood your issue correctly. Please let me know. If this does resolve your issue, it probably can be closed the remedy for this issue would be clarification in the documentation. (FAQ?)

Opening port 24678 on the server and forwarding it in VSCode resolved the issue for me and enabled auto-reload. I use it with remote development with VSCode in Docker containers.

You want to see something like this in the Chrome console:

client.ts:43 [vite] connecting...   
client.ts:43 [vite] connected.

This error in the console says there is something wrong with the Vite connection:

WebSocket connection to 'ws://localhost:24678/' failed:    

Some background information

SvelteKit uses Vite for its hot module reload (HMR) feature. This uses a WebSocket that uses a different port than the one opened with Sveltekit (default 24678, but it is configurable, but the configuration seems to not apply with SvelteKit). When you fire up SvelteKit using npm run dev it starts the server and creates a Vite WebSocket that listens to connections.

Related topics