
Show HN: Purview – A server-side component framework - karthikksv
https://github.com/karthikv/purview
======
choeger
Wait, why could we not render the HTML on the server and only let the browser
to the compositing? If there only was a protocol that would allow us to
exchange input events and some drawing commands over some arbitrary network..
let's phantasize for a moment and call that protocol X. I would use it when
it's mature so maybe from X11 on onwards.

Naturally, sending draw commands has a big downside in efficiency. Maybe we
could later exchange X with something that only sends bitmaps?

~~~
martell
> Maybe we could later exchange X with something that only sends bitmaps?

Can we call the followup Wayland because that is the only way to go :)

------
weego
So now we're stuffing sql in our react as well as html and CSS? React is on
course to reinvent the PHP that everyone spent so long laughing about

~~~
karthikksv
A common criticism I heard about React a few years back was combining JS and
HTML within the same file, as opposed to having them separate. As with most
decisions, I think separation is an important trade-off you need to consider:
it's easier to reason about the individual, separated parts that are well-
contained, but it becomes harder to reason about the system as the whole.

If you have a complex front-end and back-end with a REST API, each time you
modify a server route, you need to find all instances in your client where you
make an AJAX request to that route and change them appropriately. The
potential for inconsistency can cause numerous bugs.

GraphQL solves this by having a very flexible and standardized server (albeit
complex), giving your client access to arbitrary structured information using
a query language.

Purview solves this by moving your logic to the server-side, where you can
access your database directly. Because everything runs on the server, the
client-server interface is abstracted away, and you don't need to worry about
using GraphQL or REST. You can make database queries, contact external
services, etc. directly within your components.

To keep this maintainable, you split up your page into logical, reusable
components, just like you would with React, and each component now not only
contains your view logic, but also the server-side logic. Given that you've
decomposed your components well, this makes it easy to reason about the whole
system when it comes to any part of your page.

~~~
tdhz77
This is how cold fusion works, written by Adobe for too steep of a price. I
wonder if we are just running circles around the same ideas. Are we really
moving the ball with Purview? I’m lost.

------
Scooty
I've been playing around with a similar idea using nextjs. My idea was to
create some kind of RPC interface with typescript that works seamlessly
between server/client rendering, so during server rendering, RPC calls would
just be regular function calls, and during client rendering/event handling,
the calls would be made through sockets or HTTP requests.

There's a lot of criticism in this thread. I'm curious if you're using this in
production. I love projects like this that really push the bounds of how these
problems are typically solved.

~~~
karthikksv
We've been using this in production at the company I work at for about the
past ~1.5 months. We've gone through a fair number of fixes and improvements
throughout that time (bugs, race conditions, performance, etc.). It's
definitely still a nascent project, but we're excited to continue using
Purview and developing it. Would love to get your thoughts if you try it out
sometime.

------
janpot
looks like it's the react version of
[https://dockyard.com/blog/2018/12/12/phoenix-liveview-
intera...](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-
real-time-apps-no-need-to-write-javascript) ?

edit: nvm, it's listed in the readme as inspiration

