Phoenix 1.6.x what is `put_root_layout/2` good for?

Phoenix 1.6.6 phx.new puts some new plugs on top of router.ex these days. Those are:

plug :fetch_live_flash 
plug :put_root_layout, {PhxApp.LayoutView, :root}

While I take (please somebody correct me if I am wrong) the first one to be an extended, direct replacement of fetch_flash/2, I am wondering what the use of the second one is. What problem it solves? What was not working well enough in 1.5 that this helps with?

It puts root.html.heex as root layout while rendering.

The “root” layout is shared by both “app” and “live” layouts. It is rendered only on the initial request and therefore it has access to the @conn assign. The root layout must be defined in your router:

You can also override if you want in controllers.

conn
    |> put_root_layout({TeacherWeb.LayoutView, "blog.html"})
    |> render("index.html",  posts: posts)

For Live Views, you can override in live_session

live_session :session_name, root_layout: {MyAppWeb.LayoutView, "custom_layout.html"} do
  live "/path", MyAppWeb.PageLive
end

Live Layouts explains about this.

put_root_layout documentation

1 Like

It’s useful when You want to render in different format.

Sometime I need to render dynamic css, or files, or iframe…

I just need to switch which layout to use.

This was committed back in v1.4 branch so it’s been working well since then… Add root layouts (#3679) · phoenixframework/phoenix@a81dd86 · GitHub

Yeah, but you don’t need the said plug in your router to do that, do you? I’ve been switching those as needed happily for some time but only now got to know about that put_root_layout/2 stuff.

Might be. It’s just that I got it in my router.ex only today, once I started migrating project to 1.6.

Well, that’s what it says/implies :wink: and that’s what the controller docs say. But after a few months of work on a sizeable project I don’t recall ever missing it in my router.ex or anywhere else for that matter. I’ve been happily using app.html.slim as my “root” layout all the time. The docs on Live Layouts shed some light on it though. I believe putting it there by default is another step into closer binding of both “live” and “dead” views, right?

You don’t need it in the router in general but you have it right that it’s to bridge the gap between live and dead views. It helps to have a way to share the same root in a standard manner, so that the inital unconnected view of a live view can be rendered from the plug and you can set different pipelines to progressively upgrade the root layout. Or you can do progressive overrides e.g. the standard dead view gets a basic root, then a live session can set an upgraded root that pulls in the livesocket js stuff, and an admin live session can override the root with its own layout that may have other js which standard love views don’t need.

Well, they chose the best possible name for the func :smile:

I migrated an old project from 1.4 to 1.6 - i was surprised by this new plug. It was in phx.new from 1.5 according to git. I messed up migration and it was rendering white pages, turns out this plug was missing from router.

These days I am finding more interesting information in phoenix_live_view docs.

Yes, Common things like js, css, title, etc which go in can be put in root.html.heex to eliminate duplication between live and dead views.