Creating a Local-First Offline-Enabled LiveView PWA with Tony Dang


Summary

Tony Dang, a web developer with a mechanical engineering background, shares his experience building a to-do application using Phoenix LiveView that functions offline. The project was born from a personal need: Tony frequently lost internet connection in his apartment elevator and parking garage, preventing him from using his existing to-do app. He decided to rebuild the app with LiveView while adding offline capabilities, leading him to explore CRDTs (Conflict-Free Replicated Data Types) and the Yjs library.

Tony explains the core problem CRDTs solve: merging changes from multiple offline clients once they reconnect without conflicts. He implemented his solution using Yjs, a JavaScript CRDT library, and integrated it with LiveView via the LiveSvelte package, which allows Svelte components to be updated through LiveView socket assigns. This approach enabled him to cache HTML and app state locally, allowing the app to function without a WebSocket connection.

The discussion covers the trade-offs of his implementation, including performance considerations (sending the entire CRDT state on each change) and technical challenges like handling stale CSRF tokens when reconnecting. Tony also touches on the broader local-first movement, suitable use cases (productivity apps, music players), and the recent emergence of an Elixir port for Yjs that could enable more efficient updates.

Finally, Tony reflects on his journey into Elixir, the appeal of Phoenix’s batteries-included approach compared to JavaScript decision fatigue, and shares recommendations for other Elixir packages he finds valuable, such as Req, Oban, Joken, and Hammer. He also mentions Inertia.js as another option for connecting Phoenix backends with JavaScript frontends.


Recommendations

Libraries

  • Yjs — A CRDT library in JavaScript that Tony used to manage the state of his offline to-do app, enabling conflict-free synchronization between clients.
  • LiveSvelte — A library by Wout that seamlessly integrates Svelte components with Phoenix LiveView, allowing Svelte to be updated via LiveView socket assigns.
  • Inertia.js — A library that connects any backend (like Phoenix) with any JavaScript frontend (React, Vue, Svelte), allowing server-side routing and prop passing. An Elixir adapter exists.
  • Req — An HTTP client library for Elixir, recommended by Tony for making HTTP requests.
  • Oban — A robust background job processing library for Elixir, which Tony uses and recommends.
  • Joken — A library for working with JSON Web Tokens (JWT) in Elixir, used for signing and verifying tokens.
  • Hammer — An Elixir library for adding rate limiting to routes in Phoenix applications.

People

  • José Valim — Creator of Elixir. Tony mentions José’s quick response to his first PR on the Elixir docs, which gave him a great first impression of the community.
  • Wout — Creator of the LiveSvelte library, which inspired Tony’s project by enabling Svelte and LiveView integration.
  • Ryan Cook — Gave an ElixirConf talk that inspired Wout to create the LiveSvelte package, showing a chain of inspiration in the community.
  • Derek Reimer — Creator of the Inertia.js adapter for Phoenix and founder of SavvyCal, an Elixir-backed startup using Inertia.

Projects

  • Phoenix Presence Visualization — A fun app idea Tony has: visualizing Phoenix Presence connections as floating particles that create a ‘flame’ effect as more users connect, potentially made to work offline.
  • Sync (by José Valim) — A prototype for offline sync presented at ElixirConf. Tony is aware of the repo but hasn’t explored it yet; it represents related community exploration.

Topic Timeline

  • 00:00:00Introduction and Tony’s Background — Hosts Sundy Myint and Owen Bickford introduce the episode and guest Tony Dang. Tony shares his background as a former mechanical engineer who transitioned to web development, self-teaching in 2020. He recounts his first impression of the Elixir community when José Valim responded to his documentation PR within 10 minutes, sparking his enthusiasm for the language.
  • 00:03:28The Offline To-Do App Problem — Tony explains the personal motivation behind his project: he lives in an apartment where daily elevator rides and parking garage visits cause internet dropouts. He built a to-do app in JavaScript that failed offline, prompting him to rebuild it with Phoenix LiveView and solve the offline problem. This led him to explore CRDTs for state synchronization.
  • 00:05:47Explaining CRDTs and the Offline Solution — Tony defines CRDTs (Conflict-Free Replicated Data Types) as data structures that allow merging changes from disconnected clients without conflicts. He gives a simple example using ‘last write wins’ based on timestamps. He clarifies that LiveView itself cannot work offline without a WebSocket, so his solution uses JavaScript (Svelte via LiveSvelte) to handle interactions and cache state locally when disconnected.
  • 00:09:54Technical Implementation with Yjs and Svelte — Tony details his tech stack: Yjs for CRDT state management and LiveSvelte for integrating Svelte components with LiveView. He notes there’s no schema duplication because the entire app state is stored as a Yjs document. However, his current implementation sends the full state on every change, which is not optimal. He mentions a new Elixir port of Yjs (wrapping a Rust version) that could enable sending only updates for better performance.
  • 00:22:34Use Cases and Challenges of Local-First Apps — The conversation explores suitable applications for local-first/offline patterns, such as productivity tools and music apps, where instant local feedback enhances UX. Tony acknowledges challenges like handling merge conflicts across devices. He also discusses the trade-off between using established libraries like Yjs versus building custom CRDT algorithms, and touches on concepts like hybrid logical clocks for ordering events in distributed systems.
  • 00:32:00CSRF Token Challenge and Future Exploration — Tony presents a technical hurdle: his app caches HTML including a CSRF token, which becomes stale after some time, forcing a page reload to re-establish the WebSocket connection. He’s exploring Phoenix channels to better understand authentication and token handling. The hosts invite community input on solving this issue and discuss the balance between using LiveView’s JavaScript hooks and embracing full JavaScript frontends when needed.
  • 00:38:52JavaScript Integration and Framework Choices — Tony discusses when to reach for JavaScript within a Phoenix app, noting his preference for using JavaScript frameworks (like Svelte) for the frontend due to the larger ecosystem. He contrasts the decision fatigue in JavaScript (choosing frameworks, meta-frameworks, libraries) with the batteries-included approach of Phoenix, which attracted him. He also highlights Inertia.js as a useful library for connecting Phoenix backends with any JavaScript frontend.
  • 00:45:18Package Recommendations and Closing — Tony shares Elixir packages he recommends: Req (HTTP client), Oban (background job processing), Joken (JWT handling), and Hammer (rate limiting). The hosts thank Tony, encourage listeners to connect with him, and wrap up the episode.

Episode Info

  • Podcast: Elixir Wizards
  • Author: SmartLogic LLC
  • Category: Technology Education How To
  • Published: 2024-10-31T10:00:00Z
  • Duration: 00:48:18

References


Podcast Info


Transcript

[00:00:00] Welcome to Elixir Wizards, a podcast brought to you by SmartLogic, a custom web and mobile

[00:00:17] development shop.

[00:00:18] This is season 13, The Creator’s Lab, where we’re talking to innovators who are expanding

[00:00:23] what’s possible with Elixir, groundbreaking projects, tools shaping the future with our

[00:00:28] favorite technology.

[00:00:30] It may seem like magic, but it’s really the result of talent and lots and lots of hard

[00:00:34] work.

[00:00:36] Hey, everyone.

[00:00:37] I’m Sundy Myint, software engineering manager at Cars Commerce.

[00:00:41] And I’m Owen Bickford, staff engineer at SmartLogic.

