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

Building blocks for a mountable library's Igniter installer.

With them, a library's `mix my_lib.install` is a few lines:

    defmodule Mix.Tasks.MyLib.Install do
      use Igniter.Mix.Task

      @impl Igniter.Mix.Task
      def info(_argv, _parent), do: %Igniter.Mix.Task.Info{group: :my_lib}

      @impl Igniter.Mix.Task
      def igniter(igniter) do
        igniter
        |> PhoenixMountable.Igniter.mount(MyLib.Router, "/my_lib")
        |> PhoenixMountable.Igniter.gen_migration(MyLib.Migrations)
        |> PhoenixMountable.Igniter.add_tailwind_source(:my_lib)
      end
    end

Hosts then run `mix igniter.install my_lib`. Every step is idempotent, so
running the installer again changes nothing.

For upgrades, call `gen_migration/3` from the library's Igniter upgrader:
it writes the migration from the host's pinned version to the latest, or
nothing when the host is up to date.

# `add_css_imports`

```elixir
@spec add_css_imports(
  Igniter.t(),
  atom(),
  [String.t() | {String.t(), :import | :comment}],
  keyword()
) ::
  Igniter.t()
```

Imports style sheets of the library in the host's `assets/css/app.css`,
after its other `@import` lines: `files` are paths in the package (or
names in its `priv/static`), each a string or `{path, :comment}` for an
import left as a comment (a theme the host turns on).

    add_css_imports(igniter, :my_lib, ["my_lib.css", {"my_lib-dark.css", :comment}])

The paths go through `deps/`, or the directory of a path dependency.

## Options

  * `:path` — the file. Defaults to `"assets/css/app.css"`.

# `add_hook`

```elixir
@spec add_hook(Igniter.t(), String.t(), String.t(), keyword()) :: Igniter.t()
```

Adds a LiveView hook of the library to the host's `assets/js/app.js`:
`import { Hook } from "package"`, and `Hook` in the hooks of its
`new LiveSocket(...)`. For a library whose components render in the
host's own pages.

When the hooks cannot be edited safely, it changes nothing and warns
with the lines to add (see `PhoenixMountable.Igniter.HostAssets`). It
tells the host when its esbuild config does not resolve packages from
`deps/`.

## Options

  * `:path` — the file. Defaults to `"assets/js/app.js"`.

# `add_html_helpers`

```elixir
@spec add_html_helpers(Igniter.t(), [String.t()], keyword()) :: Igniter.t()
```

Adds lines to the `html_helpers` of the host's web module, which every
LiveView, component and template of the host gets: imports of the
library's components, or of a module of the host's.

    add_html_helpers(igniter, ["import MyLib.Components"])
    add_html_helpers(igniter, ["import {app}.Permissions, only: [allowed?: 3]"])

`{app}` is the host's module prefix (`MyApp`), `{web}` its web module
(`MyAppWeb`). A line already there is not added again. When the web
module has no `html_helpers` with a `quote` block, it changes nothing
and warns with the lines to add.

## Options

  * `:web` — the web module. The host's by default.

# `add_raw_body`

```elixir
@spec add_raw_body(Igniter.t(), keyword()) :: Igniter.t()
```

Keeps the body of the requests whose plug wants it as it was sent
(`PhoenixMountable.RawBody`): adds `body_reader:
{PhoenixMountable.RawBody, :read_body, [Router]}` to the `Plug.Parsers`
of the host's endpoint.

An endpoint whose `Plug.Parsers` has that reader already is left as it
is. One with another reader is left as it is too, with a warning that
says what to change: the host's reader may be there for a reason of its
own.

Options: `:router` and `:endpoint`, the host's by default.

# `add_supervisor`

```elixir
@spec add_supervisor(Igniter.t(), keyword()) :: Igniter.t()
```

Starts the processes of every mount at boot: adds
`{PhoenixMountable.Supervisor, router: ..., endpoint: ...}` to the host's
application, after its endpoint.

# `add_tailwind_source`

```elixir
@spec add_tailwind_source(Igniter.t(), atom()) :: Igniter.t()
```

Makes the host's Tailwind scan the library's templates, for libraries
styled by the host (`PhoenixMountable.Assets.Host`).

Tailwind v4 (Phoenix 1.8): adds `@source "../../deps/<app>";` to
`assets/css/app.css`. Tailwind v3 (Phoenix 1.7): adds
`"../deps/<app>/**/*.*ex"` to the `content` of `assets/tailwind.config.js`.

# `gen_migration`

```elixir
@spec gen_migration(Igniter.t(), module(), keyword()) :: Igniter.t()
```

Writes the migration that installs the library, or upgrades it from the
version the host's migrations pin, to the latest version.

## Options

  * `:repo` — the repo (asked, or the only one)
  * `:to` — the version. Defaults to the latest.

# `mount`

```elixir
@spec mount(Igniter.t(), module(), String.t(), keyword()) :: Igniter.t()
```

Mounts the library in the host's router: adds the mount call, with the
import of the module that defines its macro, to the scope with the given
path and pipelines (a new one when the router has none).

It looks for the mount macro in the router, so running it again, or
after the host moved the mount elsewhere, changes nothing. It adds the
library to the `import_deps` of the host's `.formatter.exs`, so that the
mount call keeps no parentheses when the library exports its macro:

    # the library's .formatter.exs
    [export: [locals_without_parens: [my_lib: 1, my_lib: 2]], ...]

## Options

  * `:router` — the router (asked, or the only one)
  * `:scope` — the path of the scope. Defaults to `"/"`. An admin goes
    in the host's admin scope: `scope: "/admin"`.
  * `:pipelines` — the pipelines of the scope. Defaults to `[:browser]`.
  * `:options` — mount options, as a string of Elixir code
    (`"resolver: MyApp.MyLibResolver"`). `{web}` in it is the host's web
    module (`"resolver: {web}.MyLibResolver"` gives
    `resolver: MyAppWeb.MyLibResolver`).
  * `:import` — the module to import for the macro. Defaults to the
    definition; a library with several definitions whose macros one
    module re-exports names that module.

---

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