Hi!
I feel like Phoenix is slightly missing a trick when it comes to front-end Javascript libraries like React, Svelte, etc.
I feel that Javascript framework components could be treated as even more of a first-class citizen than they currently are.
I realise that most, if not all, of what you need to do can be done just with LiveView, but there are times when you want a little bit more interactivity, or it doesn’t make sense to have some browser-related state in the LiveView process memory.
In those cases rendering JS framework components (particularly just as leaf nodes) from LiveView is the perfect fit.
Yes, we can use hooks for that, and also yes, there are libraries that provide these hooks, but I believe it could be even easier if Phoenix did half the work for you, i.e. the non-framework-specific parts.
Currently, a library that helps to plug a JS framework component into LiveView has to:
- provide elixir code, e.g. a function component, to render the component from the liveview
- provide javascript hook code, to mount the JS framework component and update appropriately
If Phoenix did the non-framework-specific parts out of the box (1. and some of 2. above), then for a user to use components from any given JS framework they’d only need the adapter part of 2. above, which would likely live in a third-party npm package (i.e. no need for elixir code at all).
I’ve just released a simple library, Komodo (see Komodo - easily render React, Svelte, Vue, Angular, any JS framework component from Liveview) that does (1) and (2) above, but it would be great if the generic parts weren’t even needed because Phoenix already did it (and had a standard interface for a “js component” that each library would adapt to).
To be specific, the Komodo library currently requires the user to do this in app.js
:
import { registerJsComponents } from "komodo";
import componentFromReact from "some-third-party-adapter-lib-for-react";
import SomeComponent from "path/to/some/react/component";
// ...
let liveSocket = new LiveSocket("/live", Socket, {
hooks: {
komodo: registerJsComponents({
MyReactComponent: componentFromReact(SomeComponent)
})
}
// ...
});
If Phoenix already did this, this would become, for example
import componentFromReact from "some-third-party-adapter-lib-for-react";
import SomeComponent from "path/to/some/react/component";
// ...
let liveSocket = new LiveSocket("/live", Socket, {
jsComponents: {
MyReactComponent: componentFromReact(SomeComponent)
}
// ...
});
instead.
Anyway just throwing around a few thoughts - I hope that made at least some sense!
At the very least it would be great if Phoenix (i.e. HEEX) had built-in support for custom elements (i.e. native web components) that went as far as:
- allowing props that were more than just strings, e.g. arrays, objects
- allowing listening to custom events
without requiring the user to write an extra hook for this.
Then at least people could always have the option of wrapping their framework component with a custom element if the above wasn’t feasible.
What do you think? Any thoughts welcome!