[00:00:45] We are your hosts for today’s spooky episode.

[00:00:49] For episode three, we are joined by Tony Dang, creator of Local First, LiveView, Svelte,

[00:00:55] PWA, and Web Dev Enthusiasts.

[00:00:58] Hi, Tony.

[00:00:59] How are you?

[00:01:00] Hi, everyone.

[00:01:01] Is this where I was supposed to introduce myself?

[00:01:04] Yes.

[00:01:05] All right.

[00:01:06] Hi, everyone.

[00:01:07] My name is Tony.

[00:01:08] I am a web developer from the Bay Area in California.

[00:01:13] And I guess my background is that I used to be a mechanical engineer and engineering project

[00:01:19] manager for about 10 years.

[00:01:21] And it was around 2020 when I decided I needed a break and a change.

[00:01:27] And I decided to self-teach myself.

[00:01:30] And I think like most people, I started in the JavaScript space.

[00:01:36] And then I also dabbled a little bit in Python, PHP, and a little bit of Ruby before I finally

[00:01:42] discovered Elixir.

[00:01:45] And I think since today is the 17th of October, I can still say that I have less than a year

[00:01:53] of Elixir experience.

[00:01:55] And the reason why I say that is because the first day I started, I was like, I’m going

[00:01:59] to do this.

[00:01:59] I’m going to do this.

[00:01:59] I’m going to do this.

[00:01:59] learning Elixir was October 25th. And I remember that because I made this PR when I was going

[00:02:06] through the official docs. I saw a little error, so I made a PR to fix it. And within 10 minutes,

[00:02:13] I got a reply from Jose. And I was like, whoa, this is really awesome that the creator of Elixir

[00:02:18] would respond within 10 minutes of me opening this PR. And it really gave a really good first

[00:02:24] impression of the Elixir community to me. And yeah, ever since then, I’ve been writing Elixir,

[00:02:31] trying to learn as much as I can. And yeah, that’s why I’m here today.

[00:02:36] So dear listeners, when you hear this, Tony will have been in this fully for,

[00:02:41] sorry, how many years did you say?

[00:02:42] One year.

[00:02:43] One year? Hold on.

[00:02:46] One year.

[00:02:47] One year.

[00:02:48] I heard you say that, but I thought we’ve known each other for longer than a year. That’s not true.

[00:02:53] No, it’s not.

[00:02:54] Okay. Well, back up to that, but happy Halloween, everyone. If you’re listening to this on the day

[00:03:00] that this releases, but that is also the day that is six days after PR. That is incredible.

[00:03:07] And so I guess the mechanical engineering background gives a little bit of that.

[00:03:11] That’ll be interesting to dig into also, because I see what today we’re talking about

[00:03:15] offline enabled real-time app using Phoenix, LiveViews, Felt, and CRDTs, which

[00:03:20] I don’t love acronyms. So we’re going to expand on that.

[00:03:23] But yeah, this should be really interesting.

[00:03:24] Interesting. Owen, anything to add there?

[00:03:28] Yeah, actually. So if you’re watching us on YouTube, welcome to the party. This is Halloween.

[00:03:34] Happy Halloween. We’ll dig a little bit into CRDTs and the project that you worked on.

[00:03:41] I’m curious at a higher level, I can already kind of see how CRDTs might be useful for like

[00:03:48] maybe a factory or some kind of embedded systems where maybe you’re offline most of the time,

[00:03:53] but things are happening.

[00:03:54] And you want to keep track of those even when they’re, when your site is offline for whatever

[00:03:59] reason. Is that kind of a, is that a consideration for some of the stuff you’re doing or a driving

[00:04:05] force or was it more just, I want to play with some toys?

[00:04:10] I think it’s probably the latter. And I really was just interested and it was solving a real

[00:04:15] problem that I had. The app that I built was something that required offline capabilities.

[00:04:22] So just to back up a little bit, I think one of the reasons,

[00:04:24] why I’m on this podcast today was because I built an app with live view and I also made it work

[00:04:32] offline. And this app for some background is a to-do app. So it seems like a very simple thing,

[00:04:39] right? A simple to-do app. However, the reason why I wanted to make it work offline is because

[00:04:45] the to-do app is an app that I actually use personally myself. And I happen to live in an

[00:04:52] apartment complex where every day, I have to do a lot of things. And I have to do a lot of things.

[00:04:54] I would have to go up and down this elevator. And every single time I go up and down the elevator

[00:04:59] to enter and leave the building, I would lose internet connection. And also when I’m in the

[00:05:05] parking garage, no cell reception. So, and usually I just happen to always be on my phone checking

[00:05:12] off my to-do list as I’m going down this elevator. And the fact that it doesn’t work really annoyed

[00:05:17] me. This is an app that I built before I built my offline version. And it was just an app that

[00:05:23] I built in JavaScript.

[00:05:24] But when I was learning Phoenix LiveView, I decided I wanted to rebuild the app,

[00:05:30] but also make it work offline. So that was the impetus for making an app that worked

[00:05:36] offline using CRDTs is because I had this issue that I was trying to solve.

[00:05:42] Okay, I’ve let this go on too long. You got to define that acronym.

[00:05:45] We need a segment.

[00:05:47] Define that acronym.

[00:05:47] Yes. All right. So CRDTs, it stands for conflict-free replicated data type.

[00:05:54] And honestly, it sounds like a big mouthful. I think I can try to explain it. So let’s get back

[00:06:01] to first what the problem is, right? The problem that CRDTs solves is, let’s say you have a Google

[00:06:09] Doc that the three of us are collaborating on. And let’s say at some point in time, we all get

[00:06:17] disconnected from the internet. So we’re all working on this Google Doc, but we’re all offline.

[00:06:23] So I make some changes.

[00:06:24] Sunday makes some changes.

[00:06:26] Owen makes some changes. And now we all have different changes locally.

[00:06:31] Then what happens when we all reconnect, right? When we all reconnect, now we have three different

[00:06:36] states that may or may not be in sync with each other. And that is the problem that CRDTs try to

[00:06:44] solve is how do you merge all of these changes in a way that results in no conflicts? And there

[00:06:53] are many ways.

[00:06:54] There are many different CRDT algorithms out there. But one of the simplest ways, the most simple

[00:07:01] CRDT example I have would be, let’s say I edit the document at 1pm, and then Cindy edits it at 2pm,

[00:07:10] and then Owen edits it at 3pm. So one possible algorithm is to just use last write wins. So in

[00:07:20] this case, Owen’s changes will win because he edited the document at 3pm. And then he edits it at

[00:07:24] the latest timestamp. So hopefully that explains CRDTs a little bit better.

[00:07:30] Yeah, I think so. Okay, so backing it up a little bit, you’re going into an elevator,

[00:07:36] you’re losing your internet service or just cell service, can’t make it through your to-do app.

[00:07:44] Why? Why would you, I guess this is a silly question, maybe, but like, why would you even

[00:07:49] attempt to make a to-do app in an application?

[00:07:54] That traditionally cannot work without internet connection? Like, why even go that route?

[00:08:00] And I think the answer to that is simply because I was in a state where I wanted to learn Phoenix

[00:08:05] and LiveView. And I could build my app with some other technology, but I am, I wanted to learn

