remix: [Bug]: Live Reload not working.

Which Remix packages are impacted?

  • remix (Remix core)
  • @remix-run/react
  • @remix-run/serve

What version of Remix are you using?

1.1.3

What version of Node are you using? Minimum supported version is 14.

14.17.4

Steps to Reproduce

  1. starting from the Quickstart template.
  2. create a posts route.
  3. navigate to route
  4. the route does not show up

Every step along the way I have to restart the dev server to see the changes in the web. For example I added


export default function Posts() {
    const posts = useLoaderData();
    console.log('test3');
    return (
        <div>
            <h1>Posts</h1>
        </div>
    );
}

and the console still shows that it reloaded but still shows test2 (the value from when the dev server started)

Navigated to http://10.202.57.104:3000/posts index.tsx:18 test2 posts:23 šŸ’æ File changed: app\routes\posts\index.tsx posts:23 šŸ’æ Rebuilding… posts:23 šŸ’æ Rebuilt in 201ms posts:26 šŸ’æ Reloading window … Navigated to http://10.202.57.104:3000/posts index.tsx:18 test2

I’m on Windows using Chrome(97.0.4692.71) and Edge(Version 97.0.1072.62), both failed

Expected Behavior

the hot reload should show the changes without having to restart

Actual Behavior

I have to stop the dev server and restart to see any changes

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 56
  • Comments: 102 (17 by maintainers)

Commits related to this issue

Most upvoted comments

I’m also using Windows and I realized hot-reloads only work when I make changes inside the app directory of my Remix project. I don’t know if this is how it is supposed to work or it’s a bug!

<LiveReload/> is a simple component. You can simply inline it in your root route.

export const LiveReload =
  process.env.NODE_ENV !== "development"
    ? () => null
    : function LiveReload({
        port = Number(process.env.REMIX_DEV_SERVER_WS_PORT || 8002),
      }: {
        port?: number;
      }) {
        let setupLiveReload = ((port: number) => {
          let protocol = location.protocol === "https:" ? "wss:" : "ws:";
          let host = location.hostname;
          let socketPath = `${protocol}//${host}:${port}/socket`;

          let ws = new WebSocket(socketPath);
          ws.onmessage = (message) => {
            let event = JSON.parse(message.data);
            if (event.type === "LOG") {
              console.log(event.message);
            }
            if (event.type === "RELOAD") {
              console.log("šŸ’æ Reloading window ...");
              window.location.reload();
            }
          };
          ws.onerror = (error) => {
            console.log("Remix dev asset server web socket error:");
            console.error(error);
          };
        }).toString();

        return (
          <script
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: `(${setupLiveReload})(${JSON.stringify(port)})`,
            }}
          />
        );
      };

Had the same issue. Fixed by changing remix.confix.js from:

module.exports = {
  ignoredRouteFiles: [".*"],
};

to:

module.exports = {
  cacheDirectory: "./node_modules/.cache/remix",
  ignoredRouteFiles: [".*", "**/*.css", "**/*.test.{js,jsx,ts,tsx}"],
};

same problem here on Windows and create-remix, I’m trying to follow the QuickStart tutorial but it doesn’t reload 😢

I still have not found a solution other than it the hot-reloading it working on my Linux machine but refuses to work on Windows.

This is the most basic feature a frontend dev framework should have; it’s not working in Nov/2023 so I’ll report to my team Remix is not worth considering yet šŸ˜‡

The official remix tutorial runs straight into this problem. Not a good first experience with the framework

<LiveReload/> is a simple component. You can simply inline it in your root route.

export const LiveReload =
  process.env.NODE_ENV !== "development"
    ? () => null
    : function LiveReload({
        port = Number(process.env.REMIX_DEV_SERVER_WS_PORT || 8002),
      }: {
        port?: number;
      }) {
        let setupLiveReload = ((port: number) => {
          let protocol = location.protocol === "https:" ? "wss:" : "ws:";
          let host = location.hostname;
          let socketPath = `${protocol}//${host}:${port}/socket`;

          let ws = new WebSocket(socketPath);
          ws.onmessage = (message) => {
            let event = JSON.parse(message.data);
            if (event.type === "LOG") {
              console.log(event.message);
            }
            if (event.type === "RELOAD") {
              console.log("šŸ’æ Reloading window ...");
              window.location.reload();
            }
          };
          ws.onerror = (error) => {
            console.log("Remix dev asset server web socket error:");
            console.error(error);
          };
        }).toString();

        return (
          <script
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: `(${setupLiveReload})(${JSON.stringify(port)})`,
            }}
          />
        );
      };

This is the only solution that worked for me

I don’t mean to +1, but I’m also getting the issue on mac, with a fresh vercel/ts boilerplate.

So the simple straightforward answer is:

In remix.config.js, add: devServerPort: 8002, Just that should fix the Live Reload, with its default port.

And when you’d want to change that default port, also add this change to the LiveReload component in root.tsx: <LiveReload port={8082}/>

This is the most basic feature a frontend dev framework should have; it’s not working in Nov/2023 so I’ll report to my team Remix is not worth considering yet šŸ˜‡

