Patrick Desjardins Blog
Patrick Desjardins picture from a conference

How to have ViteJS (via SolidJS) to Hot Reload when inside a Docker Container

Posted on: 2022-08-09

Suppose you are using ViteJS to automate your TypeScript, JSX, and CSS, then you will need to adjust the ViteJS configuration to use the hot-reload mechanism still. Likewise, you will need to perform these steps using SolidJS instead of CRA since SolidJS relies on ViteJS.

My current example works if you use a Docker container for your web application that mounts its file on your development machine. The solution is neat as it allows you to isolate the web server that ViteJS starts in development inside a Docker container and still leverage a fast development experience with your TypeScript, CSS, and HTML file on your machine. If you are unsure what I am describing, I suggest reading this previous article about how to configure Docker with two containers: frontend and backend.

ViteJS Configuration File

Most of the heavy work is done by modifying the ViteJS configuration file vite.config.ts, which should be at the root of your frontend project. If the file is not present, it is time to create it.

I have removed in the following code a lot of SolidJS configurations as well as other needed configurations. The goal is to highlight the vital part of having ViteJS accessible outside your container but mainly to keep the capability of modifying a .tsx file and seeing the change within a few milliseconds occurring on the browser.

export default (conf: any) => {
  return defineConfig({
    server: {
      host: "0.0.0.0",
      hmr: {
        clientPort: ENV_VARIABLES.OUTER_PORT_FRONTEND,
      },
      port: ENV_VARIABLES.INNER_PORT_FRONTEND_DEV, 
      watch: {
        usePolling: true,
      },
    },
  });
};

The first part is under server is the host. It needs to be 0.0.0.0 to make every IP accessible. A value of localhost or 127.0.0.1 is not enough when you are inside a Docker container.

The second part is the ports. The first port is under hmr, which stands for "hot module reload". The clientPort must be set to the port your Docker container exposes. My Docker-compose.yaml has for the frontend server that configuration:

ports:
      - "${OUTER_PORT_FRONTEND}:${INNER_PORT_FRONTEND}"

Which take the OUTER_PORT_FRONTEND to an INNER_PORT_FRONTEND. So, if you are exposing outside port 80 but that inside your are running on port 3000 it means that the hmr must be the 80 value. That is the value that the browser will use to access the website.

The third part is the port of the internal ViteJS server. The value you see of INNER_PORT_FRONTEND_DEV is the default 3000 port for a SolidJS application.

At this point, the configuration should work, and you should see your web application if you go on port 80, but a change does not reload the site. I notice that even a refresh of the browser is not performing any changes but that if I connect to the container, the JavaScript is generated. So, TypeScript is being transpiled, but for some reason, something blocks. The secret is to enable the polling.

watch: {
  usePolling: true,
},

Conclusion

The path to success with Docker, ViteJS, SolidJS, and all other abstractions is paved with holes. For example, it is not apparent why the polling is required to have new changes through Docker. However, it works, and I hope it helps with your configuration.