[00:08:13] Phoenix and LiveView. And it just so happens that I have this other issue that I have to solve at

[00:08:18] the same time. So that’s the reason. Okay, because yeah, for context for the audience,

[00:08:24] when Tony first presented this application, I was like, you are brand new to Elixir. And you’re

[00:08:30] literally doing the thing that the technology says it can’t do. You are attempting to do it.

[00:08:35] And I was like, that is the boldest thing. And I love it. And I was like, we have to have,

[00:08:41] we have to have a conversation about this. So what did you learn while going through that?

[00:08:45] A lot, of course, I learned a lot about how LiveView works under the hood. And I think I

[00:08:52] pretty much learned how…

[00:08:54] To make LiveView. Well, again, I think saying making LiveView work offline is not entirely true

[00:09:03] because LiveView requires a WebSocket connection in order to work, right? So really what’s happening

[00:09:09] is we’re enabling a LiveView application to have a fallback to work offline. But LiveView itself

[00:09:18] doesn’t actually work offline because there is no WebSocket connection.

[00:09:23] So when I…

[00:09:24] When I say a LiveView app that works offline, it just means that when there is no internet

[00:09:30] connection, the app will still work. And the reason why the app still works is by basically

[00:09:37] writing JavaScript, right? JavaScript is the one language that will work in the browser when there

[00:09:44] is no internet connection. And therefore, that’s the solution to the problem. And in my app, I

[00:09:50] particularly use a framework called Svelte.

[00:09:54] And the reason why I use that framework was because there is a library out there called

[00:10:00] LiveSvelte. And this library is made by another community member named Wout. And he basically

[00:10:07] was able to get Svelte and LiveView working seamlessly together so that you can write

[00:10:17] a Svelte component in JavaScript, but you can update it using the socket assigns,

[00:10:24] from LiveView. And because the integration was so seamless, it allowed me to use Svelte,

[00:10:31] but it also allowed me to learn LiveView at the same time.

[00:10:36] I think you’re touching on a couple of things. I know that, you know what, LiveView was debuted

[00:10:41] 2017, 2018, if I remember correctly, like in its kind of demo form. And it probably had been in

[00:10:48] progress. Work had been done, I’m sure, for at least a year before that. And one of the first

[00:10:53] things I think we all know is that LiveView is a very, very, very, very, very, very, very, very,

[00:10:54] understood was that, and the pitch was, we’re trying to simplify the stack, write more code in

[00:11:00] a single language so that you’re not having to cross the transom and context switch between

[00:11:06] languages. That’s like the selling point for us as developers. There were a couple of limitations

[00:11:11] that came with it. Offline support is a no-go, just because everything you said. In order to

[00:11:17] have a LiveView, you’ve got to be connected to the WebSocket. And you can’t have a WebSocket

[00:11:22] if you’re not online.

[00:11:24] And also, at least initially, this was an effort to reduce or eliminate almost all the JavaScript

[00:11:32] that you would have to write. Something that’s interesting that’s happened in the years since

[00:11:36] is that actually we’ve gained more tooling to be able to execute JavaScript, like just small

[00:11:43] snippets when we need it for copy-paste, for toggling attributes, and then also for hooking

[00:11:48] into more advanced JavaScript, whether it’s browser APIs or some other frameworks that we’re

[00:11:53] talking to.

[00:11:54] So I think what’s interesting here is that you’re also pushing the boundaries on, as a brand-new

[00:12:01] Elixir developer, on what a LiveView application can do whenever it can’t talk to the server.

[00:12:08] And this is something that we’ve seen, I think, even at ElixirConf. Jose had part of his talk was

[00:12:12] dedicated to a sync kind of prototype that he was experimenting with. Have you looked at that repo

[00:12:18] at all? Do you know anything about it? Is there some rhyming that’s happening with what you did

[00:12:22] and sync and lives?

[00:12:24] Yeah. So unfortunately, I haven’t had the chance to look. I know about the talk. I saw it,

[00:12:29] but I am still waiting for the talk to be released, actually. So I haven’t had the chance to look at

[00:12:34] it. I did see that the repo was released, though, but I haven’t had the chance to take a look at it

[00:12:40] yet, unfortunately.

[00:12:42] Okay. We’ll have a link in the show notes here. It’s archived. So I think our understanding is

[00:12:48] that this was kind of a pitch to the community, like, here’s some things we can do. This is not

[00:12:53] officially being developed.

[00:12:54] It was like maybe a weekend project or whatever. And we’ll kind of see if someone picks it up

[00:13:00] to carry it forward. But yeah, so I guess one thing that I think we as developers like to do

[00:13:09] sometimes is shove to the side some concerns that we don’t think our users are going to encounter.

[00:13:14] So offline mode is one of those concerns. A lot of us in our community particularly are probably

[00:13:20] guilty, including myself, of saying, oh, offline mode isn’t important.

[00:13:24] The application that’s valuable, that’s worth using, needs to work. We get all these benefits

[00:13:29] from being online. But you raise one great example of, here’s the thing I have to do every day,

[00:13:35] and I just can’t use some of these apps when I’m offline because I’m on an elevator.

[00:13:40] I can think of some other examples where you might be fully offline for a while, or you might

[00:13:46] have intermittent connectivity. So are there other scenarios you can imagine where we have a real

[00:13:52] problem to solve, aside from just online?

[00:13:54] So I followed the local first space a lot. And it’s a community of people who basically

[00:14:01] are trying to build everything offline as much as possible. And what I get the sense is that

[00:14:08] the majority of apps that work best for offline is productivity apps, like apps that really just

[00:14:15] work with your own data. And those are the apps that are basically the best for being offline,

[00:14:21] because you don’t need to worry.

[00:14:24] I’m sure someone might be thinking, maybe it is possible, right? Maybe you can make the purchase,

[00:14:40] and then later on, the transaction goes through later on. Maybe that is possible. But generally,

[00:14:46] I would say that apps that work with productivity software, or maybe like music apps, for example,

[00:14:54] right, those would be perfect use cases for an offline app.

[00:15:00] I think even like a shopping cart, you might have been able to execute the purchase. And like,

[00:15:05] you know, nothing’s gonna happen if you hit a buy button. But if you’re offline, maybe you can edit

[00:15:09] your cart. If you’ve got a cache of some items that you could add, or you know, remove things

[00:15:14] from your cart, I think there’s a potential here for if we’re not writing our entire application to

[00:15:19] be offline, there might still be like slices of an application that could benefit from some of the

[00:15:24] technical bits.

[00:15:26] Yeah, most definitely, because the nice thing about offline local first apps is that the feedback is

[00:15:34] instantaneous, right? Because when we are building something offline, it means that we are writing to

[00:15:41] a local database, which means anything we do should have instant feedback. And that makes for a very

[00:15:48] good user experience. Of course, it also comes with some downsides in terms.

[00:15:54] of development. For example, now we have to worry about the conflicting state, right? Because

[00:15:59] your example with the shopping cart, let’s say someone were to make updates on their shopping

[00:16:06] cart locally, but later on they open up another browser, then their shopping cart might not be in

[00:16:13] sync. So there’s like issues like that that come up as well. So it’s nice when it works, but it is

[00:16:20] also quite difficult to make working as well. Yeah, I’m curious. So you, I was watching speed

