ShlinkedIn: A Window Into Web Development With Phoenix LiveView
A closer look at Phoenix LiveView, alongside my first meaningful pull request
I had seriously considered calling this post “We Need Phoenix LiveView,” which would have combined both the “We Need” series I write and the ShlinkedIn one, but there are still some questions I have (though it still may be a good topic for a future article). The answer to why ShlinkedIn uses Phoenix LiveView is that someone named Charlie thought it sounded cool, so he made his own website with it. The result was ShlinkedIn, which once trended on the #1 page of HackerNews, and came to my attention when a podcast episode mentioned it because that episode also mentioned Curt Corginia.
The creator wrote this blog post almost exactly a year ago. This is the second paragraph:
LiveView strips away layers of abstraction, because it solves both the client and server in a single abstraction. HTTP almost entirely falls away. No more REST. No more JSON. No GraphQL APIs, controllers, serializers, or resolvers. You just write HTML templates, and a stateful process synchronizes it with the browser, updating it only when needed. And there’s no JavaScript to write.
One thing that confused me about Phoenix LiveView is whether it was frontend or backend. I posed this question to the ShlinkedIn creators, and they responded with frontend — I trust that they know what they are talking about, considering that they built this, but if I had just gone by the blog post above it would sound a little bit like some kind of hybrid. In the very first sentence, the creator writes that “it solves both the client and server in a single abstraction.”
The code above certainly does not look like any frontend I have ever seen, and yes…what I am looking at above DOES seem to be part of Phoenix LiveView. It seems that the stack ShlinkedIn uses is fundamentally different from what one might describe as “typical web development.”
From the creator of Phoenix LiveView, again:
Think about how a normal web application works. Everything is stateless. When a user does something, you fetch the world, munge it into some format, and shoot it over the wire to the client. Then you throw all that state away. You do it all over and over again with the next request, hundreds or thousands of times per second. It worked this way in PHP and Perl::Mason, and it still works this way in modern frameworks like Rails.
But Elixir can do stateful applications. It allows you to model the entire user visit as a cheap bit of concurrency on the server, and to talk directly to the browser. We can update the UI as things happen, and those updates can come from anywhere — the user, the server, or even some other server in our cluster.
You don’t want to build applications in Elixir the way you would in other frameworks.
This post by a different person says things a lot more simply, in my opinion. You “add dynamic, client side interactions to web pages using code that runs in Elixir on the server.” If you want to do basic form validation for an email sign-up, for example, there is no need to write JavaScript, bundle it, develop a backend, expose an API, implement client-side validation…LiveView just handles it.
Once again, this would make for great material in a second blog post called “We Need Phoenix LiveView.” For the time being, I am going to state questions I still have and then transition to the next section.
- Why do you keep saying I don’t need JavaScript? I am looking right now at a file called app.js, which seems to be tied to Phoenix LiveView as well (just attached another good Medium article about this)
- Is it wrong to say that Phoenix LiveView is both frontend and backend? Is it simply frontend?
- You talk a lot about how this was inspired by React.js, including live reload. How exactly is this better? If it scales better, why is that? If it does away with HTTP, REST, and JSON, what are the problems with the three?
The Problem
Issue: The “Excessive Spacing” button does not seem to do anything. This button section was designed to mock annoying and/or condescending LinkedIn posts by inserting arbitrary emojis and poor formatting, but the “excessive spacing” button was not working
The suggested solution: The “excessive spacing” actually relies on paragraph breaks. If there are no such breaks, I was asked to trigger a simple alert
Skills I THOUGHT this would require: Elixir, Phoenix LiveView
Skills This Ended Up Requiring (unless they reject the PR): HTML; unbelievably simple JavaScript
There is a file called form_component.ex that triggers an alert message. I thought this was where I would do my work, but it occurred to me that app.js should have error handling capabilities as well.
Okay, excellent. Done. If you try to use the “excessive spacing” button, and there are no paragraph breaks, trigger an alert. But wait a minute. ShlinkedIn is a PROFESSIONAL WEBSITE. These developers have STANDARDS. Sure, true, if ShlinkedIn were a real company and not a parody site someone developed in his spare time as a side project, I would have been fired by now for spending six weeks writing blog posts instead of coding. As a blogger, though, I can live my unrequited dream of being a tech journalist for a fake software company.
So…how to do this?
Well there was styling defined in yet another file, called form_component.html.leex. I could just copy the styling from that. Underneath that…um…puzzle button above (not quite sure what the point of it is) I could define a new HTML tag, give it an id, then write some really simple JavaScript to access the component.
Yes, it has a Stackoverflow link. Shut up.
This is app.js above. The first two lines were already present, and the sole purpose is to turn single spaces into two, but match is…
WAIT, WHY AM I USING VAR? Ugh. Okay, so maybe this should get another commit just to not use var, which I maybe did because the StackOverflow post also did it, which is why you should not do as I just did and blindly copy something from StackOverflow…and maybe this guy should get another space. But in the end, I got my result:
Wait, that’s not right. Try it again.
There we go.
At first, the button did not seem to do anything. I even used a sandbox just to see if things worked as I intended. The idea seemed simple enough: use a paragraph tag with an id, then in your JavaScript portion use getElementById to grab said id and then modify innerText.
The final hurdle…other than the two new things I just discovered, I suppose…is that I was still using alerts just to do my own personal tests. I took those out, and all was well.
Next Steps
Yeah, more commits.
I have not heard anything about the two PRs I submitted: This, and some very low hanging fruit to change master to main because some documentation refers to “master” and some to “main.” One contributor has responded, but the one with merge permissions has not responded.
This is maybe because he is a full-time software engineer, as well as a person who presumably has a relationship, friends, and an actual life…
But no, I will keep going. If my two pull requests have not been approved or rejected, I do not see how it will help if I try to submit even more. I have my own fork, though, and I am fully capable of continuing.
Next is a more meaningful feature: An undo button. I wrote at length last time about how complex an undo button could be, but then it occurred to me that it might be quite simple. An undo button is usually hard because there is no universal definition for what it does: If you type a sentence, does it erase one character at a time? Here, it just needs to work on buttons.
I can just use counters.
Finally, this guy has a server side and database. If I get into that, I can be ShlinkedIn full stack.