nixpkgs/pkgs/by-name/de/devmode/package.nix
Valentin Gagarin 50ff833cd8 devmode: move to pkgs/by-name
now one can use `devmode` from anywhere Nixpkgs is available:

    devmode = pkgs.devmode.override {
      buildArgs = toString ./.;
      open = "/index.html";
    };
2024-11-12 10:16:58 +01:00

123 lines
2.9 KiB
Nix

{
lib,
findutils,
nodejs_latest,
parallel,
rsync,
watchexec,
writeShellScriptBin,
# arguments to `nix-build`, e.g. `"foo.nix -A bar"`
buildArgs ? "",
# what path to open a browser at
open ? "/index.html",
}:
let
inherit (nodejs_latest.pkgs) live-server;
error-page = writeShellScriptBin "error-page" ''
cat << EOF
<!DOCTYPE html>
<html>
<head>
<style>
@media (prefers-color-scheme: dark) {
:root { filter: invert(100%); }
}
</style>
</head>
<body><pre>$1</pre></body>
</html>
EOF
'';
# The following would have been simpler:
# 1. serve from `$serve`
# 2. pass each build a `--out-link $serve/result`
# But that way live-server does not seem to detect changes and therefore no
# auto-reloads occur.
# Instead, we copy the contents of each build to the `$serve` directory.
# Using rsync here, instead of `cp`, to get as close to an atomic
# directory copy operation as possible. `--delay-updates` should
# also go towards that.
build-and-copy = writeShellScriptBin "build-and-copy" ''
set -euxo pipefail
set +e
stderr=$(2>&1 nix-build --out-link $out_link ${buildArgs})
exit_status=$?
set -e
if [ $exit_status -eq 0 ];
then
# setting permissions to be able to clean up
${lib.getExe rsync} \
--recursive \
--chmod=u=rwX \
--delete-before \
--delay-updates \
$out_link/ \
$serve/
else
set +x
${lib.getExe error-page} "$stderr" > $error_page_absolute
set -x
${lib.getExe findutils} $serve \
-type f \
! -name $error_page_relative \
-delete
fi
'';
# https://watchexec.github.io/
watcher = writeShellScriptBin "watcher" ''
set -euxo pipefail
${lib.getExe watchexec} \
--shell=none \
--restart \
--print-events \
${lib.getExe build-and-copy}
'';
# A Rust alternative to live-server exists, but it fails to open the temporary directory.
# `--no-css-inject`: without this it seems that only CSS is auto-reloaded.
# https://www.npmjs.com/package/live-server
server = writeShellScriptBin "server" ''
set -euxo pipefail
${lib.getExe' live-server "live-server"} \
--host=127.0.0.1 \
--verbose \
--no-css-inject \
--entry-file=$error_page_relative \
--open=${open} \
$serve
'';
in
writeShellScriptBin "devmode" ''
set -euxo pipefail
function handle_exit {
rm -rf "$tmpdir"
}
tmpdir=$(mktemp -d)
trap handle_exit EXIT
export out_link="$tmpdir/result"
export serve="$tmpdir/serve"
mkdir $serve
export error_page_relative=error.html
export error_page_absolute=$serve/$error_page_relative
${lib.getExe error-page} "building " > $error_page_absolute
${lib.getExe parallel} \
--will-cite \
--line-buffer \
--tagstr '{/}' \
::: \
"${lib.getExe watcher}" \
"${lib.getExe server}"
''