| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 1 | [container] |
| 2 | name = "frq-flutter-web" |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 3 | description = "the Flutter web build, incremental, from a pinned toolchain" |
| 4 | # `debian:13-slim` and not `arch-nix`: there is no nix in this container any |
| 5 | # more. The build is `tools/build-web.sh`, which fetches its own Flutter, JDK |
| 6 | # and Clojure CLI by pinned sha256, so what the image owes it is curl, git, |
| 7 | # tar and a C runtime — and the smallest image that has them is the right one. |
| 8 | registry = "debian:13-slim" |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 9 | # A Sandbox, not a Function: it runs on a real VM, the command is the |
| 10 | # sandbox's own process so it dies when the command does, and only a Sandbox |
| 11 | # can hold open a tunnel -- which is the whole of `serve`. |
| 12 | runtime = "sandbox" |
| 13 | |
| 14 | [build] |
| 15 | # The container lives inside the repo it builds, so the copy is rooted two |
| 16 | # levels up and `.` is the whole tree. |
| 17 | context = "../.." |
| 18 | include = ["."] |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 19 | # The whole image build, and it is one apt line. What used to be here -- a |
| 20 | # nix store to populate, a devShell to print, a closure to warm before the |
| 21 | # source arrived so an edit would not invalidate it -- is gone with the nix |
| 22 | # it was for. There is no `warm` list any more either: this step reads |
| 23 | # nothing out of the tree, so nothing in the tree can invalidate it. |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 24 | # |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 25 | # git, because Flutter shells out to it against its own SDK checkout and |
| 26 | # refuses to run without one; unzip and xz-utils, because that is what the |
| 27 | # SDK and the toolchain tarballs arrive as; rsync for the sync below; |
| 28 | # ca-certificates so curl can verify what it fetches. |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 29 | setup = [ |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 30 | "apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git rsync tar unzip xz-utils && rm -rf /var/lib/apt/lists/*", |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 31 | ] |
| 32 | # The build state a local checkout carries, wanted by nothing out here: this |
| One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago | 33 | # container builds into a volume of its own, and the clojure caches |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 34 | # are the laptop's. |
| 35 | ignore = [ |
| 36 | "flutter/build", "flutter/.home", "flutter/.dart_tool", |
| 37 | "flutter/.clojuredart", "flutter/.cpcache", |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 38 | # The ClojureDart compiler's output, gitignored and -- until now -- |
| 39 | # uploaded anyway, because this list is explicit and does not read |
| 40 | # .gitignore. It is megabytes of generated Dart per run, and worse than |
| 41 | # the upload is what happened on arrival: the rsync below overwrote the |
| 42 | # volume's copy, the one the last container compiled, with a laptop's. |
| 43 | # Every file whose content differed then looked new to the compiler and |
| 44 | # to Flutter, which is the incremental build undone by the thing that was |
| 45 | # meant to feed it. It belongs to the volume, like flutter/build. |
| 46 | "flutter/lib/cljd-out", |
| 47 | # The toolchain, which is a gigabyte of Flutter SDK and lives on the |
| 48 | # volume out here. |
| 49 | ".toolchain", |
| One frontend where there were three, and a core that is not Clojure 438b247 nandi 21h ago | 50 | ".cpcache", "result", "build", ".git", |
| Pictures a browser will accept, through the one origin that vouches for them 1a1f153 nandi 2d ago | 51 | # An editor's linter rewrites this while the upload is reading it, and |
| 52 | # Modal fails the whole run with "was modified during build process". |
| 53 | # Nothing out here reads it. |
| 54 | ".clj-kondo", |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 55 | ] |
| 56 | |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 57 | # One volume now, where there were two: the nix binary cache went with nix. |
| 58 | # `devshell` is the working state of an incremental loop, shared by every |
| 59 | # container that has one -- each gets its own directory under it, named for |
| 60 | # what it belongs to, so `flutter-web` and `flutter-desktop` never write the |
| 61 | # same tree. Modal Volumes have no locking, so those directory names are the |
| 62 | # only thing keeping them apart, and two runs of the *same* container must |
| 63 | # not overlap. |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 64 | [volumes] |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 65 | devshell = "/devshell" |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 66 | |
| 67 | [resources] |
| 68 | cpu = 8 |
| 69 | memory = 16384 |
| 70 | timeout = 3600 |
| 71 | |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 72 | # The port `tools/build-web.sh serve` listens on, tunnelled out. Nothing is |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 73 | # served unless the command asks for it -- a plain build exits and the tunnel |
| 74 | # closes with the sandbox -- but the port has to be declared at create time, |
| 75 | # so it is declared once here and `modal run --command` decides whether |
| 76 | # anything ever binds it. |
| 77 | [network] |
| 78 | ports = [8080] |
| 79 | |
| 80 | [run] |
| 81 | workdir = "/app" |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 82 | # Source in, toolchain out of the volume, build in place. Three steps, and |
| 83 | # none of them evaluates anything: the old command spent its first minutes |
| 84 | # entering a devShell, printing an environment, caching that environment |
| 85 | # against flake.lock and copying a nix closure back afterwards, all to arrive |
| 86 | # at a PATH. A PATH is what `tools/toolchain.sh env` prints, out of a |
| 87 | # directory that is already on the volume. |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 88 | command = """ |
| 89 | set -e |
| 90 | SHELL_DIR=/devshell/frq-flutter-web |
| 91 | |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 92 | # Beside the working tree and NOT inside it: the rsync below runs with |
| 93 | # --delete, so anything under $SHELL_DIR that is not in /app is removed on |
| 94 | # every run. A cache kept in there would be deleted moments before it was |
| 95 | # consulted -- which is what happened to the last one that tried. |
| 96 | export FRQ_TOOLCHAIN=/devshell/frq-flutter-web.toolchain |
| 97 | mkdir -p "$SHELL_DIR" "$FRQ_TOOLCHAIN" |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 98 | |
| 99 | echo "sync: /app -> $SHELL_DIR" |
| 100 | # rsync and not cp, with --checksum and not mtimes: Modal copies the source in |
| 101 | # with fresh timestamps every run, so a plain copy looks entirely new to |
| 102 | # Flutter and rebuilds the lot. --checksum compares content and leaves the |
| 103 | # unchanged files' timestamps alone, which is the whole basis of the |
| 104 | # incremental build. |
| 105 | # |
| 106 | # The excludes are the state we are here to keep -- overwriting them from /app |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 107 | # would defeat the volume. `flutter/web/` is NOT on the list: it is committed, |
| 108 | # because the OAuth client keeps a script there, so it has to arrive from |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 109 | # /app like any other source. |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 110 | rsync -a --checksum --delete \ |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 111 | --exclude 'flutter/.home/' \ |
| 112 | --exclude 'flutter/.clojuredart/' \ |
| 113 | --exclude 'flutter/build/' \ |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 114 | --exclude 'flutter/lib/cljd-out/' \ |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 115 | --exclude 'flutter/.dart_tool/' \ |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 116 | --exclude '.toolchain/' \ |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 117 | --exclude '.git' \ |
| 118 | /app/ "$SHELL_DIR/" |
| 119 | |
| 120 | cd "$SHELL_DIR" |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 121 | # What survived from the last run, by presence and not by size: `du` here |
| 122 | # walked the pub cache, the toolchain and every object of the last build over |
| 123 | # a network volume, for numbers nobody acts on. |
| 124 | for d in "$FRQ_TOOLCHAIN" flutter/.clojuredart flutter/lib/cljd-out flutter/build; do |
| 125 | [ -d "$d" ] && echo " carried over: $d" |
| 126 | done |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 127 | |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 128 | # The same script `just flutter-web` runs, with the same single build mode: |
| 129 | # what is served and what a laptop compiles are the same bundle. |
| 130 | tools/build-web.sh build |
| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 131 | """ |
| Three tarballs where a devShell was 5ce66d5 nandi yesterday | 132 | # Flutter keeps its settings -- `--enable-web` among them -- under |
| 133 | # XDG_CONFIG_HOME, and its own caches under XDG_CACHE_HOME. Both point into |
| 134 | # the volume so a second run finds what the first one decided. Set here |
| 135 | # rather than in the command so a shell into this container gets them too. |
| 136 | env = { XDG_CACHE_HOME = "/devshell/frq-flutter-web.toolchain/.cache", XDG_CONFIG_HOME = "/devshell/frq-flutter-web.toolchain/.config", FRQ_TOOLCHAIN = "/devshell/frq-flutter-web.toolchain" } |