PhoenixMountable.Igniter (PhoenixMountable v0.2.1)

Copy Markdown View Source

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.

Summary

Functions

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).

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.

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

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

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

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).

Functions

add_css_imports(igniter, otp_app, files, opts \\ [])

@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(igniter, hook, package, opts \\ [])

@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_supervisor(igniter, opts \\ [])

@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(igniter, otp_app)

@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(igniter, migrations, opts \\ [])

@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(igniter, definition, path, opts \\ [])

@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.