Do you still have DeadViews accompanying LiveViews?

I was just curious about what others are doing with simple pages.

For instance we can let “about page” be a dead view and “contact us” page to be a live view.

For reducing memory usage, but loosing the smooth page navigation.

Static page can be cached, so 404 and other error pages can be made DeadView.

Can we have something like SvelteKit, where we just write it as LiveView, but can mark certain pages as DeadView?

So that the page will have server side rendering, but no socket connection.

However if need arises, we can just remove that spec and page will become LiveView again!

That way we won’t have to choose between the controller and LiveView approach, we just gravitate towards the LiveView side for any page building, and Controllers side for API!!

In Svelte Kit, you can mark certain pages Static or the whole site static. So they have the option of setting few pages static, which in turn doesn’t hydrate in the front end, thereby speeding up the initial load and stuff!


Options like:

  • render: once (For content that gets fetched at runtime.)

  • render: static (For content that is fixed at compile time, i.e. Nimble Publisher or just local db or git source, Which will essentially make Phoenix a static site generator!!)


Why would you make contact us a LiveView? I would make it dead as there is no state and no point remounting them if they return to the tab later on.

It depends what the site is and where your users are. On a LAN you can make everything liveview pretty fearlessly but I wouldn’t use it for content pages on the www.

I’ve seen blogs as liveviews and I tell you, being scrolled back to the top of a blog you were halfway through reading but switched tabs is not a good UX.


I suggested Contact Us as LiveView, because I just dreamt it as a custom solution for contacting, instead of an old school mailto.

Also every example I posted is just a random scenario, I am not talking specifically about a Blog or Contact US page.

What I am trying to get across is that LiveView may not be right for everything, and instead of creating a page twice or context switching between Controllers and LiveView, can’t we just have an option to disable LiveView for pages we don’t meed interaction with!

Say any page apart from the admin dashboard being InertViews, but the dashboard or collaboration page are Live.

Also, if the site is getting DDOSed, we can temporarily disable the socket connection and let the site be served as static pages until the attack subsides.

I thought that was not an issue with LiveView.

I just thought HotWire has that issue, after using GitHub.

It is an issue for liveview on mobile. I’m not sure if it’s LiveView or the browser’s fault though.

In your scenario, do you imagine a page could be switched between dead or live. That would probably get messy or be impossible. Or are you thinking that dead views live in the same folder with a render function and event handlers?

Yup, I was thinking like once we declare something as Dead View, it stays inert throughout.

LiveView, only falls back to render once / mount once mode when we set it like that. (Say with a FunWithFlags feature flag.)

And in the UI we can notify users with: “We are currently experiencing DDOS, thus our site is read only mode, you can see the pre-rendered view!”

And we can scope the dead view stuff with –web arg.

So it will be in a separate folder. It will utilise the same component as any LiveView and Controller, and just act like a server side rendered static page.

Similar to how Phoenix 1.7 unified the Heex template usage across Controller and LiveView, I am hoping it gets further unified and we won’t need controller at all. (Except for REST APIs)

Why use separate views in the first place. LV already does a static render. The page only becomes “live” when the websocket/channel connection is established. To stop that you could have some toggle to prevent the websocket connection (or the LV part of it).

I don’t think that’s a useful goal given the technical differences between http and persistent connections (websockets). E.g. a file download works considerably different with http vs trying to send a file through websockets.


I am aware of the second mount call and That’s exactly what I was asking for.

How do I do it? i.e. Prevent the socket connection?

I understand that, I was just saying why have two ways of writing the same thing, at least for static page with no file upload. Just a read only page should render fine without socket connection stage and second mount.

If I can just figure out a way to stop that second mount and socket connection, I will write everything in LiveView and only prevent socket connection for static pages.

P.S. I hope it’s not on_connect? |> dont_connect. :sweat_smile:

P.P.S. This is the reason I’m asking for a solution:

Simplest would probably be put some meta tag in your head (root.html.heex) similarly to how the csrf token is handled – this can e.g. be based on an assign set in a plug or the LV mount. In the js read that value to either start or not start the websocket connection.


Actually a contact form is a good candidate for LiveView because it will stop spammers, as most spams only automate post requests, they don’t establish websocket connections and emit the required events.

