From dc4d0444ad4f5266e98606c16400a1715c20b8dc Mon Sep 17 00:00:00 2001 From: Technofab Date: Mon, 18 Sep 2023 12:08:32 +0200 Subject: [PATCH] feat: add SSR support --- README.md | 21 ++++++++++++++++++-- lib/inertia_phoenix.ex | 8 ++++++++ lib/inertia_phoenix/controller.ex | 33 ++++++++++++++++++++++++++++++- lib/inertia_phoenix/helper.ex | 5 +++++ lib/inertia_phoenix/view.ex | 14 +++++++++---- mix.exs | 4 +++- 6 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 lib/inertia_phoenix/helper.ex diff --git a/README.md b/README.md index b69e19d..f3351e9 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,29 @@ Import render_inertia `lib/active_web.ex` end ``` +If you want to use SSR add `InertiaPhoenix.ViewHelper` to `lib/_web.ex` +```elixir + defp view_helpers do + quote do + ... + + import InertiaPhoenix.ViewHelper + + ... + end + end +``` + ## Configuration Add to `config/config.exs` ```elixir config :inertia_phoenix, - assets_version: 1, # default 1 - inertia_layout: "app.html" # default app.html + assets_version: 1, # default 1 + inertia_layout: "app.html", # default app.html + ssr_enabled: false, # default false + ssr_url: "http://127.0.0.1:13714" # default http://127.0.0.1:13714 ``` - Asset Versioning Docs: https://inertiajs.com/asset-versioning @@ -96,6 +111,8 @@ An example layout: ... + + <%= inertia_head(@conn) %> <%= @inner_content %> diff --git a/lib/inertia_phoenix.ex b/lib/inertia_phoenix.ex index fc4deaa..0e8ddb8 100644 --- a/lib/inertia_phoenix.ex +++ b/lib/inertia_phoenix.ex @@ -22,6 +22,14 @@ defmodule InertiaPhoenix do |> to_string end + def inertia_ssr_enabled do + Application.get_env(:inertia_phoenix, :ssr_enabled, false) + end + + def inertia_ssr_url do + Application.get_env(:inertia_phoenix, :ssr_url, "http://127.0.0.1:13714") + end + def path_with_params(%{request_path: request_path, query_string: ""}), do: request_path def path_with_params(%{request_path: request_path, query_string: query_string}) do diff --git a/lib/inertia_phoenix/controller.ex b/lib/inertia_phoenix/controller.ex index efa8935..6897dd3 100644 --- a/lib/inertia_phoenix/controller.ex +++ b/lib/inertia_phoenix/controller.ex @@ -1,12 +1,14 @@ defmodule InertiaPhoenix.Controller do @moduledoc false import InertiaPhoenix + require Logger import Plug.Conn, only: [ get_req_header: 2, put_resp_header: 3, - put_resp_cookie: 4 + put_resp_cookie: 4, + assign: 3 ] alias Phoenix.Controller @@ -26,13 +28,42 @@ defmodule InertiaPhoenix.Controller do def render_inertia(conn, component, assigns) do assigns = build_assigns(conn, assigns, component) + %{"body" => body, "head" => raw_head} = fetch_ssr(conn, assigns) + assigns = Keyword.put(assigns, :inertia_ssr_body, body) + head = Phoenix.HTML.raw(Enum.join(raw_head, "\n")) + conn |> Controller.put_view(InertiaPhoenix.View) |> Controller.put_layout(html: {InertiaPhoenix.View, :inertia}) |> put_csrf_cookie + |> assign(:inertia_ssr_head, head) |> Controller.render("inertia.html", assigns) end + defp fetch_ssr(conn, assigns) do + default = %{ + "head" => [], + "body" => "" + } + + if inertia_ssr_enabled() do + case HTTPoison.post(inertia_ssr_url() <> "/render", Jason.encode!(page_map(conn, assigns)), [{"Content-Type", "application/json"}]) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + if body == "" do + Logger.warn("Inertia SSR returned empty response, check SSR server logs") + default + else + Jason.decode!(body) + end + response -> + Logger.warn("Inertia SSR request failed: #{inspect(response)}") + default + end + else + default + end + end + defp build_assigns(conn, assigns, component) do assigns |> filter_partial_data(conn, component) diff --git a/lib/inertia_phoenix/helper.ex b/lib/inertia_phoenix/helper.ex new file mode 100644 index 0000000..8fd3562 --- /dev/null +++ b/lib/inertia_phoenix/helper.ex @@ -0,0 +1,5 @@ +defmodule InertiaPhoenix.ViewHelper do + def inertia_head(conn) do + conn.assigns[:inertia_ssr_head] + end +end diff --git a/lib/inertia_phoenix/view.ex b/lib/inertia_phoenix/view.ex index 888b6f5..dd95d7d 100644 --- a/lib/inertia_phoenix/view.ex +++ b/lib/inertia_phoenix/view.ex @@ -4,10 +4,16 @@ defmodule InertiaPhoenix.View do alias Phoenix.HTML.Tag def render("inertia.html", assigns) do - Tag.content_tag(:div, "", [ - {:id, "app"}, - {:data, [page: page_json(assigns)]} - ]) + { body, assigns } = Map.pop(assigns, :inertia_ssr_body) + + if body != "" do + Phoenix.HTML.raw(body) + else + Tag.content_tag(:div, "", [ + {:id, "app"}, + {:data, [page: page_json(assigns)]} + ]) + end end defp page_json(%{conn: conn}) do diff --git a/mix.exs b/mix.exs index 17f1ebf..8efc976 100644 --- a/mix.exs +++ b/mix.exs @@ -43,7 +43,9 @@ defmodule InertiaPhoenix.MixProject do {:ex_doc, "~> 0.29.4", only: :dev}, {:plug_cowboy, "~> 2.1", only: [:test]}, {:excoveralls, "~> 0.16", only: :test}, - {:doctor, "~> 0.17.0"} + {:doctor, "~> 0.17.0"}, + # needed for SSR + {:httpoison, "~> 2.0"} ] end