I think a lot about building a web app friendly from desktop to mobile. I’m convinced by the fact managing the state as much as possible in the back-end is a very nice approach to minimize work and bugs. Maybe you guessed, I think about LiveView to communicate between the back-end and the user UI.
My wish:
on desktop, the experience is nice via web browser
on mobile, the experience is nice via web browser
on mobile, the experience is nice and encouraged via a mobile app (main topic of this post)
I see two different approaches to design the mobile experience via a mobile app reusing the Phoenix Liveview powered views:
building a PWA (Progressive Web App), however I’m not sure it is pragmatic with LiveView SSR
building two minimal hybrid mobile apps (Android and iOS), with features written natively for tiny generic features (like splash screen, notifications, no network behavior, etc.) and pushing the main content as a web view (see this exemple or this other one I found writting this)
Do you have some experience feedbacks on this in the Phoenix/LiveView ecosystem?
The second option take inspiration from this talk by Sam Stephenson from Basecamp about how they used Turbolinks (now named Turbo) to serve their web app from desktop to mobile via Rails SSR.
PS: note I already watched about LiveView Native which is seems considered as R&D right now, my point here is web based content.
To me the most promising solution right now looks to be using liveview and svelte together.
Svelte is a disappearing framework with none of the react framework overhead or virtual dom inefficiencies and includes an excellent approach to transitions, animations, scoped styles and client side state management. I think it’s a perfect match to enriching liveview based apps. Even if I was doing pure JS apps or native apps (i.e. Svelte Native) I would be reaching for Svelte regardless.
Anyone who would indulge using JS hooks or alpine.js in Liveviews should seriously look at live-svelte as a superior approach. Live-svelte is not doing anything mysterious or magical and merely matures the very straightforward liveview approach as described in the blog post by Ryan Cook.
Another framework that is at the very early development stage is Hologram. It is likely to be some time before it is truely viable but the approach is certainly very interesting and it is being used by the developer for a production site. Definitely worth watching.
I have the code on GitHub (I’m on mobile now), but it’s buried in a branch and I can get you the code if needed, but I don’t have a working implementation. I would like to resurrect it though, for situations like this.
I made a basic app with nav buttons at the bottom (it was a todo list). One for Todos, one for User stuff. Above that, was a WebView widget that contained that actual Phoenix/LV application.
In the Phoenix application, I could detect a custom HTTP header sent by the mobile WebView to know if it was in a “mobile native” environment. (There were other ways, but that’s what I settled on.)
Then you could use a sort of Javascript-based message passing to communicate between the web application container and the native mobile app. It was reasonably simple once I figured it out. The app worked as expected on both iOS and Android, all in a relatively simple wrapper application.
If you go down this route, note the first-party Flutter WebView dependency is laggy and under-featured. There a popular third-party dependency that does the WebView thing much better. You’ll recognize it when you see it.
It would be great to understand what’s needed before it can be a full liveview replacement as it opens up a range of possibilities that are not possible with the liveview design.
I was also thinking it would be great to separate the transpiling and JavaScript runtime into a separate package. Although it probably wouldn’t be useful unless the goal was full Erlang VM compatibility on the client.
What are the current language and runtime restrictions of your implementation? Eg can you spawn processes, genservers, supervisors on the client?
Regardless, I think if you manage to get some traction and people succeeding with real world production apps using Hologram then it could be one of the next big things for developing Elixir web applications.
In the initial version, the complete Elixir syntax will be available, excluding elements related to processes (e.g. the “receive” keyword), supervisors, and anything specifically tied to the server, such as filesystem access. Besides the Elixir syntax, you’ll have access to the standard Elixir library, automatically transpiled for your convenience. In later stages, I plan to delve into parallelism using the Web Workers API. However, in my opinion, due to Hologram’s architecture (action/command), processes won’t be as beneficial, and 99% of the work you perform won’t require them. This is because, on the client side, it primarily involves input processing and state updates. Parallelism/concurrency would be more beneficial if you intend to process files on the client. For asynchronous tasks, you can simply employ Hologram commands, running on the server with full access to Erlang VM functionality.
That is very interesting, however do you think that introducing a subset of elixir that gets transpiled is beneficial?
I mean having a functional language on frontend is great, however missing so many crucial features makes it a completely different language, this also includes libraries that use supervisors/processes that will be incompatible.
Bit of a necro, but IMO, from recent experience this is probably the most pragmatic approach to get started. I added PWA support to a LV app recently, and it took maybe a weekend.
The PWA Builder report card was very helpful, and their docs are ok. That helps you craft a single web_manifest.json file, and the rest is getting a no-op service worker registered correctly in your app’s assets and build process. That’s all it takes to have a trivial-to-execute mobile/desktop experience.
The LV SSR experience works as fine as any backend-state-heavy application on mobile, which is to say, it degrades fast based on network connection. But I would say the value of getting something onto mobile quickly, and then validating if your actual users even have connectivity constraints, or actually require full OS integration, is very valuable.
Diving into a radically more expensive and complicated approach to application development is still on the table, but PWAs can get a Phoenix and LV app out there much quicker, cheaper, and are easier to maintain. Worth trying!
The ultimate goal is to incorporate processes and supervision on the client side as well. Remember, Rome wasn’t built in a day, and we have to start somewhere Even if processes turn out not to be feasible on the client, I still see significant value in this approach: the development team doesn’t have to use JavaScript, and there’s no need for hooks or something like the JS module in LiveView (or Alpine JS, for that matter). Even if Hologram was only a subset of Elixir (which it won’t be, since the entire syntax will work, except for “receive”), this opens up new frontiers. See what NX could achieve with a similar approach. Not to mention all the advantages related to managing the state on the client instead of the server (check it out here: Hologram - full stack isomorphic Elixir web framework - #17 by bartblast).
Besides, I don’t believe that processes will be particularly helpful with this client/server component architecture (except for background file processing). This is because the client will only be used for managing the UI (with JavaScript/DOM being inherently single-threaded). Hologram will intelligently know which code runs on the client and which on the server, so you won’t have to create separate modules for each of them—it’ll be kind of seamless. I know it might sound a bit abstract, but I hope this will be clearer once I create a demo app.