[00:16:29] running the video where you’re showing the live view and database syncing from the browser and the

[00:16:34] server. And so there may be some technical bits in there that I haven’t caught yet, but I’m curious

[00:16:41] how much you have to replicate either state like schemas, like do you have to like define your

[00:16:48] schema on the server? And then also,

[00:16:50] define it in Svelte. Like how much duplication are you getting back into by supporting offline?

[00:16:56] Yeah, so there’s actually not much duplication at all, because in the app that I built, I am using

[00:17:02] a library called Yjs. So Yjs is a CRDT library originally built in JavaScript. And it basically

[00:17:11] comes with this data structure that keeps the state of your app. And this entire data structure

[00:17:18] is just sent to the server. And then you have to do a lot of work to get it to work. And so

[00:17:20] there’s actually no duplication. So I am not making a different, for example,

[00:17:25] actual schema or anything to keep this data. Everything is actually stored as a Yjs document.

[00:17:33] So there is actually no duplication. That being said, though, I would say that the app that I

[00:17:40] built does have some flaws in terms of performance. The way that the app works right now,

[00:17:47] since I was trying to keep it simple, was,

[00:17:50] every single time you make a change to a to-do list, you would send the entire CRDT state

[00:17:58] from the client to the server. And then if there are any connected clients,

[00:18:03] then the server will send that entire state down to all the connected clients.

[00:18:08] So you’re basically sending your entire app state back and forth throughout the various clients.

[00:18:13] And it’s definitely not the most performant way to do it. Ideally, what you would do is you would

[00:18:19] only send updates. So you would only send updates to the server. And then you would send the entire app state

[00:18:20] to the server. So what would happen in the ideal scenario is when you start up your app,

[00:18:26] you will create your state on the client, and then you send the initial state to the server.

[00:18:33] And then following that, every single time you make a change on any client,

[00:18:38] you will only send the update of the change up to the server. And that’s a much more performant

[00:18:44] way to do it. But the reason why I didn’t do that, one is the way I did it was,

[00:18:50] it’s much simpler. But then the second reason is because of the need to run Yjs on the server.

[00:18:56] Because if you were to send updates from the client to the server, then when you send the

[00:19:01] update to the server, you need to somehow be able to merge the state on the server with the update

[00:19:08] that you sent to it. And this would be possible if you can run Yjs on the server side. And it is

[00:19:15] possible to run Yjs server side because there is, you can run the JavaScript library server,

[00:19:20] but at the time in which I made the app that I did, there was no Elixir port.

[00:19:26] Since then though, as of I think a couple of weeks ago, there was another community member

[00:19:31] who made a Yjs port to Elixir. Besides the JavaScript port, there’s actually a Rust port

[00:19:40] of Yjs that was also made by the creator of the original JavaScript Yjs version.

[00:19:47] And the Elixir port is actually a Rust port.

[00:19:50] It’s a wrapper around the Rust port so that you can run the Rust version of Yjs on an Elixir server.

[00:19:59] How recent was that?

[00:20:01] So that was like a couple of weeks ago when I first learned off the library, the Elixir port.

[00:20:08] Okay, cool.

[00:20:09] Yeah. So I haven’t implemented this in my app yet. I’m just saying that

[00:20:13] if I were to do it again today, I would probably pursue that solution.

[00:20:20] It’s funny. That happened to me in the past year. We did some work to, there’s a package

[00:20:26] that we’re using for generating, let’s say PDFs. And the way we had written all the templates

[00:20:32] was not compatible with that package. Did a bunch of work, probably took two months to

[00:20:38] like kind of refactor things. So to support that version, literally the next week they

[00:20:44] announced support for everything that we had in the system originally. So it’s kind of funny.

[00:20:49] Yeah.

[00:20:50] You just have to laugh once you’ve spent a bunch of engineering time

[00:20:52] kind of shoehorning things into the thing and then they obviate all the work you just did.

[00:20:58] Laughing is better than crying, Owen.

[00:21:00] No, but at least you made it work though, right? And you got it working sooner than

[00:21:04] you would have if you had waited.

[00:21:06] You are a better engineer today.

[00:21:09] Yes.

[00:21:10] Maybe.

[00:21:11] That’s how you have to look at those.

[00:21:14] Yeah. I was just thinking off this one Joel Armstrong quote. I’m not sure if you’re

[00:21:19] familiar.

[00:21:20] The one that goes, first make it work, then make it beautiful, then make it fast. Right?

[00:21:27] So I think that quote really resonates with me because in the app that I made, I made

[00:21:36] it work. So it works offline and I made it aesthetically pleasing to myself so I can

[00:21:42] use it, but it’s not the most performant. But I’ve been using this app pretty much weekly

[00:21:49] since I,

[00:21:50] I made it and I think I first released it in about February of this year. So I don’t

[00:21:56] know how long that has been. And I haven’t had any issues really performance wise. One

[00:22:02] thing that is happening is that the payload size of the data going back and forth through

[00:22:08] the WebSocket is definitely growing as the more I use the app. However, everything is

[00:22:14] still working fine. And honestly, I feel like I want to push to see how far I can go with

[00:22:19] the app.

[00:22:20] As is before I need to make any performance optimizations.

[00:22:25] Cool.

[00:22:27] Yeah, I, so you talked about the simple algorithm last right wins. I’ve done a little bit of

[00:22:34] reading up on CRDTs over the past few weeks as well. And local first development, finding

[00:22:39] the same thing that you’re finding like, yeah, it works great for think an obvious easy use

[00:22:44] cases like single user productivity apps. Linear dot app is actually a project

[00:22:50] management tool that I think has gained a lot of success as a local first app and that

[00:22:55] even supports teams of people. I think I’m curious, there are other algorithms. Could

[00:23:01] you touch on maybe some other technical solutions you might need to consider? For maybe last

[00:23:07] right? When is the thing you actually need for a particular feature? Are there alternatives

[00:23:11] to that?

[00:23:12] There are alternatives, but I’ll be honest that I am completely not an expert

[00:23:16] in this. So I also just started looking at a couple of things. I have a question about,

[00:23:17] you know, if I create a web-based app or if I create a web-based app, do I want to have

[00:23:18] to have a web-based app? Does take a lot of time to get it up to date with the real

[00:23:19] Mongo I am hopefully not an expert in this. So I also just started looking a couple things. And,

[00:23:19] things up before this podcast so i’m aware but i am definitely not an expert so my the one i know

[00:23:27] the most is the last right wins because before using the yjs library i actually implemented my

[00:23:32] own crdt using a last right win algorithm then when i switched over oh so let me back up the

[00:23:40] reason why i switched over to yjs was because as i was writing my algorithm i realized that it was

[00:23:47] getting very complex to make sure you hit all the edge cases and not only that you have to make it

[00:23:52] performant and a battle-tested library like yjs pretty much did all the work already and i didn’t

[00:24:00] want to have to reinvent the wheel i have not since looked at many other solutions first up

[00:24:07] besides yjs there are a lot of other crdt solutions in the community but i would say the two most

[00:24:15] popular ones at the moment

[00:24:17] are

[00:24:17] and another library called auto merge and in terms of how they implement their crdts though

[00:24:25] i am actually not aware of the exact algorithm they use behind the scenes so i really can’t

