1{
2 live-server,
3 parallel,
4 watchexec,
5 writeShellApplication,
6 # arguments to `nix-build`, e.g. `"foo.nix -A bar"`
7 buildArgs ? "",
8 # what path to open a browser at
9 open ? "/index.html",
10}:
11let
12 error-page = writeShellApplication {
13 name = "error-page";
14 text = ''
15 rm -rf "''${serve:?}"
16 mkdir -p "$(dirname "''${error_page_absolute:?}")"
17
18 cat > "''${error_page_absolute:?}" << EOF
19 <!DOCTYPE html>
20 <html>
21 <head>
22 <style>
23 @media (prefers-color-scheme: dark) {
24 :root { filter: invert(100%); }
25 }
26 </style>
27 </head>
28 <body/><pre/>building...
29 EOF
30 '';
31 };
32
33 build-and-link = writeShellApplication {
34 name = "build-and-link";
35 runtimeInputs = [ error-page ];
36 text = ''
37 error-page
38
39 set +e
40 2>&1 nix-build --out-link "''${staging:?}" ${buildArgs} \
41 | tee -a "''${error_page_absolute:?}"
42 exit_status=$?
43 set -e
44
45 if [ $exit_status -eq 0 ]; then
46 rm -rf "''${serve:?}"
47 mv "''${staging:?}" "''${serve:?}"
48 fi
49 '';
50 };
51
52 # https://watchexec.github.io/
53 watcher = writeShellApplication {
54 name = "watcher";
55 runtimeInputs = [
56 watchexec
57 build-and-link
58 ];
59 text = ''
60 watchexec \
61 --shell=none \
62 --restart \
63 build-and-link
64 '';
65 };
66
67 # https://crates.io/crates/live-server
68 server = writeShellApplication {
69 name = "server";
70 runtimeInputs = [ live-server ];
71 text = ''
72 live-server \
73 --host=127.0.0.1 \
74 --open=${open} \
75 "''${serve:?}"
76 '';
77 };
78in
79writeShellApplication {
80 name = "devmode";
81 runtimeInputs = [
82 parallel
83 watcher
84 server
85 error-page
86 ];
87 text = ''
88 function handle_exit {
89 rm -rf "$tmpdir"
90 }
91
92 tmpdir="$(mktemp -d)"
93 trap handle_exit EXIT
94
95 export serve="$tmpdir/serve"
96 export staging="$tmpdir/staging"
97 export error_page_absolute="$serve/${open}"
98
99 error-page
100
101 parallel \
102 --will-cite \
103 --line-buffer \
104 --tagstr '{/}' \
105 ::: \
106 watcher \
107 server
108 '';
109}