LiveVue - seamless integration of Vue with Phoenix LiveView

Perhaps the Meteor community could provide some guidance. They’ve had multi-framework integration for almost a decade

1 Like

Since I started posting about LiveVue I got regular requests:

That sounds amazing! What about LiveReact? LiveSolid? LiveQwik?

And that’s a fair point, every developer has his own preference & past experiences. So I thought about it a lot and I think there’s a room for such a solution. We could have a shared library called LiveSPA handling all of these:

  1. Installing bundler (Vite or ESBuild). Maybe some automated script.
  2. Function component rendering a div with all the props / handlers / slots
  3. Giving a higher-order hook - library consumers would need to just provide code to mount / update / destroy component based on arguments, it would handle deserialisation etc.
  4. Handling Server-Side Rendering (maybe own implementation, not relying on node_js package)
  5. Handing JSON diffs & general performance optimizations (avoiding re-sending not-updated fields etc)
  6. Giving all the helpers - ~V sigil for in-place declaration of a component, shortcuts for easier usage etc.

All in all, there’s quite a long list of shared stuff every such library would need to do.

Then, we could implement LiveReact, LiveVue etc (I don’t believe all these should be “packed” into a single lib, these should be probably maintained by different authors) by consuming all these utilities. They would consist only of:

  1. Bundler config
  2. JS hook implementation
  3. Some wrapper around component from point 2) to make it more idiomatic.
  4. …and that’s it? :thinking:

That said, I want to explore all the possibilities with LIveVue, maybe help to implement some improvements I figured out to LiveSvelte and then talk how we could move that topic forward.

We could get inspiration from Inertia.js, doing a similar thing for PHP / Ruby but without live updates.

Ecto handles this well. They have adapters for every database they support out of the box and have a section on custom adapters.

Also a great source!

Most likely the ship has sailed already in regards of the “LiveVue” name - I’ve seen it mentioned in Reddit already.

LiveSPA is a good one for the umbrella term

I’ve seen it mentioned in Reddit already

I think I’m the one who set that ship to sail :sweat_smile: TBH reddit also commented that name is ambiguous.

1 Like

Some other interesting resources for inspiration come from the Eleventy community:

About esbuild not being modern - it still is :sweat_smile: Just it still builds the whole bundle after each change, so it doesn’t scale well as project grows. Besides, it doesn’t have a good hot-reload functionality included.

On the other hand Vite uses modern browsers support for <script type="module"> and in development serves files from your disk without bundling them. It allows for a very easy and granular invalidation, and quick starts (almost no work is done upfront). They have a great section in docs why Vite is a good choice.

About LiveSPA: aren’t these libraries (LiveVue and LiveSvelte) the exact opposite of SPA, i.e. separate frontend calling backend API endpoints? Instead they promote just adding JS-based components where they need to be, as the internet should work.

2 Likes

Nice, didn’t know about this one!

It seems to be much simpler than LiveVue / LiveSvelte and slightly outdated (<phoenix 1.7), but I’d need to dive deeper.

I was mostly being cheeky but thanks for the info!

Also I realize I didn’t answer your earlier question re: LiveViewJS. The answer is that I don’t know though development on it seems to have slowed right down.

Decided to switch here (and I owe you couple answers on GitHub, I remember that :see_no_evil: . But topics are quite huge, didn’t get enough time to explain my thoughts)

Thinking about your idea… it would require a fairly complex interop of LiveView / JavaScript, mostly when it comes to slots and nesting components. I’m not sure if it’s really possible, since vue components woul need to be rendered differently depending if it’s nested inside other component or not (to avoid creating multiple root-level components) :thinking:

But maybe I shouldn’t write here since it’s not the topic for it :sweat_smile: I think integrating client side hooks is a necessity for good UX. Recently there was a quite huge drama on twitter how LiveViews doesn’t scale because of delay between interaction and change in UI in Hey application. This could be avoided with hooks. Just it’s quite challenging to write complex components using hooks because it’s imperative - you have to control all changes by yourself, there is no way to declare a template and ask library to keep it in sync with the state… that’s why I’ve created LiveVue :wink:

The only really missing part currently is a shared state: by “shared” I mean shared with the backend LiveView (I believe it’s quite simple to have global state shared between all - even related to different roots - LiveVue components via a singleton module or multiple). I still think that pinia with a custom store plugin could be a good candidate for that. But custom solution would work as well: something which will intercept specific messages from the frontend hooks and inject values into the socket. It’s just a basic abstract idea, I don’t fully understand how to get changes back to the LiveVue.

But having that it would be possible to have actual “reactive” connection between LiveVue and LiveView parts. Of course, it won’t be instant because of the roundtrip, but it is much easier than per-vue component useLiveVue().pushEvent/2. I would even urge to discourage people to use this method on a day-to-day basis (it can create bad habits :slight_smile: components should avoid inject-like interactions); though I think it is a necessity to have this option.

Not sure but see if this library does what you have in mind: storex

1 Like

Looks interesting on the first glance, I have to dig it deeper. Thanks!

I’m not exactly sure if I understand what you’re saying.

These are possible states:

  • Server (socket) state - added by assigns
  • Client (Vue) state - added in setup(), eg. const val = ref(123)

Client state is divided into:

  • Global state (pinia store or by using const state = reactive({}) outside of Vue component and importing it)
  • Local component state

Server state is also divided into LiveView state and LiveComponents state but I think it’s not that relevant now.

So then it all boils down to synchronizing that state across various places.

You’re covered with Socket -> Vue Component. Simply pass props to <.vue> component and they’ll be synchronized. If you need it in multiple places, pass it to each. This could be optimized in the future but I want to make sure problem exists.

You’re also covered with Vue Component -> Socket. The most direct solution is to use useLiveVue().pushEvent(event_name, data, response_handler) and implement handle_event(event_name, params, socket). If you update assign passed to <.vue> it will be synchronized.

Remember you can return {:reply, data, socket} tuple from handle_event and data will be passed back to the frontend. That way you can treat LiveView as GenServer, which reacts to messages and can send back responses. Something like an API but with a persistent state underneath. I’m using it to generate LLM responses that are local to the frontend component and not needed at the server state.

What might be tricky is prop drilling. Since all the state is available at the root component you might need to pass it down possibly through multiple levels. That problem in the frontend world is solved either by global states (stores like Pinia) or providers (inject / provide in Vue).

Is it the problem you’re referring to? :sweat_smile: I’m looking for a concrete example what you’d like to accomplish.

1 Like

LiveView is listing Support for Web Components in the road map post 1.0 release. That probably will solve quite a few things. Maybe the need for a UI library based on Functional Components will go away?
I need a rich text editor integrated into the app. All good ones Tiptap, Novel, Lexical are having only React components for UI. I am a bit unsure if I have to go the full distance with LiveVue or LiveSvelte or just be comfortable with JS hooks.
I guess finally it is a question of tradeoffs.

is Inertia.js a drop-in replacement for projects like LiveVue, LiveSvelte?

The way I understand it LiveView uses your applications normal controllers to fetch data. Instead of building your pages in heex you’d render the page in vue, react, etc

From the docs

With Inertia you build applications just like you’ve always done with your server-side web framework of choice. You use your framework’s existing functionality for routing, controllers, middleware, authentication, authorization, data fetching, and more.

However, Inertia replaces your application’s view layer. Instead of using server-side rendering via PHP or Ruby templates, the views returned by your application are JavaScript page components. This allows you to build your entire frontend using React, Vue, or Svelte, while still enjoying the productivity of Laravel or your preferred server-side framework.

Where is the roadmap is located? I was recently searching for one, but wasn’t able to locate it.

I believe they’re referring to this post by Chris where he states

Following the RC phase, we’ll be continuing efforts around collocated JavaScript hooks, Web Component integration, navigation guards, and more as outlined in our issue tracker.

1 Like