[00:24:30] say much about that sunday did you know that you’ve been using crdts this whole time no but

[00:24:36] that’s kind of the true of everything that’s got an acronym i don’t know i’m using it if i remember

[00:24:42] correctly there’s some portion of the live view stack i don’t know if it’s like

[00:24:47] presence or pub sub or if it’s actually unlike you itself that has some crdts to manage state

[00:24:52] and updates over time do you remember tony where that might be

[00:24:59] yes i i believe it’s part of the phoenix presence uh that there is some crdts being used for that

[00:25:05] feature of phoenix right okay yep the other piece that i’ve that it’s kind of like a mental tab in

[00:25:15] my mind that i’m going to come back and open up the database next week is a kind of like an open-shop

[00:25:15] or let’s just say there’s a shadows or something that you’re not using this還有 other ways that

[00:25:15] have been used right auf jedenfall ist resurrection зап tease can hopefully i see jesus in what might be

[00:25:15] a really nice combination by the way since i know that into actual figures i mean but if and when you see i want to

[00:25:15] mind that i’m going to come back and open again is hybrid logical clocks one problem that that

[00:25:21] you’ll run into is we’re talking about it essentially a distributed system you got all

[00:25:25] these computers that are using your application they need to synchronize with each other you could

[00:25:30] just assume that the the computer’s clock is accurate and then whenever you get all these

[00:25:37] events once they reconnect then you have to figure out which ones are in order but of course those

[00:25:42] clocks are not trustworthy they may be just inherently inaccurate there’s drift there’s

[00:25:47] people can edit their clocks and stuff so there’s a concept called hybrid logical clocks that will

[00:25:53] essentially take a time stamp and then append it with a hash so that you get a format that

[00:25:59] regardless of what device is coming from you get all these events and they’re time stamped in a way

[00:26:04] that they can always be sorted in a consistent idempotent manner so you always get the same

[00:26:09] order events out

[00:26:11] you

[00:26:12] is that something it sounds like that might be something you roll into the into this application

[00:26:17] potentially if you were to like expand it to grow to more users potentially is that something that’s

[00:26:21] been on your radar honestly no because i i actually feel that the yjs algorithm as is already is

[00:26:29] working really well so i don’t think there is a need to move on to any other crdt structures at

[00:26:35] least for this application honestly a to-do app is it’s quite simple right there’s not really like

[00:26:40] an issue with the application it’s not really an issue with the application it’s not really an issue

[00:26:42] with there’s not too many issues with like merge conflicts because for example like in git right

[00:26:47] when we are we have two different branches and we do a merge and we get a merge conflict it is

[00:26:55] because maybe it is the myth that we made in the past that is actually the one we want to keep

[00:27:01] and not the one that we made in the future which is the latest one whereas i think with yjs if

[00:27:08] something is made in the future it is going to win and i feel like with a to-do app i think it’s going to win

[00:27:12] most likely that is what you would like as well.

[00:27:15] But I can see for other apps,

[00:27:18] you might not want the one that happened in the past to win.

[00:27:21] So in that case, I would think that you would have to explore

[00:27:24] other CRDT algorithms or hybrid logical clocks

[00:27:28] in order to solve the problem.

[00:27:30] Makes sense.

[00:27:32] Any other fun app ideas using Svelte or YJS

[00:27:36] rattling around in there?

[00:27:38] I had this idea of making this app

[00:27:42] and I was just going to call it Phoenix Presence.

[00:27:46] And hopefully that gives you an idea of what it does.

[00:27:48] Just imagine a screen that has a bunch of floating particles

[00:27:53] and each particle represents one person connected to the app.

[00:28:00] So the more people you have connected,

[00:28:02] the larger this bundle of particles grow.

[00:28:05] And you basically get like a flame,

[00:28:07] a flame effect as you get more people.

[00:28:10] So I was thinking of doing something like that

[00:28:12] and also making it work offline as well.

[00:28:15] But this is like an idea that I had.

[00:28:17] I’m not sure when and with if I would have time

[00:28:19] to actually make it happen.

[00:28:22] It’s fun.

[00:28:23] It’s definitely, it would have a wow factor

[00:28:25] if you were to present that at a conference

[00:28:27] in a room full of people who are connecting to it

[00:28:30] and then creating the flame before your eyes.

[00:28:33] But I definitely, I had my fair share of like

[00:28:35] code is art kind of projects.

[00:28:37] I think that’s what I was thinking of when I was in college.

[00:28:39] So that’s kind of what that reminds me of.

[00:28:41] That’s fun.

[00:28:42] Before we circle back to future ideas,

[00:28:44] your to-do app, the current one that you have,

[00:28:46] is that something that is available out there

[00:28:48] for people to use?

[00:28:49] Or is that mostly just a you thing?

[00:28:51] It’s available for other people to use.

[00:28:53] I did not intend for it to be like a production app

[00:28:58] because I have no guarantees on people’s data or anything.

[00:29:01] If someone wants to use it, they can feel free to,

[00:29:04] but at the same time, I’m hesitant to tell people

[00:29:07] to do that because I’m not sure whether or not

[00:29:09] I’ll make any breaking changes in the future.

[00:29:11] That being said, I’ve actually been tracking

[00:29:14] the number of people who have signed up for the app

[00:29:16] since I released it.

[00:29:17] And I checked today and there was 256 people

[00:29:20] who have signed up to test out the app.

[00:29:22] Obviously, I don’t think all of those are people

[00:29:24] who are actually signing in every day.

[00:29:26] I don’t have any tracking to see whether or not

[00:29:28] people are logging in on a regular basis.

[00:29:30] So I’m not sure if there’s anyone else besides myself

[00:29:33] who’s actually using the app regularly.

[00:29:37] You know what’s funny? I just…

[00:29:39] You’re looking for a productivity app, Owen.

[00:29:41] No, no, no. You said 256.

[00:29:44] There’s a pun. There’s a joke in here somewhere.

[00:29:46] I just searched 256. There’s a whole…

[00:29:49] It has its own page.

[00:29:51] There’s a Wikipedia page for the number 256.

[00:29:54] Oh.

[00:29:56] So we’re going to drop that in the show notes as well.

[00:29:58] Okay.

[00:30:00] I don’t know why. I don’t know if there’s anything useful in there.

[00:30:02] All right. No one else sign up for the ToDo app.

[00:30:04] Let Tony have a magical number.

[00:30:07] Yep.

[00:30:08] I mean, I can start weeding out all the bots

[00:30:10] because I can see that, like, some of the emails

[00:30:12] are, like, something at example.com.

[00:30:14] It’s definitely not someone real, but for some of it,

[00:30:16] I can see, oh, this might actually be a real person checking this out.

[00:30:19] It’s a real person.

[00:30:20] Do you know how many times I’ve done Sunday at example.com?

[00:30:23] Well, I mean, like, a real person’s email, right?

[00:30:26] Yeah.

[00:30:27] You know, it’s cool to see that I wasn’t expecting

[00:30:30] to have so many people sign up,

[00:30:33] and it was good to see that this caught

[00:30:36] a lot of people’s interest.

[00:30:38] And I still get a couple of signups.

[00:30:40] Like, pretty much every week, there’ll be one or two new signups.

[00:30:43] So I’m glad that someone out there is finding this useful.

[00:30:46] Yeah.