~~~
karthikksv
Yes, that was my inspiration! Chris gave a great talk about it at ElixirConf
is anyone is interested in watching:
[https://www.youtube.com/watch?v=Z2DU0qLfPIY](https://www.youtube.com/watch?v=Z2DU0qLfPIY)

Some differences compared to LiveView:

\- Type-checking: there are extensive JSX typings
([https://github.com/karthikv/purview/blob/master/src/types/js...](https://github.com/karthikv/purview/blob/master/src/types/jsx.ts))
that ensure you're attaching event handlers with the correct signatures,
specifying supported props, using valid HTML tags and attributes, etc. Static-
typing guarantees are one of my big priorities.

\- I'm not sure if LiveView intends to support nested components like React
does. Having the ability to split up complex pages into components that you
can nest and reuse (with mostly one-way data flow) is a key part of
maintainability. I wanted to maintain a very familiar React interface, so you
can pick up Purview quickly if you're comfortable with React.

~~~
chrismccord
Neat project! We indeed support nesting in LiveView :)

~~~
karthikksv
Thanks for chiming in Chris! If you don't mind, I have a few implementation
questions about LiveView:

\- I noticed that you said you use morphdom for LiveView. I originally started
with this too, but found that the DOM diffing doesn't work well with any
client-side JS that may modify the page (e.g. a date picker, a tooltip
library, a custom dropdown, etc.). I ended up switching to snabbdom
([https://github.com/snabbdom/snabbdom/](https://github.com/snabbdom/snabbdom/)),
a virtual DOM implementation, to avoid updating parts of the page that the
user doesn't directly intend to modify. This helps with client-side interop,
and it also gave us a nice boost in performance. Did you run into any similar
issues with LiveView? Do you still use a DOM diff rather than a virtual DOM
diff?

\- On that note, what's the recommend way to interop with client-side
libraries like I mentioned earlier? We use the WebComponents custom-elements
spec to define custom tags that encapsulate client-side JS logic (e.g. we have
an <audio-player>, a <date-picker>, etc.), and then in our Purview components
we can just send down these tags. We also had to provide the ability to
integrate with DOM events triggered by these custom elements. Is there a
recommended approach in LiveView to integrate with these libraries?

\- With respect to nesting in LiveView, do you call live_render() directly
within a view's render() function? Do you pass props in this call? There
doesn't seem to be a differentiation between props and state for LiveView--are
both consolidated into "assigns"? Hence both are mutable? I'm aware that you
use immutable data structures in Erlang/Elixir, but I mean in the sense that
you can assign a different value to a prop that was given to you by your
parent. If this is the case, how would that work if there's a re-render and
the prop passed by the parent changes?

------
erokar
[https://dockyard.com/blog/2018/12/12/phoenix-liveview-
intera...](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-
real-time-apps-no-need-to-write-javascript)

------
rudolph9
> Not React compatible due to the differences listed below, so you can't use
> existing React components/libraries with Purview.

Existing components/libraries is the only reason I use react.

A good alternative that provides a nice setup for SSR on the initial page load
as well as code splitting is nextjs
[https://github.com/zeit/next.js/](https://github.com/zeit/next.js/)

------
macobo
This smells a lot like meteor. Would love to see an actual semi-large app
built with this approach.

------
mplewis
In React, forms are often built with this pattern:

* Type/change events fire on the field (e.g. username)

* Username updates the internal model (this.username = 'karthikksv')

* The submit button fires an event so the parent page can act on the entire data model ({ username: 'karthikksv', password: 'fluffykittens' })

I'm concerned that this model won't work well using server-side React
components on a network with high latency – each type event would have to
round-trip to the server to update in the DOM.

~~~
karthikksv
Higher latency connections will certainly have longer delays, but it's quite
fast on a reasonable connection thanks to the persistent WebSocket, even if
you're sending each letter that's being typed. We're using Purview in
production at the company I work at, and we haven't had issues with input-
related delays.

If you don't need to send each letter, it's recommended to not do so; the
submit event object includes all form data, so you can do one final validation
at the end, similar to what you'd do with a normal web server.

------
bloomca
Shameless plug: I have a library for server-side react-like components
([https://github.com/Bloomca/welgo](https://github.com/Bloomca/welgo)).

It does not help you with client side, so it is more like composable
templates, but they are async, so you can query DB inside your components.

------
rienbdj
normally security would be implemented at an api level. you would have to be
careful to implement that in the renderer here.

~~~
karthikksv
You're right, there's validation for the WebSocket messages sent to the
server. For certain events (e.g. submit), the validation of user form data is
left to you, just as you would normally be responsible for.

------
chikien276
I am surprised that nobody mentions this similarly
[https://docs.microsoft.com/en-us/aspnet/core/razor-
component...](https://docs.microsoft.com/en-us/aspnet/core/razor-
components/hosting-models?view=aspnetcore-3.0#server-side-hosting-model)

------
robinduckett
<?php print("this is far easier lol"); ?>

~~~
forgotmyhnacc
I know this comment is a joke, but this is actually how react was created.
Facebook made a templating language in php called xhp
([https://docs.hhvm.com/hack/XHP/introduction](https://docs.hhvm.com/hack/XHP/introduction))
and some people at fb developed react as a natural extension to xhp but in
JavaScript.

~~~
rajangdavis
TIL. Thanks for sharing!

------
kgwxd
I'm sure there's a use case for this but, for me, it's pretty rare to need
pull new data or persist anything after most events, let alone every event. A
single fetch and single save is usually all that's needed.

~~~
karthikksv
Whenever any information needs to be saved or processed by the server, you can
perform your server-side logic inline in the event handler (e.g. update the
database, contact external services, etc.). There's no need to make an AJAX
request and have a corresponding API route. This abstracts away the client-
server interface, and you get safety guarantees with type-checking.

------
neurotrace
Looks an awful lot like old fashioned aspx pages. They're the bane of my
existence. The syntax looks a lot nicer and there isn't the odd CodeBehind
shenanigans so maybe it's better to work with.

------
spyke112
Wait... Didn’t Microsoft do this back in the day with ASP.NET Web Forms?

Full circle for sure!

------
root_axis
> _What if your React components ran on the server-side?_

Huh? React components _can_ run on the server side, that is one of the primary
benefits of React compared to its predecessors.

~~~
karthikksv
Perhaps I could've explained myself better. I meant that _all_ the business
logic of the components (i.e. event handlers, lifecycle hooks, setState()
calls, etc.) run on the server, unlike just the initial server-side rendering
that React provides. The server maintains the state of all components, and
when an event occurs, the client notifies the server to run the appropriate
event handler.

~~~
root_axis
Ah! I see what you mean. It reminds me of
[https://github.com/airbnb/hypernova](https://github.com/airbnb/hypernova)

------
stigsb
Everything old is new again! Facebook once had a PHP extension called XHP
which I guess you could call a server-side predecessor to React.

------
pennaMan
so it's a next.js clone?

~~~
karthikksv
All the business logic of the components (i.e. event handlers, lifecycle
hooks, setState() calls, etc.) run on the server, unlike just the initial
server-side rendering that Next.js provides. The server maintains the state of
all components, and when an event occurs, the client notifies the server to
run the appropriate event handler.

------
k__
Haha, I saw people using it in WebWorkers, no nothing prevents them from using
it on the back-end.

One Lambda per component would be interesting tho, haha.

------
solarkraft
> Applications that require minimal latency (e.g. animations, games) are not
> well suited for Purview

It's not actually React compatible.

Just why?

~~~
janpot
Because the DOM is not synchronously accessible, I guess.

------
slifin
Seems like the creator(s) of this need to take a hard look at Om next to solve
their n query+net request problem

------
vlucas
It's a JS framework that targets server-side (node.js), and is written in a
language that is not natively supported - TypeScript, thus requiring
transpilation right out the box to use. Does that seem odd to anyone else?

On the update: This does seem kinda neat, and certainly useful in some
situations.

~~~
karthikksv
You're not required to use TypeScript. As janpot mentioned, the library is
transpiled prior to being published on npm, so you can use it with regular
JavaScript. This is true of most TypeScript libraries.

------
ahamdy
this is a whole new level of security bugs

------
stevebmark
God, GOD WHY. Whhhyyyyy. Build APIs, not database calls from templates like
Rails or PHP garbage. We know how to do this nowwwwwwww don't make this Rails
User.friends.comments garbage DB calls from templates

~~~
benbristow
Why's that garbage? Sometimes a full SPA is not needed.

~~~
throwawayy1001
Just take a step back and look at it, you're combining HTML, SQL and JS, on
the fucking server.

~~~
ako
If you’re going this way, might as well put all of that as a stored procedure
in the database. At least it Simplifies your infrastructure.

------
patgrdj
here we go again

