Working in Elevators: How to build an offline-enabled, real-time todo app w/ LiveView, Svelte, & Yjs

แชร์
ฝัง
  • เผยแพร่เมื่อ 25 ม.ค. 2025

ความคิดเห็น • 33

  • @woutdepuysseleir
    @woutdepuysseleir 11 หลายเดือนก่อน +13

    Using a service worker to keep the app working when offline is really nice. One of the main counterpoints of LiveView is that you need to be connected to the server at all times and this shows you can still make LiveView work in those cases with a little bit of effort! Super cool!

  • @PaKa-kj3rj
    @PaKa-kj3rj หลายเดือนก่อน +1

    Thanks so much for going over this! Immensely valuable.

  • @nicholasprice5137
    @nicholasprice5137 2 หลายเดือนก่อน +1

    WOW. Excellent solution, clear explanation, and beautiful presentation (and app!). This is an excellent tactic for offline capability in liveview, and the svelte integration also allows for beautiful client-side reactivity and components, all while managing state gracefully.
    Well done!! I hope you make more videos like this in the future!!

  • @mruizcamauer
    @mruizcamauer 11 หลายเดือนก่อน +8

    very clear, and capable solution. It'd be great if this was all "built-in" to Liveview, as it'd be a great functionality to have simple offline apps!

  • @BorisBarroso
    @BorisBarroso 2 หลายเดือนก่อน +1

    Amazing solution. PWA

  • @mr.keith31337
    @mr.keith31337 11 หลายเดือนก่อน +4

    Quite an elite stack!

  • @Aphova
    @Aphova 8 หลายเดือนก่อน +2

    This was very interesting! Saw on your site you only started coding a few years ago so this is quite impressive. Think you've got a promising career ahead of you!

    • @thisistonydang
      @thisistonydang  8 หลายเดือนก่อน

      Thank you for the kind words! I very much appreciate it 🙏

  • @fredguth1315
    @fredguth1315 3 หลายเดือนก่อน +1

    Very well explained

  • @Kevin-hk4fv
    @Kevin-hk4fv 6 หลายเดือนก่อน +1

    Love it love it love it, thanks for the great video!

  • @gonglexin
    @gonglexin 9 หลายเดือนก่อน +1

    Very cool project! Speak very clearly, even my English listening is not very good, I can understand you completely.

  • @AlexKelleyD
    @AlexKelleyD 8 หลายเดือนก่อน

    Very clever approach. Your presentation was very thorough and clearly presented. Thank you for sharing!

  • @RicoTrevisan
    @RicoTrevisan 11 หลายเดือนก่อน +1

    Fantastic project; super clear presentation. Thanks for this!

  • @FrancoBugnano
    @FrancoBugnano 11 หลายเดือนก่อน +2

    Super cool video!

  • @dwylhq874
    @dwylhq874 6 หลายเดือนก่อน +2

    Awesome work Tony! 😍 Subbed. 🔔

  • @sismith5427
    @sismith5427 8 หลายเดือนก่อน +1

    Be interesting to see if Chris McCord takes anything from this concept to extend Phoenix itself to enable offline

    • @thisistonydang
      @thisistonydang  8 หลายเดือนก่อน +1

      It would be great to see offline support built into Phoenix itself, but I think it's unlikely. Working offline inherently means using JavaScript, so the only way I can imagine this being accomplished in Phoenix would be to have a bunch of Elixir wrappers around Javascript. That sounds like a lot of additional overhead that the Phoenix team probably won't want to take on, but I'd definitely be very happy if I see it :)

  • @FrancoBugnano
    @FrancoBugnano 11 หลายเดือนก่อน +3

    Just one question: You showed how CRDT works when connected to the websocket, and you briefly mentioned that Yjs is able to run both on the client and on the server. I'm missing the part how CRDT works on the server in case of an offline client that reconnects. I mean, how does the central Postgres DB know which state to store in case of a reconnecting client with a different state?

    • @thisistonydang
      @thisistonydang  11 หลายเดือนก่อน +4

      Good question! When reconnecting, each client will send its current state back up to the server. For example, if we have the following states when disconnected:
      - client #1, `state A`
      - client #2, `state B`
      - server, `state C`
      When reconnecting, client #1 and client #2 will send their states up to the server. The order in which the states are sent to the server won't matter. On the server, Yjs will take care of merging the states, so the resulting state on the server will be `state A` + `state B` + `state C`. So let's just call it `state ABC` for short.
      Then, `state ABC` will be sent from the server down to the clients. On client #1, Yjs will take care of merging the states so the state will be: `state A` + `state ABC` which will just equal `state ABC`.
      The same thing happens on client #2. Yjs will merge `state ABC` + `state B` which will again equal `state ABC`
      So now we should end up with the same `state ABC` everywhere.
      Remember to note, that thanks to the Yjs CRDT algorithm, these updates could have been sent in any order to each other, and even sent multiple times, and the resulting state will always end up being `state ABC`.
      Sorry, it was a little hard explaining via text, but I hope this helped! Let me know if things are still not quite clear and I can try to explain further or make another video with some diagrams :)

    • @FrancoBugnano
      @FrancoBugnano 11 หลายเดือนก่อน +1

      @@thisistonydang Thanks for the reply, it's a bit clearer now, but I don't understand how Yjs works on the server. I mean, is there an Elixir port of Yjs, or there's a separate Nodejs server running whose sole job is to run Yjs?

    • @thisistonydang
      @thisistonydang  11 หลายเดือนก่อน +5

      @@FrancoBugnano There isn't a port of Yjs in Elixir. You'll have to use one of the ports that is available (github.com/yjs/yjs?tab=readme-ov-file#Ports ) or have a separate Nodejs server.
      In my case, I am using a Cloudflare Worker function so that I can run Yjs in JavaScript. After receiving a state update from a client, I'm sending the client state and current server state to my Cloudflare function to do the merging, which will then send it back to my Phoenix server.
      This is not the most efficient solution since you have to do a round trip to another server, but it was the quickest solution that got the job done for me :)
      You can definitely just use one of the available ports or just use nodejs and run Yjs on the same server as Elixir as well.

    • @FrancoBugnano
      @FrancoBugnano 11 หลายเดือนก่อน

      @@thisistonydang Thanks for the explaination, now everything is clear😀

  • @andrelandgraf1398
    @andrelandgraf1398 11 หลายเดือนก่อน +1

    Really cool!

  • @yannbernard4173
    @yannbernard4173 8 หลายเดือนก่อน

    I have an issue while deploying the app. For some reason the app.css is not in assets after deployment.

    • @thisistonydang
      @thisistonydang  7 หลายเดือนก่อน

      Hmm, I'm not sure why the app.css wouldn't show up after deployment. I just added some instructions to the repo for deployment and running the project locally. Hopefully it helps! github.com/tonydangblog/liveview-svelte-pwa

  • @VladimirRokovanov
    @VladimirRokovanov 8 หลายเดือนก่อน

    I've examined the implementation and noticed that the Yjs document is stored in a PostgreSQL database directly. I'm curious if there's a straightforward method for decoding/encoding Yjs documents and validating changes in fields?

    • @thisistonydang
      @thisistonydang  8 หลายเดือนก่อน

      In order to be able to validate the data, you'll have to run Yjs server-side. In my original implementation of the project, I was running Yjs server-side by using a Cloudflare Worker. However, I've since removed the Cloudflare Worker because I wanted to remove the dependency of using an additional server.
      To be able to run Yjs on the same Phoenix server, there are some possibilities that I haven't tried yet myself:
      1. Use Rustler with the Yjs Rust port
      2. Use Elixir's `Port` to run JS Yjs
      3. Compile Yjs to WASM and run with Extism
      So to answer your question- yes, it's possible to decode the Yjs document server-side for validation, but it's not super straightforward.