Skip to main content

lib/mix/tasks/install.ex

defmodule Mix.Tasks.DicEx.Install do
  @moduledoc """
  Copies the dicEx prebuilt assets into the host Phoenix application's
  `assets/vendor` and `assets/css` directories so they bundle into `app.js` /
  `app.css`, and prints the wiring snippet.

      mix dic_ex.install

  Phoenix 1.8+ only serves `app.js` / `app.css` from the bundle, so dicEx's
  assets must be imported rather than referenced via external `<script>` tags.
  Run this inside your Phoenix app (e.g. dragonEx / dragonias) after adding
  `{:dic_ex, "~> 0.1.0"}` to your dependencies.
  """

  use Mix.Task

  @shortdoc "Installs dicEx assets into the host Phoenix app"

  @impl true
  def run(_args) do
    cwd = File.cwd!()
    vendor = Path.join(cwd, "assets/vendor")
    css_dir = Path.join(cwd, "assets/css")
    File.mkdir_p!(vendor)
    File.mkdir_p!(css_dir)

    copies = [
      {"dic_ex.min.js", Path.join(vendor, "dic_ex.min.js")},
      {"dic_ex.css", Path.join(css_dir, "dic_ex.css")}
    ]

    for {file, dest} <- copies do
      src = Path.join([:code.priv_dir(:dic_ex), "static", file])

      if File.exists?(src) do
        File.cp!(src, dest)
        Mix.shell().info("[dicEx] copied #{file} -> #{Path.relative_to_cwd(dest)}")
      else
        Mix.shell().error("[dicEx] missing #{file} — run `mix dic_ex.build` in the package first")
      end
    end

    Mix.shell().info("""

    dicEx assets copied. Two manual steps to wire them into your bundle:

    1) Import the JS hook in assets/js/app.js (anywhere before LiveSocket):

        import "../vendor/dic_ex.min.js"

        // then make sure the hook reaches LiveSocket:
        const hooks = { ...(window.DicExHooks || {}) }
        const liveSocket = new LiveSocket("/live", Socket, { hooks, params: {_csrf_token: csrfToken} })

    2) Import the styles in assets/css/app.css (after the tailwind import):

        @import "./dic_ex.css";

    Then drop the component into any LiveView:

        <.live_component module={DicExWeb.DiceRoller} id="roller" on_roll={self()} />

    and receive rolls in the host:

        def handle_info({:dic_ex_rolled, %{result: result}}, socket), do: ...
    """)
  end
end