[00:30:47] And yeah, this kind of rounds back to one of the reasons

[00:30:50] why I shared it in the first place was because,

[00:30:53] as I mentioned, I built this app after seeing

[00:30:58] the Live Svelte package by Welt.

[00:31:01] And I know that he was inspired to make

[00:31:06] his package because he saw an ElixirConf talk

[00:31:09] by someone else named Ryan Cook.

[00:31:12] Basically, I’m hoping that since I was inspired by Welt to make this,

[00:31:16] maybe someone else will see this project

[00:31:19] and get inspired to make something even cooler.

[00:31:21] So I’m hoping that the chain just keeps continuing on.

[00:31:24] Yeah.

[00:31:25] Just keep the train going.

[00:31:27] So speaking of, like, being inspired by Elixir,

[00:31:30] this, the reason, so for, again, for context,

[00:31:33] the reason why I was shocked at the beginning is because

[00:31:35] I feel like when you came to DC Elixir Meetup,

[00:31:38] I guess that was a year ago,

[00:31:40] but in my head feels like 10 years ago.

[00:31:42] So that’s a different problem for a different time.

[00:31:45] And I remember you being new to Elixir.

[00:31:47] You’re now almost a year in.

[00:31:49] Do you have any, like, takeaways, learnings, interesting things

[00:31:53] now that you’ve been in the Elixir space for a little bit

[00:31:56] and, like, any hopes, dreams for the future

[00:31:58] with your development journey with Elixir?

[00:32:00] Like I said at the beginning,

[00:32:02] I think I’m still in the phase where I’m learning a lot.

[00:32:04] So right now, my, the latest project I’m building

[00:32:09] is actually not a live view project at all.

[00:32:11] And that’s because I wanted to learn just, like,

[00:32:13] vanilla Phoenix, so with controllers

[00:32:15] and with Phoenix channels.

[00:32:17] So I’m trying to learn that right now.

[00:32:19] And one of the reasons for that is because

[00:32:23] I wanted to understand how channels work a little bit more

[00:32:26] under the hood, because there is actually one issue

[00:32:29] with my live view offline to-do app.

[00:32:34] That I’ve had, that I haven’t figured out a solution to yet.

[00:32:37] Maybe you can help me with a solution, actually.

[00:32:40] Doing it live!

[00:32:42] Everybody lean in. Let’s hear it.

[00:32:44] So one of the issues is that with this app,

[00:32:49] since it works offline, what’s happening is that

[00:32:53] I am caching the HTML

[00:32:56] so that when there is no server connection,

[00:32:59] the app can still load the HTML from a cache.

[00:33:04] However, what that means is that

[00:33:07] the HTML cache also is caching a CSRF token.

[00:33:12] So, let’s say that

[00:33:16] I am connected to my to-do app

[00:33:19] and I connect to the server. Everything works.

[00:33:22] And then after that, I close my app

[00:33:24] and it goes into the background on my phone.

[00:33:26] One day later, I’ll come back

[00:33:29] and then I’ll try to connect.

[00:33:31] But what happens is that the CSRF

[00:33:34] token is now stale.

[00:33:36] So what needs to happen is that

[00:33:38] you need to do a reload

[00:33:40] and fetch a new token

[00:33:42] from the server

[00:33:44] in order to reconnect your socket.

[00:33:46] And that’s the issue I have,

[00:33:48] is that

[00:33:50] when that reconnection happens,

[00:33:52] there’s going to be this flash

[00:33:54] because you have to reload the page

[00:33:56] in order to get a new token.

[00:33:58] And I’m wondering if there’s any way

[00:34:00] for you to reestablish

[00:34:02] a WebSocket connection

[00:34:04] that the CSRF token is stale.

[00:34:06] This is an interesting problem.

[00:34:08] So, my spidey sense tells me

[00:34:10] this might be the wrong path,

[00:34:12] but the spidey sense tells me

[00:34:14] maybe there’s a way

[00:34:16] that a service worker

[00:34:18] could intercept.

[00:34:20] This is one use case for service workers.

[00:34:22] They’re good at handling

[00:34:24] your network connection state.

[00:34:26] I don’t know if there’s a new API

[00:34:28] that’s just built into the browser

[00:34:30] that would be better for this now,

[00:34:32] but you’re asking,

[00:34:34] whenever you reconnect,

[00:34:36] you want to maybe

[00:34:38] discard the cached HTML

[00:34:40] and just maybe fetch the new

[00:34:42] live view HTML

[00:34:44] and then sync the data.

[00:34:46] So if that’s

[00:34:48] the goal,

[00:34:50] it seems like maybe a service worker

[00:34:52] is one possible

[00:34:54] tool to use.

[00:34:56] There may be some other ways

[00:34:58] to hook into either live view

[00:35:00] directly or a browser API

[00:35:02] There’s also, I can start to imagine

[00:35:04] some really hacky things like

[00:35:06] removing the tag from the DOM

[00:35:08] or something, like removing the CSRF tag.

[00:35:10] I don’t know if that might still blow up

[00:35:12] because then you don’t have

[00:35:14] a CSRF tag at all, but

[00:35:16] in real time, that’s the first

[00:35:18] couple of thoughts that come to mind.

[00:35:20] Gotcha. Yeah, because I was

[00:35:22] looking into this for quite a while

[00:35:24] and I couldn’t figure out a good solution

[00:35:26] because removing

[00:35:28] and re-adding the tag

[00:35:30] would work, but the issue

[00:35:32] I had was that you still need

[00:35:34] to pass the token to

[00:35:36] the Phoenix

[00:35:38] JavaScript client library

[00:35:40] in order to open the WebSocket

[00:35:42] connection. So somehow you have to

[00:35:44] fetch the new token,

[00:35:46] pass it to live view

[00:35:48] or PhoenixJS, and have

[00:35:50] that reopen up a new

[00:35:52] connection. And that

[00:35:54] is the part that I haven’t figured out yet.

[00:35:56] And again, so this is one of the reasons why

[00:35:58] I was looking into just Phoenix channels

[00:36:00] because if you just use

[00:36:02] Phoenix channel without

[00:36:04] live view,

[00:36:06] you control the

[00:36:08] authentication. So you pass

[00:36:10] your own tokens and you can

[00:36:12] determine how you want to authenticate.

[00:36:14] So that’s why I’m looking at that right now,

[00:36:16] just so I can understand that a little bit better.

[00:36:18] And I’m hoping that eventually

[00:36:20] I’ll round back to see if I can make it work with

[00:36:22] live view as well.

[00:36:24] I don’t know if you guys can

[00:36:26] hear it. I can hear people yelling at

[00:36:28] their phones right now, so

[00:36:30] if any of our community wizards, just,

[00:36:32] know the answer and they want to like

[00:36:34] give it to you, how would they do that?

[00:36:36] They can contact me.

[00:36:38] I guess the best way to get to

[00:36:40] me is I have a

[00:36:42] personal website at TonyDang.com

[00:36:44] and basically all my contact

[00:36:46] information is on there. You can send me an email

[00:36:48] or you can send me a message

[00:36:50] via Twitter or GitHub,

[00:36:52] anything. That would be great.

[00:36:54] And we’ll have your socials

[00:36:56] in the show notes. But this will also

[00:36:58] be on YouTube, so I feel like if we want to timestamp

