| A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago | 1 | # `flutter-web` |
| 2 | |
| 3 | modal run .modal/flutter-web/container.py |
| 4 | just modal flutter-web |
| 5 | |
| 6 | Defined by `container.toml`; see `../spec.md` for the keys. |
| 7 | Built on the published `arch-nix` image. |
| 8 | |
| 9 | `flutter-dev` with the Linux target swapped for the web one: the same |
| 10 | `clojure -M:cljd compile` over the same `flutter/src` and `common/`, |
| 11 | then dart2js instead of CMake and Ninja. Same incremental shape -- |
| 12 | the working tree and Flutter's caches live on the `devshell` volume, |
| 13 | under `frq-flutter-web/` so the desktop container's directory beside |
| 14 | it is untouched. |
| 15 | |
| 16 | Runs as a Sandbox on a real VM (kernel 6.x, not gVisor). The command |
| 17 | is the sandbox's own process, so it dies when the command exits. |
| 18 | |
| 19 | To look at what it built, ask for the serve action -- `[network] |
| 20 | ports` tunnels 8080 out, and the URL is printed once the sandbox is |
| 21 | scheduled: |
| 22 | |
| 23 | modal run .modal/flutter-web/container.py \ |
| 24 | --command 'cd /devshell/frq-flutter-web && nix develop /app#flutter-web --command just -f /devshell/frq-flutter-web/justfile flutter-web serve' |
| 25 | |
| 26 | That blocks until you Ctrl-C it, and it bills until you do. |
| 27 | |
| 28 | ## It compiles; it does not start |
| 29 | |
| 30 | dart2js links the whole app -- `main.dart.js` is 3.6MB and has |
| 31 | `frq`, `irc`, `atproto` and `handshake` all through it, so the |
| 32 | `dart:io` imports under `flutter/src` are not the wall they look |
| 33 | like. What stops it is the first line of `main`: |
| 34 | `getApplicationDocumentsDirectory` is a platform channel, path_provider |
| 35 | ships no web implementation, and the channel with no handler behind it |
| 36 | throws `MissingPluginException`. `main` awaits that before installing |
| 37 | `frq.io.dart`, so no widget is ever built and the page stays white. |
| 38 | |
| 39 | That is the seam doing its job rather than a build problem. The fix is |
| 40 | a `frq.io.web` behind `frq.io` -- the browser's answer for a private |
| 41 | file is IndexedDB or localStorage, not a directory -- and `main` |
| 42 | choosing it the way `flutter/src/frq/main.cljd` chooses the Dart one |
| 43 | now. `frq.net.web` is the next one after it, for the same reason: a |
| 44 | browser has no raw socket, so the IRC connection wants a WebSocket. |
| 45 | |
| 46 | ## Serving it |
| 47 | |
| 48 | `serve.py` is the other half: a Function that mounts the same volume |
| 49 | and hands out `flutter/build/web`, so a rebuild in the Sandbox is |
| 50 | picked up by the next cold start with nothing redeployed. |
| 51 | |
| 52 | modal deploy .modal/flutter-web/serve.py |
| 53 | |
| 54 | `[network] ports` tunnels 8080 out of the Sandbox as well, for the |
| 55 | case where you want the build and the server to be one process. |