django-elm icon indicating copy to clipboard operation
django-elm copied to clipboard

Implement elm-hot for HMR

Open Confidenceman02 opened this issue 2 years ago • 1 comments

I'm not sure if this is even possible but it would be sick to not need to rely on browser reload to reload the entire page every time there is a change. In fact if we could tell Django to not even look inside the app static files after initial load. Perhaps there is some sort of middleware hook we can give the django file watcher.

We could set up an endpoint (much like browser reload) and send server events to the client to fetch the new assets as string the eval it in the client.

Resources: elm-hot

Confidenceman02 avatar Jan 05 '24 00:01 Confidenceman02

Pretty pumped to start work on this.

Here's a very shitty implementation idea:

import defo from "@icelab/defo";

const views = {
    djelmDropzone: async (el: HTMLElement, data: any) => {
        let currentApp;

        // Load and initialize the Elm program
        const loadElm = async () => {
            //@ts-ignore
            const { Elm } = await import("../../../src/DropZone.elm");
            currentApp = Elm.DropZone.init({
                node: el,
                flags: data,
            });
        };

        await loadElm();

        return {
            update: (newData, oldData) => {
                // Update flags if the data changes
                if (JSON.stringify(newData) !== JSON.stringify(oldData)) {
                    data = newData;
                    currentApp.ports?.updateFlags?.send(newData); // Optional: if you add a port
                }
            },
            destroy: () => {
                currentApp = null; // Cleanup
            },
            // New method for hot reloading
            hotReload: async () => {
                if (currentApp) {
                    // Destroy the old instance
                    currentApp = null;
                    // Reload the updated module
                    await loadElm();
                }
            },
        };
    },
};

const instance = defo({ views, prefix: "elmprogramsdropzone" });

// WebSocket listener for hot reloads (example)
const ws = new WebSocket("ws://localhost:3000");
ws.onmessage = (event) => {
    const { program } = JSON.parse(event.data);
    if (program === "DropZone") {
        instance.views.djelmDropzone.hotReload();
    }
};

Because djelm controls the generation of this entrypoint file it's very easy to add the websocket code.

When djelm is run with watch --hot it could spin up the websocket server at the same time and also generate the ws code in the entrypoint.

The really nice thing is djelm has access to the running elm programs init model, so its easy to instantiate it when programs change, no refresh required. However, the trick will be to get access to the internal model so that it can persist between refreshes.

This current implementation solves the refresh issue, but not the preserved model issue. It's a start though.

Confidenceman02 avatar Apr 02 '25 02:04 Confidenceman02