How to package static single page nodejs webapp? (Ollama-WebUI)

I would like to package a web frontend Ollama-WebUI for Large Language Model (LLM) execution backend Ollama to make it easy for people to run Open-Source ChatGPT alternatives locally. However, i’m struggling to to include a webserver as the underlying binary to serve the web app (which compiles into a static page).
Using writeShellApplication works, but i can’t set the version attribute.

let
  # ollama-webui doesn't tag versions.
  # version = "0.0.1";
  version = "0820d846190569334151d2970169f77240a0916d";
  # we just package the JS frontend part, not the Python reverse-proxy backend
  # for simplicity.
  ollama-webui-frontend-static-page = buildNpmPackage rec {
    pname = "ollama-webui-static-page";
    inherit version;

    src = fetchFromGitHub {
      owner = "ollama-webui";
      repo = "ollama-webui";
      rev = version;
      hash = "sha256-3Lf7v5tEVrhHrEcpdJYV8EmoDSeHKVenLbtMyWUmjVU=";
    };
    npmDepsHash = "sha256-N+wyvyKqsDfUqv3TQbxjuf8DF0uEJ7OBrwdCnX+IMZ4=";

    # "npm run build" creates a static page in the "build" folder.
    installPhase = ''
      cp -R ./build $out
    '';

  };
in writeShellApplication {
  name = "ollama-webui";
  # inherit version;
  runtimeInputs = [ nodePackages.http-server ];

  text = ''
    ${nodePackages.http-server}/bin/http-server ${ollama-webui-frontend-static-page}
  '';
}

Full nixpkgs MR.

What is a better alternative? I tried symlinkJoin with wrapProgram but didn’t get it to run, and i think i’m also not able to specify the version attribute.

You could do something like this:

let
  script = ''
    #!${pkgs.runtimeShell}
    ${nodePackages.http-server}/bin/http-server $out/lib
  '';
in buildNpmPackage rec {
    pname = "ollama-webui-static-page";
    inherit version;

    src = fetchFromGitHub {
      owner = "ollama-webui";
      repo = "ollama-webui";
      rev = version;
      hash = "sha256-3Lf7v5tEVrhHrEcpdJYV8EmoDSeHKVenLbtMyWUmjVU=";
    };
    npmDepsHash = "sha256-N+wyvyKqsDfUqv3TQbxjuf8DF0uEJ7OBrwdCnX+IMZ4=";

    # "npm run build" creates a static page in the "build" folder.
    installPhase = ''
      cp -R ./build $out/lib
      echo '${script}' > $out/bin/start-ollama
      chmod +x $out/bin/start-ollama
    '';
}

More pseudocode than anything else (I imagine interpolated newlines won’t work properly), but you get the idea.

While I’m at it, instead of using let to define everything, use the fixed-point feature instead; doing it your way makes overrides impossible.

Alternatively, write a module instead, and serve it with an nginx virtualHost.

@TLATER Thanks, that looks exactly like what i was looking for; i forgot that you can create and bundle scripts right into any package. I’ll try it out. The fixed-point setup i can’t quite wrap my head around from the documentation though; i’ll dig into that later.