mix mob.adopt (mob_dev v0.6.16)

Copy Markdown View Source

Adds Mob (mobile framework) to an existing Phoenix-based Elixir project.

⚠ Experimental (pre-1.0)

mix mob.adopt is experimental. On anything outside the supported shapes the task refuses with a clear message rather than risk breaking your app. The supported surface will widen as we stabilise.

Supported (default — LV bridge)

  • Single (non-umbrella) Phoenix project.
  • Stock assets/js/app.js (contains new LiveSocket(...)).
  • Stock root layout (lib/<app>_web/components/layouts/root.html.heex or the legacy templates/layout/root.html.heex) with a <body> tag.
  • Ecto Repo uses the SQLite adapter (:ecto_sqlite3 in deps). The generated mob_app.ex migrates <App>.Repo on-device; the SQLite assumption is hard-coded. A mix phx.new --database sqlite3 project matches.

Supported (--no-live-view — thin-client)

Same Phoenix-shape requirements but no Ecto/Repo constraint — the phone opens a deployed Phoenix server via WebView and runs no DB on-device. Works against Postgres / MySQL / --no-ecto hosts.

Refused (loud, with guidance)

  • Umbrella applications.
  • Non-Phoenix projects (no :phoenix dep).
  • Heavily customised app.js (no recognisable new LiveSocket().
  • Heavily customised root layout (no recognisable <body> tag, or no layout file at all).
  • LV mode + host Repo uses Postgres / MySQL / MSSQL (or no Repo at all). Use --no-live-view instead, or wait for the future --with-local-repo mode that handles non-SQLite hosts via a separate on-device LocalRepo.

Composable, Igniter-based — mirrors the architecture of team-alembic/phx_install. This is the install-into-existing counterpart to mix mob.new, which generates a project from scratch. mix mob.new is unaffected by this task.

Usage

mix mob.adopt [OPTIONS]

Run from inside an existing Mix project. The target project must declare {:igniter, "~> 0.7", only: [:dev, :test]} in its mix.exs (most modern Phoenix-ecosystem projects already do).

The native trees (--android / --ios, on by default) render from mob_new's templates, so they also require the mob_new archive installed:

mix archive.install hex mob_new

mob_new stays the single source of native templates (no duplication across repos). The Elixir-side adoption (deps, LiveView bridge, mob.exs, MobScreen) needs no archive — only --android/--ios do.

Options

  • --no-ios — skip the iOS native tree
  • --no-android — skip the Android native tree
  • --localpath: deps for :mob/:mob_dev; pre-fill mob.exs paths from MOB_DIR / MOB_DEV_DIR. For Mob framework contributors.
  • --python — iOS-only: pre-configure embedded CPython via Pythonx
  • --host-url URL — write config :mob, host_url: URL so the generated MobScreen opens URL instead of the default http://127.0.0.1:4000/. Use for thin-client deployments where the WebView points at a deployed Phoenix server (fly.io etc.).
  • --no-live-view — skip the LiveView bridge patches (assets/js/app.js MobHook, root.html.heex bridge div) AND generate a thin-client mob_app.ex that does NOT boot Phoenix on-device. For Hologram-only or non-Phoenix hosts where the BEAM-on-device is just the native interop layer.

Both platforms emit by default. Passing both --no-ios and --no-android raises.

What gets installed

  • :mob + :mob_dev deps in mix.exs
  • lib/<app>/mob_screen.exMob.Screen opening a WebView at Application.get_env(:mob, :host_url) (default localhost)
  • mob.exs — build-environment config
  • .gitignore updated to ignore mob.exs
  • android/ and/or ios/ native trees (gated by platform flags)
  • lib/<app>/mob_app.ex + src/<app>.erl for on-device BEAM entry
  • erlc_paths/erlc_options added to mix.exs

Default (no --no-live-view):

  • MobHook injected into assets/js/app.js
  • bridge <div> injected into root.html.heex
  • mob_app.ex boots the host Phoenix endpoint on-device

With --no-live-view:

  • LiveView bridge patches skipped
  • mob_app.ex is the thin-client variant (use Mob.App shell, no Application.ensure_all_started)

Composability

Every sub-installer is invokable independently:

mix mob.adopt.deps          # just bump mix.exs
mix mob.adopt.bridge        # just patch app.js + root.html.heex
mix mob.adopt.screen        # just generate mob_screen.ex
mix mob.adopt.mob_app       # just generate mob_app.ex + .erl bootstrap
mix mob.adopt.mob_exs       # just write mob.exs + .gitignore
mix mob.adopt.native        # both native trees
mix mob.adopt.native.android
mix mob.adopt.native.ios
mix mob.adopt.finalize      # post-install notice (no file changes)

Each accepts the same flags as mob.adopt and respects them individually. Run mix help mob.adopt.<sub> for sub-task docs.

On-device runtime services (Mob.ComponentRegistry, Mob.NativeLogger, etc.) start imperatively inside <App>.MobApp.start/0Mob.App is the behaviour the device entry uses (via use Mob.App), never a supervision-tree child.

The native trees come from mob_new's priv/templates/mob.new/; the Elixir-source content (mob_screen.ex, mob_app.ex, the LV bridge patches) from MobDev.Adopt.Patcher / MobDev.Adopt.Generator, both duplicated from mob_new pending the Phase-5 Igniter reunification.