dockerTools.buildImage minimal static site

buildImage is building all the dependencies for the static site into the image. The result of building the static site is a small self contained directory of html, js, and css. In the final output there are no references to anything. Given the nix expr below it produces a large 400MB image.

How can I just get the resulting static files from the “site” derivation below into the image, and not any dependencies used for building it?

{pkgs ? import <nixpkgs> {}}:

let
  site = pkgs.mkYarnPackage {
    name = "foo";
    src = ./.;
    packageJSON = ./package.json;
    yarnLock = ./yarn.lock;
    yarnNix = ./yarn.nix;
    buildPhase = "yarn run build";
    installPhase = "mkdir -p $out/public/assets; mv deps/foo/build/* $out/public/";
    distPhase = "true";
  };

  staticServerImage = pkgs.dockerTools.buildImage {
    name = "foo";
    contents = [site];
  };

in {
  inherit site staticServerImage;
}

You want to build a docker image with just html, js, and css, but no software to serve them?

You could copy all relevant files of site into a new derivation and leave all dependencies behind:

...
  site-files = runCommand "site-files" {} ''
    mkdir $out
    cp ${site}/static/files $out/files
  ''

… and then reference site-files when building the docker image.

BTW, using buildLayeredImage instead of buildImage resulted in smaller images for me.

I actually have a static binary that I use to serve the files. That doesn’t seem to be the problem as it is only 5MB and building an image with that only builds an image of 5MB. The above example was to demonstrate the minimal example.

A more complete example (including the suggestion of an intermediate derivation)

{pkgs ? import <nixpkgs> {}}:

let

  staticServer = pkgs.stdenv.mkDerivation rec {
    name = "static-web-server";
    version = "1.11.0";
    src = builtins.fetchurl {
      url = "https://github.com/joseluisq/static-web-server/releases/download/v${version}/static-web-server-v${version}-x86_64-unknown-linux-musl.tar.gz";
      sha256 = "1y6c2k30w47aazv2rwcqrvpz2wx0wr5v9zp3fmaca8gjbxw0qg8c";
    };
    unpackPhase = "tar xf $src";
    installPhase = "mkdir -p $out/bin; cp static-web-server $out/bin";

  };

  site-files = pkgs.runCommand "site-files" {} ''
    mkdir $out
    cp -R ${site}/public $out/public
  '';

  staticServerImage = pkgs.dockerTools.buildLayeredImage {
    name = "foo";
    config = {
      cmd = ["${staticServer}/bin/static-web-server" "--root" "${site-files}/public" "--assets" "${site-files}/public/assets"];
    };
  };

  site = pkgs.mkYarnPackage {
    name = "foo";
    src = ./.;
    packageJSON = ./package.json;
    yarnLock = ./yarn.lock;
    yarnNix = ./yarn.nix;
    buildPhase = "yarn run build";
    installPhase = "mkdir -p $out/public/assets; mv deps/foo/build/* $out/public/";
    distPhase = "true";
  };

  shell = pkgs.mkShell {
    inputsFrom = [site];
  };

in {
  inherit site shell staticServer staticServerImage;

}

It doesn’t make a difference if I reference the “site”, or “static-site”, or if I simply include them in contents. All variations seem to include dependencies for building the site.