It seems fixable? When you disconnect you store the scroll state, when you reconnect you revert it there. It is probably doable with callbacks but maybe it should be as part of LiveView?


I have a private family/friends project which is little more than a weekend hack. So the only public entry to it is a static deadview login form.

Once you’re in, you’re treated to the full LiveView app.

In general, in my opinion, if it can be a static page, make it deadview. No reason to set up websocket connections, send over extra JS (even if it’s already cached by the browser) etc. just to display a static page.


That’s exactly my point. @LostKobrakai suggestion seems doable, however I don’t want that.

I just want it to be stopped from backend.

If a LiveView is set as render once, no JavaScript should land users browser. And no initiation of Socket connection happens!

Yup, now even for simple forms I won’t use dead view controller way of doing it.

Yes please. Scroll position getting messed up in SPAs feel bad. I hate it when along with losing scroll position the whole data reloads. (Like YouTube)


My suggested approach would allow you to implement just that. What I suggested specifically would only prevent the socket connection, but there’s nothing stopping you from using an assign to not include the js in the html head, or switch to a different js script.

Yes, it would work.

But it’s an awesome hack.

I was kind of hoping that towards 2.0 release of Phoenix framework, we will have this from the backend itself!!

Since it’s a compile time decision or somewhat runtime decision and both of those decisions can be done on server side.

Not late on client side!

Akin to how the page loads when JS is disabled. :sweat_smile:

I want to feed bots static cached data and not waste compute on them!

Using an assign to modify the result of rendering your root.html.heex layout is handling this server side. I suggested delaying this to client side, because usually your js doesn’t just connect to websockets, but also handles additional concerns of the UI like dropdowns, video players, …, which you’d likely not want to disable just because the page is “static”.

Drop downs and video players are supposed to be UI only JS like Alpine js or hls library’s responsibility. It should still work.

Or something like QWIK can be done:

This framework serializes the JavaScript necessary for a certain interaction inline. Similar to @chrismccord’s idea of keeping related things together!

I haven’t checked when the js hooks gets downloaded, hope it’s downloaded only when an element using it, references it.

I was playing with that idea a few weeks ago with idea that a “contact us” chat form would always be visible but dead until the user actually interacted with it and then it would be a liveview component.

Here’s some test code dump work · rktjmp/phx-necromancy@d7ba32c · GitHub with the idea that you would just attach data-live-view-connect="event-type" to elements to trigger connects, or you can just match on phx-click etc wholesale. I would imagine anyone doing this in production would have very focused requirements on what things caused a summon.

Mostly its very simply but you have to re-fire events that would trigger a connect after connection is established, and currently forms connect but don’t show validation until the second event for whatever reason, didn’t look to hard into that, sure its not hard to solve.

From memory you still needed the LV JS and page prep ready to go - just unconnected for the necromancy effect to work vs not having the code at all and fetching it as needed, then connecting. Doing that would probably add noticeable latency anyway (http get, parse, connect, socket upgrade vs connect,upgrade?).

I didn’t try, but I imagine most of LiveView.JS’s in page things should work without a connection too.

1 Like

Haha, this is the complexity and friction people will avoid, if it’s part of Phoenix itself.

Excerpt from @soup’s readme:


  • A consistent developer experience.

All your views are constructed in the same manner, with a mount, handle_params,
etc process flow. The “template render flow” is the same.

  • But not all views really need to be “live”

Some static [sic] pages have no sever state to update. These could/can just be
regular Phoenix controller actions.

  • But, but some views might warrant starting dead and then becoming live.

Reasons against

  • Kinda weird
  • Added complexity with expecting a liveview to never connect?
  • Phoenix 1.7 may unify how templates are put together with the new
    templating engine?

You’re contradicting yourself. In the end my message still stands: You can likely do what you’re proposing here already. Depending on how it should look exactly it might not even require much code to do so.

That was the naive solution I thought of but I think you’ll need to identify the tab with a unique ID. There’s no tab specific in browser storage is there?

Might be well worth including. I can’t imagine too many scenarios where I wouldn’t want them to return to where they are. Unless the page content has changed since they were last there…?

1 Like