Packages
mob
0.7.5
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.2
0.6.1
0.6.0
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.11
0.5.10
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.0
BEAM-on-device mobile framework for Elixir
Current section
Files
Jump to
Current section
Files
mix.exs
defmodule Mob.MixProject do
use Mix.Project
def project do
[
app: :mob,
version: "0.7.5",
elixir: "~> 1.19",
start_permanent: Mix.env() == :prod,
elixirc_paths: elixirc_paths(Mix.env()),
compilers: compilers(Mix.env()) ++ Mix.compilers(),
deps: deps(),
aliases: aliases(),
unused: [
ignore: [
# GenServer / behaviour callbacks (mix_unused can't see them).
{:_, :init, 1},
{:_, :handle_call, 3},
{:_, :handle_cast, 2},
{:_, :handle_info, 2},
{:_, :handle_continue, 2},
{:_, :terminate, 2},
{:_, :code_change, 3},
# Mob's public render-tree API — every component module exposes
# render/1 callable from app code. mix_unused sees no internal
# caller because it lives in user apps.
{~r/^Mob\..+/, :render, 1},
# Screen lifecycle callbacks dispatched by the Mob.Screen
# GenServer wrapper.
{~r/^Mob\..+/, :mount, 3},
{~r/^Mob\..+/, :on_start, 0},
{~r/^Mob\..+/, :on_resume, 1},
# Screen state persistence — generated by `use Mob.Screen, vsn: N`.
{~r/^Mob\..+/, :__mob_vsn__, 0},
{~r/^Mob\..+/, :__mob_persist__, 0},
{~r/^Mob\..+/, :dump_state, 1},
{~r/^Mob\..+/, :load_state, 2},
{~r/^Mob\..+/, :screen_key, 1},
# NIF stub functions in src/mob_nif.erl (apply'd via load_nif).
{:mob_nif, :_, :_},
# Mob.Test diagnostic API surface — IEx-driven, no internal
# caller in mob itself.
{~r/^Mob\.Test$/, :_, :_},
# Theme accessors — used by user apps via Mob.Theme.<name>.
{~r/^Mob\.Theme\..+/, :_, :_}
]
],
description: "BEAM-on-device mobile framework for Elixir",
source_url: "https://github.com/genericjam/mob",
homepage_url: "https://hexdocs.pm/mob",
package: package(),
docs: docs()
]
end
def application do
[
# :public_key is needed by Mob.Certs at runtime; Elixir 1.19+ strips
# unused OTP applications from the code path, so it must be declared
# here even though mob doesn't *start* it directly.
extra_applications: [:logger, :public_key]
]
end
# Two hexdocs-only injections: (1) classify unstyled <pre><code> blocks as
# Elixir so they get syntax-highlighted, and (2) render ```mermaid fenced
# blocks as SVG (ex_doc has no built-in mermaid support; GitHub renders
# them natively, so READMEs work there without this).
defp before_closing_body_tag(:html) do
"""
<script>
// Default unstyled code blocks to Elixir highlighting.
document.querySelectorAll("pre code").forEach(el => {
if (!el.className) el.className = "language-elixir";
});
</script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
mermaid.initialize({ startOnLoad: false });
let id = 0;
for (const codeEl of document.querySelectorAll("pre code.mermaid")) {
const preEl = codeEl.closest("pre");
const graphEl = document.createElement("div");
const graphId = "mermaid-graph-" + id++;
mermaid.render(graphId, codeEl.textContent).then(({ svg, bindFunctions }) => {
graphEl.innerHTML = svg;
if (bindFunctions) bindFunctions(graphEl);
preEl.replaceWith(graphEl);
});
}
});
</script>
"""
end
defp before_closing_body_tag(_), do: ""
defp docs do
[
main: "readme",
before_closing_body_tag: &before_closing_body_tag/1,
logo: "assets/logo/logo_full_color.png",
source_url: "https://github.com/genericjam/mob",
source_url_pattern: "https://github.com/genericjam/mob/blob/master/%{path}#L%{line}",
extras: [
"README.md": [title: "Mob"],
"CHANGELOG.md": [title: "Changelog"],
"MOB_PLUGINS.md": [title: "Plugins — Manifest Reference"],
"MOB_PLUGIN_SECURITY.md": [title: "Plugins — Security & Trust"],
"MOB_STYLES.md": [title: "Styles — Manifest Reference"],
"guides/why_beam.md": [title: "Why the BEAM?"],
"guides/getting_started.md": [title: "Getting Started"],
"guides/packages.md": [title: "First-Party Packages"],
"guides/architecture.md": [title: "Architecture & Prior Art"],
"guides/screen_lifecycle.md": [title: "Screen Lifecycle"],
"guides/events.md": [title: "Events"],
"guides/event_model.md": [title: "Event Model"],
"guides/background_execution.md": [title: "Background Execution"],
"guides/components.md": [title: "Components"],
"guides/styling.md": [title: "Styling & Native Rendering"],
"guides/theming.md": [title: "Theming"],
"guides/navigation.md": [title: "Navigation"],
"guides/device_capabilities.md": [title: "Device Capabilities"],
"guides/mobile_surface_matrix.md": [title: "Mobile Surface Matrix"],
"guides/permissions.md": [title: "Permissions"],
"guides/native_extensions.md": [title: "Native Extensions (NIFs, features)"],
"guides/plugins.md": [title: "Writing a Plugin"],
"guides/dns_on_ios.md": [title: "DNS on iOS"],
"guides/push_notifications.md": [title: "Push Notifications"],
"guides/data.md": [title: "Data & Persistence"],
"guides/testing.md": [title: "Testing"],
"guides/tooling.md": [title: "Tooling & Formatting"],
"guides/publishing.md": [title: "Publishing to App Store / TestFlight"],
"guides/troubleshooting.md": [title: "Troubleshooting"],
"guides/support_matrix.md": [title: "Device Support Matrix"],
"guides/liveview.md": [title: "LiveView Mode"],
"guides/ios_physical_device.md": [title: "iOS Physical Devices"],
"guides/agentic_coding.md": [title: "Agentic Coding"]
],
groups_for_extras: [
Guides: ~r/guides\/.*/,
Plugins: ["MOB_PLUGINS.md", "MOB_PLUGIN_SECURITY.md", "MOB_STYLES.md"]
],
groups_for_modules: [
Core: [Mob, Mob.App, Mob.Screen, Mob.ScreenState, Mob.Socket, Mob.State],
UI: [
Mob.UI,
Mob.Style,
Mob.Renderer,
Mob.Composite,
Mob.Theme,
Mob.Theme.Light,
Mob.Theme.Dark,
Mob.Theme.Adaptive
],
Navigation: [Mob.Nav.Registry],
Plugins: [Mob.Plugins, Mob.Plugins.Supervisor, Mob.Plugins.Lifecycle],
"Device APIs": [
Mob.Haptic,
Mob.Clipboard,
Mob.Share,
Mob.Permissions,
Mob.Files,
Mob.Audio,
Mob.Motion
],
"Testing & Debugging": [Mob.Test],
Tooling: [Mob.Formatter],
Internals: [Mob.Dist, Mob.NativeLogger, Mob.List, Mob.Sigil]
]
]
end
defp elixirc_paths(:test), do: ["lib", "test/onboarding", "test/onboarding/support"]
defp elixirc_paths(_), do: ["lib"]
defp package do
[
licenses: ["MIT"],
links: %{"GitHub" => "https://github.com/genericjam/mob"},
files: ~w(
lib src priv
android ios assets
mix.exs mix.lock
README.md CHANGELOG.md LICENSE
)
]
end
defp aliases do
# `mix setup` after cloning installs deps and activates the shared git
# hooks (.githooks): format / Credo --strict / compile run on every push
# and the full suite when mix.exs changes — the same gate CI enforces.
[setup: ["deps.get", "cmd git config core.hooksPath .githooks"]]
end
defp deps do
[
# HTML/HEEx template engine — same one Phoenix uses
# {:phoenix_live_view, "~> 1.0", optional: true}, # add when HEEx rendering lands
{:nimble_parsec, "~> 1.0"},
{:ex_doc, "~> 0.34", only: :dev, runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:jump_credo_checks, "~> 0.1.0", only: [:dev, :test], runtime: false},
# ex_slop — Credo check that catches AI-generated Elixir patterns
# (blanket rescue, narrator-style docs, redundant Enum chains, etc).
# Wired in via .credo.exs as `{ExSlop, []}` in the enabled list.
{:ex_slop, "~> 0.4", only: [:dev, :test], runtime: false},
{:erlfmt, "~> 1.8", only: :dev, runtime: false},
# mix_audit — CVE scan over mix.lock against the Erlef advisory feed.
# Invocation note: `mix deps.audit` alone fails with
# `YamlElixir.read_from_file/1 is undefined` because mix_audit doesn't
# ensure_all_started its yaml_elixir transitive dep before parsing
# the advisory files. CI works around this with `mix do app.start +
# deps.audit` (the app.start prefix starts the host app, which
# transitively starts yaml_elixir via the runtime tree).
{:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false},
# Known Elixir 1.20-rc.4 dep warning (cosmetic, dev-only):
# lib/mix_unused/filter.ex:61 — `_.._ inside match is deprecated`.
# No upstream fix shipped yet (0.4.1 is latest, from 2024). Bump
# this version + drop this comment once mix_unused ships a 1.20-clean
# release.
{:mix_unused, "~> 0.4", only: :dev, runtime: false},
{:ecto_sqlite3, "~> 0.18", only: :test}
]
end
# `:unused` only runs in dev. Keeps test/CI logs clean.
defp compilers(:dev), do: [:unused]
defp compilers(_), do: []
end