Phoenix, AZ, USA
Follow us on
How to change the localhost port for the new Shopify Remix App template

How to change the localhost port for the new Shopify Remix App template

After scanning through the docs there is a simple parameter we can pass to set the port for use with localhost, which we use to run our own tunnel service (using Cloudflare, but with our own subdomain).

The main benefit for me is that the app urls won’t keep updating to new values every time we go to run the dev server. It was such a pain to update webhook endpoints after every time.

In shopify.web.toml we need to add port= parameter

shopify.web.toml
name = "remix"
roles = ["frontend", "backend"]
webhooks_path = "/webhooks"
port=8002 # add this param

[commands]
dev = "npm exec remix dev"

[hmr_server]
http_paths = ["/ping"]

Update!

After being annoyed by the wss:// connecting error in console, I did some more digging. The reason the app constantly hits the socket page is because of the LiveReload system. (Not HMR, it’s live reload). I found a few resources that brought up this issue so here is how I fixed it:

Create a LiveReload.tsx file in app/components:

app/components/LiveReload.tsx
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)})`,
            }}
          />
        );
      };

Then, in root.jsx make sure you remove the LiveReload import coming from @remix-run/react and import it from your component and add a port parameter, the same port listed in your shopify.web.toml, I believe the default is always 8002:

root.jsx
import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "@remix-run/react";
import { LiveReload } from "./components/LiveReload";

export default function App() {
  return (
    <html>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        <Outlet />
        <ScrollRestoration />
          <LiveReload port={8002} />
        <Scripts />
      </body>
    </html>
  );
}

I found out that when running over the tunnel, the dev server also pings the site at /ping on initial load, I found that we just need to make this route and we are good to go.

app/routes/ping.tsx
import { json } from "@remix-run/node";

export const action = async ({ request }) => {
  return json({success: true}, 200);
}

I also made sure to change the dev command in the package.json to contains the --tunnel-url= parameter:

package.json
    "dev": "shopify app dev --tunnel-url=https://{your-subdomain}.innovonics.com:80",

That’s it! You should have everything running through the tunnel and no socket errors! I have found that live reload still doesn’t work unfortunately, but at least the errors are gone.

*If you followed my previous instructions below, please remove them. You don’t need the socket.tsx

*** Do not do this! This is from my original testing and does not need to be done! ***

This isn’t all though, I found that I also had to add 2 new routes. I am not sure why but the Shopify app server was looking for it:

app/routes/socket.tsx
import { json } from "@remix-run/node";

export const loader = async ({ request }) => {
  return json({success: true}, 200);
};

The above runs through Cloudflare so I have a subdomain set up for app development.

Make sure your Cloudflare (or ngrok) tunnel is pointing to the port you set in the TOML and you should be able to build and receive requests.

1 drawback I found was that I am not getting constant GET requests at /socket route due to the hot module reloading (I assume). I don’t know how this looks in production yet.

doitalldev_
doitalldev_
Senior Software Engineer | Shopify Expert
Related Posts
2 Comments
Braden

This is literally the only thing that worked to solve my wss:// issue on my AWS instance.
Everything worked great locally, even in docker, but I have no end of issues on AWS.

Anyway, thank you!

BradByte

This was a life saver! Thank you.

Leave a Reply

Your email address will not be published.Required fields are marked *