[00:37:00] like the Tony question,

[00:37:02] and just give it a section, if you

[00:37:04] are watching on YouTube

[00:37:06] and you’ve got a suggestion for Tony

[00:37:08] and you feel like you can’t hold it in,

[00:37:10] you have to get it out there, please comment

[00:37:12] and we’ll make sure it gets to Tony.

[00:37:14] Yes, it’ll be very

[00:37:16] much appreciated. I

[00:37:18] have been, like I

[00:37:20] said earlier, I feel like this app is

[00:37:22] pretty much done for now, but I have not

[00:37:24] stopped noodling in my head

[00:37:26] things about how I can improve it.

[00:37:28] Because eventually I know I want to

[00:37:30] make another app similar to this,

[00:37:32] and I would like to make it better in every

[00:37:34] single way. And this is definitely one of the

[00:37:36] areas that I need to figure out still.

[00:37:38] So there’s

[00:37:40] some interesting things to talk about here as well.

[00:37:42] So you’ve already, we’ve been talking mostly

[00:37:44] about adding support for offline,

[00:37:46] using CRDTs,

[00:37:48] using YJS on the

[00:37:50] client. I’ve also done a

[00:37:52] decent amount of work interacting with

[00:37:54] live view through JavaScript,

[00:37:56] JavaScript hooks. I happen to know, and you mentioned earlier

[00:37:58] some, a fun idea about

[00:38:00] animating presence with something

[00:38:02] that sounds like 3JS or D3

[00:38:04] or something, which would be another

[00:38:06] JavaScript integration. I think

[00:38:08] I also happen to know you

[00:38:10] gave a talk about authentication and

[00:38:12] passkeys recently. I did.

[00:38:14] So there’s, this is kind of like

[00:38:16] another frontier. If we want to put on

[00:38:18] our drama glasses,

[00:38:20] there was a

[00:38:22] debate a couple months ago about

[00:38:24] Phoenix having a ceiling,

[00:38:26] right? Oh, there’s just

[00:38:28] so many things you can’t do because, you know,

[00:38:30] I don’t want to, like, misrepresent

[00:38:32] the argument, but it was, there was,

[00:38:34] there were hot takes going back and forth.

[00:38:36] Blog posts were written about

[00:38:38] actually, yeah, we

[00:38:40] have all these tools in live view for

[00:38:42] interacting with JavaScript because

[00:38:44] sometimes you need the escape hatch,

[00:38:46] and that’s what Elixir is really great at, is

[00:38:48] letting you reach out to other

[00:38:50] tools whenever you really need it. Can you speak

[00:38:52] a little bit about your experience looking

[00:38:54] for tools, like when you know you need to reach

[00:38:56] for JavaScript or interact with something

[00:38:58] just outside of live view?

[00:39:00] So when I would need to

[00:39:02] reach for JavaScript outside of live view,

[00:39:04] for me personally, since I have

[00:39:06] a strong background in JavaScript,

[00:39:08] I pretty much defer

[00:39:10] to actually building my front end

[00:39:12] using JavaScript. For example,

[00:39:14] in the app that I built, the way it

[00:39:16] works is that I

[00:39:18] pretty much pass, once

[00:39:20] it hits the front end, Svelte

[00:39:22] is pretty much the driver.

[00:39:24] And then I am just talking

[00:39:26] to my backend via the WebSocket

[00:39:28] connection that is given by

[00:39:30] live view. I guess my

[00:39:32] answer to the question is I would

[00:39:34] always defer to using JavaScript for

[00:39:36] the front end because I think that

[00:39:38] there is a larger

[00:39:40] ecosystem

[00:39:42] available for JavaScript

[00:39:44] specifically for front end.

[00:39:46] So I think that would be my answer

[00:39:48] for that. And I honestly think that

[00:39:50] at the end of the day, since we

[00:39:52] had that quick discussion about

[00:39:54] CL links and all, I think that

[00:39:56] honestly, at the end of the day, you can

[00:39:58] actually build anything

[00:40:00] you want in either language.

[00:40:02] But there are tradeoffs.

[00:40:04] So for example,

[00:40:06] I think Elixir is

[00:40:08] for sure better at handling

[00:40:10] WebSockets and

[00:40:12] doing things like background jobs.

[00:40:14] Hands down, it is going to be better

[00:40:16] than running it in JavaScript.

[00:40:18] But you can do it in JavaScript,

[00:40:20] it just wouldn’t be as

[00:40:22] performant or easy. You might have to

[00:40:24] run it up like another server, whereas

[00:40:26] with Phoenix, you would only need one server.

[00:40:28] So there are tradeoffs there.

[00:40:30] And on the other side though, I do think

[00:40:32] JavaScript has some advantages as well.

[00:40:34] And one of it, honestly, is just

[00:40:36] the size of the community, which means that

[00:40:38] there is probably a

[00:40:40] library available for what

[00:40:42] you want to do.

[00:40:44] And of course, there’s the flip side of that too,

[00:40:46] which is there is a library

[00:40:48] for everything you want to do

[00:40:50] and more, which means there’s going

[00:40:52] to be a lot of decision

[00:40:54] fatigue when you’re trying to decide

[00:40:56] what libraries you want to

[00:40:58] use. And this kind of

[00:41:00] actually comes back to one of the reasons why

[00:41:02] I ended up at Elixir in the first place.

[00:41:04] So like I said, I have a really

[00:41:06] long background in

[00:41:08] JavaScript, and

[00:41:10] one of the reasons why I started looking

[00:41:12] elsewhere was because

[00:41:14] I was getting a little bit tired

[00:41:16] of all of the

[00:41:18] decisions that I had to make in order to start

[00:41:20] an app in JavaScript.

[00:41:22] Because in JavaScript, I think the first thing

[00:41:24] you have to do is you have to choose a rendering framework.

[00:41:26] So do you choose React, Vue,

[00:41:28] or Svelte? After that, you have to

[00:41:30] choose your meta framework. Are you

[00:41:32] familiar with meta frameworks?

[00:41:34] After React, you

[00:41:36] have to choose, do you want to use Next.js

[00:41:38] or Remix? Or do you want to

[00:41:40] use SvelteKit, Astro? The list goes on

[00:41:42] and on. And then after that,

[00:41:44] you have to decide, okay, what’s your

[00:41:46] auth package going to be? What’s your ORM?

[00:41:48] And as you can see, there’s a lot of decisions

[00:41:50] you have to make in JavaScript.

[00:41:52] Which is why I started looking

[00:41:54] for more batteries

[00:41:56] included frameworks.

[00:41:58] And in the

[00:42:00] web dev community, I believe

[00:42:02] the three that I

[00:42:04] know of are Rails,

[00:42:06] Laravel, and then there was

[00:42:08] Phoenix. And I honestly

[00:42:10] tried all three,

[00:42:12] and I just ended up really

[00:42:14] liking Phoenix. And one of the

[00:42:16] reasons for Phoenix is because

[00:42:18] like I said, the WebSocket support

[00:42:20] I think is the best out of any

[00:42:22] framework I’ve seen. And number

[00:42:24] two is that it does have

[00:42:26] the front-end support

[00:42:28] that other frameworks

[00:42:30] don’t have. Meaning it

[00:42:32] can do things with LiveView