It is working, but we have to improve the documentation because it’d work properly if you keep your code inside the /app directory.

In my case I have all my components inside the ./app folder. But hot-reload is still not work. I am on MacOS

I’m also using Windows and I realized hot-reloads only work when I make changes inside the app directory of my Remix project. I don’t know if this is how it is supposed to work or it’s a bug!

Interesting observation. I was struggling with this and your point made me realize I currently have all my components in a components/ folder outside of my app/ directory. I just did a brief experiment and moving a component into the app/ directory seems to fix it — i.e. causes changes to reflect on the hot reload live.

As a possible feature, could we provide paths to whatever is watching the filesystem for hot reload?

There seem to be multiple different issues people are running into.

Named exports

Named exports are required for HMR. Note that this is a limitation of React Fast Refresh, not Remix. Thus the same limitation is present in Vite and Next.

Code outside of app/ dir

Expecting changes outside of app/ to trigger hot updates. As already mentioned, you can add those paths to watchPaths, but we’d recommend keeping all your app code within app/ anyway.

LiveReload before Scripts (Vite)

This limitation has been removed from unstable Vite support. The order of LiveReload and Scripts no longer matters.

Quickstart/Tutorial not working

@BoilingSoup I couldn’t reproduce this error, but if you are still running into it could you file a separate issue?


This issue was already too broad when it was first created, so moving forward please file separate issues with your specific problem so that we can make sure we prioritize a fix.

I was having the same issue with the blues stack, I started with the template that had LiveReload after Scripts. I changed the order now where LiveReload comes first, and now it is fixed. This is important if you are using vitest. Source: https://remix.run/docs/en/main/future/vite#livereload-before-scripts

From root.tsx:

      <body className="h-full">
          <Outlet />
          <ScrollRestoration />
          <LiveReload /> //comes before <Scripts/>
          <Scripts />
      </body>

LiveReload is still not working in version 1.13. If you include the <Scripts/> import from ā€œ@remix-run/reactā€, then it works.

Had the same issue. Fixed by changing remix.confix.js from:

module.exports = {
  ignoredRouteFiles: [".*"],
};

to:

module.exports = {
  cacheDirectory: "./node_modules/.cache/remix",
  ignoredRouteFiles: [".*", "**/*.css", "**/*.test.{js,jsx,ts,tsx}"],
};

This worked for me! Thanks @nilobarp After a server restart that reload was hot hot hot šŸ”„

to clarify the workaround that some other people have suggested, the Remix project needs to be installed in the WSL only portion of the WSL filesystem. it may look like /mnt/c/Users/[username]/projects/my-remix-app is in the WSL filesystem but since it’s an abstraction of the Windows filesystem it will not work. however, it should work fine if you set up the project in /home/[username]/my-remix-app for example. the reason this works is the WSL filesystem is able to detect file changes in its own virtualized environment but not in its abstraction of the Windows filesystem

this workaround requires setting up your code editor to point to the WSL files which isn’t an option for everyone, so I support an option for polling to be added as a short term solution while WSL itself gets the bug fixed

Same issue on MacOS. Nothing makes it work for me, even if i remove the process.env.NODE_ENV check around <LiveReload/>

I have reproduced the issue on 1.1.3 1.1.2 and 1.1.1 so downgrading does not appear to help.

I am using arc sandbox - so this may be affecting it.

Its dropped the Remix DX from a 10/10 down to a 1/10. I’ve had to put my project on hold until this is fixed. 😦

All my components are inside the app directory

@BoilingSoup I couldn’t reproduce this error, but if you are still running into it could you file a separate issue?

https://github.com/remix-run/remix/issues/7466

It is here.

I fix this by adding the components directory that I have outside of the app directory in the watchPaths array, my remix.conf.js file looks like this:

/** @type {import('@remix-run/dev').AppConfig} */
export default {
  ignoredRouteFiles: ["**/.*"],
  watchPaths: ["./components"],
  // appDirectory: "app",
  // assetsBuildDirectory: "public/build",
  // publicPath: "/build/",
  // serverBuildPath: "build/index.js",
};

Live reload does not seem to work for the socket.io example.

Setting devServerPort doesn’t appear to make a difference in this case.

remix watch is seeing the file changes and rebuilding, and there is a websocket open on 8002. No errors in the browser console, and on initial page load we have successful connection to the websocket at 8002, but no network activity happens in response to the change, and reload requires manually refreshing the page.

Netlify Starter is not hot/live reloading.

The OS doesn’t matter. I tried in both macOS and Windows10. It doesn’t show any errors on the terminal. The changes on files don’t make the browser reload.

Hot reload doesn’t work for me on create-remix@1.3.3 with the starter templates. I’m on Windows with WSL2.

I dug a little deeper and found the root cause here: https://github.com/microsoft/WSL/issues/4739

This issue comes up across many tools, and the workaround is often to switch to polling.

Maybe remix should also offer a polling option?

Hey, @pcattori, I have tried Vite, and the issue no longer exists. Now I am curious, when will Vite be stable and ready for production? šŸ¤”

