# `PhoenixMountable`
[🔗](https://github.com/hattoriai/phoenix_mountable/blob/v0.2.1/lib/phoenix_mountable.ex#L2)

Build libraries that mount into a Phoenix app.

A mountable library brings its own routes, LiveViews, controllers, assets
and processes, and a host app mounts it with one line in its router:

    # in the host router
    import MyLib.Router

    scope "/" do
      pipe_through :browser
      my_lib "/my_lib", resolver: MyApp.MyLibResolver
    end

The library declares everything in a *definition module*:

    defmodule MyLib.Router do
      use PhoenixMountable,
        otp_app: :my_lib,
        macro: :my_lib,
        layout: {MyLib.Layouts, :root},
        assets:
          {PhoenixMountable.Assets.Embedded,
           css: "priv/static/app.css",
           js: "priv/static/app.js",
           prepend: [:phoenix, :phoenix_html, :phoenix_live_view, :phoenix_mountable]}

      options resolver: [type: :atom, default: MyLib.Resolver, verify: {:behaviour, MyLib.Resolver}],
              features: [type: {:list, :atom}, default: []]

      routes do
        get "/export", MyLib.ExportController, :csv

        live_session :public, host_on_mount: false do
          live "/share/:token", MyLib.ShareLive, :show
        end

        live_session :default, on_mount: [MyLib.Auth] do
          live "/", MyLib.HomeLive, :index
          live "/items/:id", MyLib.ItemLive, :show
        end
      end
    end

The generated macro (`my_lib/2`) inserts ordinary Phoenix routes and live
sessions into the host router: `mix phx.routes` lists them, the host's
pipelines and scopes apply to them, and LiveView navigation works between
them. LiveView is optional: a library of controllers and plugs mounts in a
host without it.

See `PhoenixMountable.Definition` for `options/1`, `routes/1` and
`pipeline/2`, and `PhoenixMountable.Routes` for the routes.

## `use` options

* `:otp_app` (`t:atom/0`) - Required. The library's OTP application.

* `:macro` (`t:atom/0`) - Required. The name of the mount macro defined for hosts.

* `:as` (`t:atom/0`) - The default mount name, used to name live sessions and route helpers. Defaults to the macro name. Hosts pass `:as` to mount the library more than once.

* `:title` (`t:String.t/0`) - The page title of `PhoenixMountable.Layout`. Defaults to the camelized OTP application.

* `:layout` - The root layout of the library's pages: a `{module, function}` tuple for a document of its own (such as `{PhoenixMountable.Layout, :root}`), or `:host` to render inside the host's root layout. The default value is `:host`.

* `:assets` - How the library's CSS and JavaScript reach the browser: `{strategy, options}`. See `PhoenixMountable.Assets`. The default value is `nil`.

* `:on_mount` - `on_mount` hooks of the library, run in every library live session after the host's. The default value is `[]`.

* `:schema` (`t:atom/0`) - The library's `PhoenixMountable.Migrations` module. The first use of each mount then checks the host has run the library's migrations; see `c:PhoenixMountable.repo/1`.

* `:reload_on_stale` (`t:boolean/0`) - Reload a page whose library assets belong to a previous build when its LiveView reconnects. The default value is `true`.

* `:socket_path` (`t:String.t/0`) - The default of the `:socket_path` mount option. The default value is `"/live"`.

* `:transport` - The default of the `:transport` mount option. The default value is `:websocket`.

## Mount options

Besides the options a library declares, every mount macro takes:

* `:as` (`t:atom/0`) - The mount name: names the live sessions and route helpers. Mount a library twice with different names.

* `:on_mount` - The host's `on_mount` hooks, run before the library's. The default value is `[]`.

* `:socket_path` (`t:String.t/0`) - The path of the host's LiveView socket. Defaults to `"/live"`.

* `:transport` - The LiveView transport, `:websocket` (default) or `:longpoll`.

* `:csp_nonce_assign_key` - The assign holding the request's CSP nonce, or a map of kinds to assigns, such as `%{script: :script_nonce, style: :style_nonce}`. The default value is `nil`.

* `:asset_host` - A scheme and host to load the library's assets from, such as a CDN. The default value is `nil`.

* `:pubsub` - The PubSub server of `PhoenixMountable.PubSub`. Defaults to the endpoint's. The default value is `nil`.

## The mount

Library code reads the current `PhoenixMountable.Mount` as `@mount` in
LiveViews and templates, `conn.assigns.mount` in controllers and plugs, or
with `PhoenixMountable.Mount.current/0` in the process handling them.

# `children`
*optional* 

```elixir
@callback children(PhoenixMountable.Mount.t()) :: [
  Supervisor.child_spec() | {module(), term()} | module()
]
```

Child specs of the processes of one mount.

They start under a supervisor of their own the first time the mount is
used, or when the host starts `PhoenixMountable.Supervisor`. Each mount
gets its own subtree, so two mounts never share state. Name the children
with `via/2`.

# `normalize_options`
*optional* 

```elixir
@callback normalize_options(keyword()) :: keyword()
```

Adjusts or cross-validates the library's options after their validation.

Receives the options with defaults (a keyword list) and returns them,
possibly changed. Raise `ArgumentError` for an invalid combination. Runs
when the host router compiles.

# `repo`
*optional* 

```elixir
@callback repo(PhoenixMountable.Mount.t()) :: module() | nil
```

The Ecto repo holding the library's tables, for the `:schema` check.

# `session`
*optional* 

```elixir
@callback session(conn :: Plug.Conn.t(), PhoenixMountable.Mount.t(), session :: atom()) ::
  map()
```

Extra values for the LiveView session of a library live session.

Runs on the HTTP request that renders a library LiveView, with the host's
conn, so it can resolve the current user from the host's assigns. Returns a
map with string keys, merged into the session.

# `mounts`

```elixir
@spec mounts(module()) :: [PhoenixMountable.Mount.t()]
```

The mounts a host router declares.

# `via`

```elixir
@spec via(PhoenixMountable.Mount.t(), term()) ::
  {:via, Registry, {PhoenixMountable.Registry, term()}}
```

A `:via` name for a process of a mount, unique to the mount.

    def children(mount) do
      [{MyLib.Cache, name: PhoenixMountable.via(mount, :cache)}]
    end

---

*Consult [api-reference.md](api-reference.md) for complete listing*