[00:42:34] if you didn’t want to write JavaScript at all.

[00:42:36] But at the same

[00:42:38] time, you do have the option

[00:42:40] to use JavaScript if you want

[00:42:42] via the JavaScript hooks.

[00:42:44] It gives you the way to escape

[00:42:46] into JavaScript if you do want to.

[00:42:48] And I guess

[00:42:50] since we’re on the topic of using

[00:42:52] Phoenix with JavaScript,

[00:42:54] I’ll also mention really quickly

[00:42:56] another library. I’m not sure if either of you

[00:42:58] have heard of a library called

[00:43:00] Inertia.js.

[00:43:02] Heard of it, not used it.

[00:43:04] But yeah,

[00:43:06] tell us about Inertia.

[00:43:08] So Inertia is actually

[00:43:10] a library that was born from

[00:43:12] the Laravel community.

[00:43:14] And what it allows you to do

[00:43:16] is use your

[00:43:18] any backend you want.

[00:43:20] So you can use Rails, you can use

[00:43:22] Laravel, or you can use Phoenix.

[00:43:24] And you’re

[00:43:26] able to use

[00:43:28] the router from

[00:43:30] the Phoenix framework.

[00:43:32] But when you

[00:43:34] render out your page

[00:43:36] from a controller, it actually renders

[00:43:38] out a

[00:43:40] JavaScript component.

[00:43:42] So on the frontend, you can

[00:43:44] use React, you can use Vue, you can use

[00:43:46] Velt, you can use whatever.

[00:43:48] But what it does is it renders out the

[00:43:50] JavaScript component.

[00:43:52] And then it also passes props

[00:43:54] from the server

[00:43:56] down to the client

[00:43:58] as well.

[00:44:00] And I just find that it’s a very

[00:44:02] good in-between in order to

[00:44:04] hook up any backend to any frontend.

[00:44:06] And I’ve been using it

[00:44:08] with Phoenix via

[00:44:10] an adapter.

[00:44:12] And it’s been

[00:44:14] working really well, actually.

[00:44:16] So I just wanted to mention that as another option

[00:44:18] if you wanted to

[00:44:20] use a JavaScript frontend with

[00:44:22] a Phoenix backend.

[00:44:24] Nice.

[00:44:26] Yeah, I know, just the last thing I’ll say on Inertia is

[00:44:28] I know that there’s

[00:44:30] an Elixir startup,

[00:44:32] an Elixir backed startup called SavvyCal

[00:44:34] from Derek Reimer,

[00:44:36] part of the team that

[00:44:38] created Drip,

[00:44:40] that email marketing campaign thing.

[00:44:42] And so I think he’s also using

[00:44:44] Elixir on the backend and then using Inertia

[00:44:46] on the frontend to connect with the more

[00:44:48] real-time client-side

[00:44:50] interactions.

[00:44:52] Correct. Yeah, I believe

[00:44:54] Derek is the one who made the

[00:44:56] Inertia adapter for Phoenix, actually.

[00:44:58] Oh, nice.

[00:45:00] Cool.

[00:45:02] Tony, I think it’s going to be really interesting

[00:45:04] to see what you get up to in maybe

[00:45:06] the next year, so that’s going to be fun.

[00:45:08] Do you, okay, you already gave us your

[00:45:10] website, you already gave us some of your socials,

[00:45:12] and we’ll again put that in the

[00:45:14] things below. Anything else

[00:45:16] you have to add before we wrap up?

[00:45:18] I guess one thing I wrote

[00:45:20] down that, so one thing I wish

[00:45:22] that maybe

[00:45:24] a lot of podcasters would ask

[00:45:26] of their hosts is what packages

[00:45:28] do you use? Because I have a list of

[00:45:30] packages that I have been

[00:45:32] using and I really like, so I just wanted to

[00:45:34] give them a shout out. I already mentioned Inertia,

[00:45:36] but I’ve also been using

[00:45:38] REC a lot. It’s the

[00:45:40] HTTP library from

[00:45:42] Wojtek. I’ve also been using

[00:45:44] Obon a lot, and

[00:45:46] it’s been really awesome. And then two other ones

[00:45:48] are Jokin. Have you used Jokin?

[00:45:50] It’s like token except with a J,

[00:45:52] and it allows you to

[00:45:54] work with JSON web

[00:45:56] tokens. So it allows

[00:45:58] you to sign tokens and

[00:46:00] verify tokens.

[00:46:02] And then the last one that I just wanted to mention

[00:46:04] real quickly is Hammer, if either of you

[00:46:06] use Hammer.

[00:46:08] I’m not.

[00:46:10] So Hammer is a library that allows

[00:46:12] you to do rate limiting in your

[00:46:14] apps.

[00:46:16] I heard of this, yes.

[00:46:18] So basically you can

[00:46:20] protect routes in your Phoenix

[00:46:22] application and set a rate limit

[00:46:24] on it. And I thought it worked really

[00:46:26] well, so I wanted to give that a shout out as well.

[00:46:28] But yeah, I always like it when

[00:46:30] people recommend the

[00:46:32] most used packages, so I

[00:46:34] can discover new packages to use myself

[00:46:36] as well. Nice.

[00:46:38] In the spirit of shout outs, I’ll shout

[00:46:40] out previous guest Zach Daniel.

[00:46:42] I’ve been using Igniter this week

[00:46:44] to write code generators.

[00:46:46] Awesome. It’s nice.

[00:46:48] It’s very nice.

[00:46:50] Yeah, I actually just

[00:46:52] listened to that episode, so yeah.

[00:46:54] It was an awesome conversation.

[00:46:56] It did release today. Today the

[00:46:58] day that we’re recording, not today Halloween.

[00:47:00] Not to be confused.

[00:47:02] Well, Tony, it’s been great chatting

[00:47:04] with you. I hope we get to see more

[00:47:06] from you soon. Thank you for joining

[00:47:08] us. We’ll see everyone next week on

[00:47:10] the next episode of Elixir Wizards.

[00:47:14] Elixir Wizards is a production of SmartLogic.

[00:47:16] You can find us online at

[00:47:18] SmartLogic.io and we’re at

[00:47:20] SmartLogic on Twitter. Don’t forget to

[00:47:22] like, subscribe, and leave a review.

[00:47:24] This episode was produced and edited by

[00:47:26] Paloma Pichinick for SmartLogic.

[00:47:28] Thanks for joining us in the Creator’s

[00:47:30] Lab, and we’ll see you next week for more

[00:47:32] stories of innovation with Elixir.

[00:47:46] Hey, this is Yair

[00:47:48] Flicker, president of SmartLogic,

[00:47:50] the company that brings you this podcast.

[00:47:52] SmartLogic is a consulting company

[00:47:54] that helps our clients accelerate the pace

[00:47:56] of their product development.

[00:47:58] We build custom software applications for

[00:48:00] our clients, typically using Phoenix and

[00:48:02] Elixir, Rails, React, and Flutter

[00:48:04] for mobile app development. We’re always

[00:48:06] happy to get acquainted, even if there isn’t

[00:48:08] an immediate need or opportunity.

[00:48:10] And, of course, referrals are always

[00:48:12] greatly appreciated. Please email

[00:48:14] contact at SmartLogic.io to chat.

[00:48:16] Thanks, and have a great day.