https://twitter.com/markdalgleish/status/1736240852308251053

https://github.com/remix-run/remix/pull/8266

@LukeXF Are you on Mac or Windows?

Did you add/change devServerPort in remix.config?

Also check to see if REMIX_DEV_SERVER_WS_PORT environment variable is defined.

Worst case, just update your dev script to:

"cross-env NODE_ENV=development PORT=3000 REMIX_DEV_SERVER_WS_PORT=8002 remix dev"

Also, try to connect to the web socket server using your browser: http://localhost:8002

You should see the message ā€œUpgrade Requiredā€

@LukeXF Are you on Mac or Windows?

Did you add/change devServerPort in remix.config?

Also check to see if REMIX_DEV_SERVER_WS_PORT environment variable is defined.

Worst case, just update your dev script to:

"cross-env NODE_ENV=development PORT=3000 REMIX_DEV_SERVER_WS_PORT=8002 remix dev"

Also, try to connect to the web socket server using your browser: http://localhost:8002

You should see the message ā€œUpgrade Requiredā€

this helped!!! thanks so much šŸ˜„

Apologies, yes 1.12. I had NextJS 13 in my head as I’m trying different SSR frameworks out!. Yes, 1.12, but the rest of what I stated still stands.

Should be fixed by #5339

Apologies, yes 1.12. I had NextJS 13 in my head as I’m trying different SSR frameworks out!. Yes, 1.12, but the rest of what I stated still stands.

My apologies.

@Ali-Parandeh You already mentioned that, I’m not sure repeating it is helpful 😃

In case it helps others, I tried a bunch of the stuff above before realising that Remix does ā€œlive reloadsā€ and not ā€œhot module replacementā€ aka HMR.

So live reloads were actually working (e.g. page was reloaded on changes automatically), but I was assuming that it should be doing HMR (e.g. changes updated in place without reloading the entire page). This is not the case.

There’s a good discussion here (https://github.com/remix-run/remix/discussions/2384) about HMR support, which will hopefully land eventually, although I appreciate the reasoning behind leaving it out currently.

What fixed the issue for me was setting an explicit port prop on LiveReload:

import { LiveReload } from '@remix-run/react'

export default function App() {
  return (
    <html>
      <body><LiveReload port={8002} /></body>
    </html>
  )
}

It will stop attempting to look up the default value from the process then.

Managed to fix this: Because the live reload is just a WebSocket, it wasn’t by default published in Docker So I provided a fixed port in remix.config.js:

  devServerPort: 3001,

And published the port in my docker-compose.yml:

    ports:
      - "3001:3001"

Hope this helps someone

I just updated to 1.5.1 and still am experiencing this issue. Am I the only one? I tried to play with the port (3000, 3001… instead of the deafault 8002), but nothing works.

EDIT: I just ran the jokes app and it works there. I’ll investigate what in the Blues Stack is messing with the LiveReload.

EDIT2: I just ran a fresh Blues Stack and it does indeed fails to connect to the websocket. I guess I’ll migrate my code to a simple create-remix template.

EDIT3: Moving my code to a fresh simple create-remix template (Remix App Server) did the work! Hot reload is back baby šŸš€

WebSocket connection to 'ws://localhost:3001/socket' failed:

Remix dev asset server web socket error:

Event
 isTrusted: true
 bubbles: false
 cancelBubble: false
 cancelable: false
 composed: false
 currentTarget: WebSocket {url: 'ws://localhost:3001/socket', readyState: 3, bufferedAmount: 0, onopen: null, onerror: ʒ, …}
 defaultPrevented: false
 eventPhase: 0
 path: []
 returnValue: true
 srcElement: WebSocket {url: 'ws://localhost:3001/socket', readyState: 3, 
 bufferedAmount: 0, onopen: null, onerror: ʒ, …}
 target: WebSocket {url: 'ws://localhost:3001/socket', readyState: 3, bufferedAmount: 0, onopen: null, onerror: ʒ, …}
 timeStamp: 2514.599999964237
 type: "error"

@LukeXF Are you on Mac or Windows?

Did you add/change devServerPort in remix.config?

Also check to see if REMIX_DEV_SERVER_WS_PORT environment variable is defined.

Worst case, just update your dev script to:

"cross-env NODE_ENV=development PORT=3000 REMIX_DEV_SERVER_WS_PORT=8002 remix dev"

Also, try to connect to the web socket server using your browser: http://localhost:8002

You should see the message ā€œUpgrade Requiredā€

I believe there was a bug in the dev tool in that it wasn’t passing the REMIX_DEV_SERVER_WS_PORT variable to the compiler. Have you tried the latest version? Remix now gets a random unused port for the WS port.

@nilobarp That’s already in my remix.config.js. Why would it matter either way? My best guess is these ā€œsolutionsā€ are all part of an elaborate April fools prank. 😁

Thx.

FIY everybody, if you move to Remix Stack (Blues) there is no issue with hot reloading in WSL2. It is using pm2 server internally for that, AFAIK. That’s what I did.

@Tymek the warning is unrelated, check #1077