Isomorphic web apps with Elm?

579 views
Skip to first unread message

Rupert Smith

unread,
Jan 9, 2017, 6:24:57 AM1/9/17
to Elm Discuss
Just wondering if there is anyone out there interested in isomorphic applications with Elm? or has tried experimenting with isomorphic Elm?

Now that I have the same view code running on server and client side, it occurs to me that I am potentially getting into isomorphic web development. If I understand it right, and isomorphic app is one which is written in javascript in order to run the same code client or server side. Some or all of the page rendering is done server side, then whatever has been rendered plus the application state is handed over to the client, and the client displays it or completes or enhances the rendering. The idea is to be able to get the best of both worlds without having to write the code twice; once in javascript for the client and once in some other language for the server.

In my case, I am using server side rendering just for (relatively) static content, so there is practically no application state. I am pretty much there with this simple application model as far as being isomorphic goes.

I believe there is something called the 'isomorphic hand-off' which refers to the transfer of state from server to client, once the server rendering has completed. I think this needs to go something like this:

Run Elm on Server to produce HTML + a little bit of javascript to request everything needed to complete on the client.
Show HTML on the client as quickly as possible (that is, don't download the Elm code just yet).
Trigger the loading of the javascript needed to complete the client side rendering (the same Elm program as was run on the server).
Start up the Elm program and request the state from the server.
Continue rendering from where the server side left off.

I'm really not sure what exactly the difference is between isomorphic and progressive enhancement. What I am actually trying to do is to add an editing mode on the client side - so client and server side renderings will be very different and more capabilities will be available in client editing mode. For this reason, I don't think isomorphic is really what I am after, but I can't help wondering if Elm provides a very neat starting point for doing it.

I think Elm might be very well suited to isomorphic, so long as you keep the model clean and don't put any functions in it. If it is easy to encode/decode the model, then it becomes almost trivial to write the isomorphic hand-off?

Noah Hall

unread,
Jan 9, 2017, 6:27:45 AM1/9/17
to elm-d...@googlegroups.com
Let's not use Javascript names for things here here: you mean shared
code between client and the server.

Like everything else in the area, I have already done this in the
take-home: https://github.com/noredink/take-home#support-summary

It was very, very nice. It allows for seemless APIs that simplified
the code sharing a whole bunch.
> --
> You received this message because you are subscribed to the Google Groups
> "Elm Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to elm-discuss...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Joel McCracken

unread,
Jan 9, 2017, 8:55:08 AM1/9/17
to Elm Discuss
It was very, very nice. It allows for seemless APIs that simplified
the code sharing a whole bunch.

Oh? My impression was that you thought this wasn't worth it, based upon comments here https://github.com/noredink/take-home#should-i-use-this-in-production and IIRC what I've read elsewhere.

Incidentally, I also hate the term isomorphic for shared client-server code.

Noah Hall

unread,
Jan 9, 2017, 9:22:44 AM1/9/17
to elm-d...@googlegroups.com
It's important to separate the two ideas: being able to share code
between client and the server was awesome and very nice - but writing
Elm to work around node's model was not nice/reliable.

Rupert Smith

unread,
Jan 9, 2017, 9:24:43 AM1/9/17
to Elm Discuss
From the wikipedia page for isomorphism:

"The interest of isomorphisms lies in the fact that two isomorphic objects cannot be distinguished by using only the properties used to define morphisms; thus isomorphic objects may be considered the same as long as one considers only these properties and their consequences." 

Which sounds like a reasonable way to describe when the rendered page is exactly the same, whether it is rendered client side or server side. As I understand it though, it often means that some elements of the server side rendering may be ommitted or only mocked up. Particularly interactive elements that just won't work with a full server round trip, but will work asm interactice UI components on the client side.

Also, I think describing what I am trying to do with my editing mode as 'progressive enhancement' isn't quite right either. I think the concept behind progressive enhancement is that you start with you baseline client; perhpas you even have to support some old version of IE, or users who will not have javascript enabled in their browser. You code for that in the main, but add capabilities that better browsers/environments can take advantage of, if they are available.

Not sure why you don't like isomorphism, has the word been poisened by too may javascript libraries?

Noah Hall

unread,
Jan 9, 2017, 9:32:43 AM1/9/17
to elm-d...@googlegroups.com
It's easier to say:

code shared between client and the server

than

isomorphic

and have everyone understand you. Isomorphic means a lot of different
things to different people. Say what you mean, and more people will be
able to take part and understand :)

Rupert Smith

unread,
Jan 9, 2017, 9:38:32 AM1/9/17
to Elm Discuss
On Monday, January 9, 2017 at 2:32:43 PM UTC, Noah Hall wrote:
It's easier to say:

code shared between client and the server

than

isomorphic

and have everyone understand you. Isomorphic means a lot of different
things to different people. Say what you mean, and more people will be
able to take part and understand :)

I do think the term 'isomorphic' may not be so well received, now that it is past the hype stage. One blog I read said that it means your best developers will be tied up trying to do something overly clever and difficult with javascript, instead of adding value to your business.

Rupert Smith

unread,
Jan 9, 2017, 10:32:56 AM1/9/17
to Elm Discuss
On Monday, January 9, 2017 at 11:24:57 AM UTC, Rupert Smith wrote:
Some or all of the page rendering is done server side, then whatever has been rendered plus the application state is handed over to the client, and the client displays it or completes or enhances the rendering.

A wee problem with this. I don't see how a page can be partially rendered server side then passed to the client to complete, when using a virtual dom. Suppose for example that my pages are running with Main.fullscreen(), I can't just take the DOM that was rendered on the server, set it up as the virtual dom, and then have the client make changes to it as deltas to the DOM. I could just delete all of the server rendered DOM and replace it with the client rendered one through ELM, but you will see the screen blink as this happens.

I guess therefore, that we are limited to all or nothing rendering on one side or the other, for any given DOM subtree? I can see how within a page their could be multiple Elm Html.programs attached to different sections of the page, and during the server rendering they might just act as placeholders for content that will only be rendered client side.

Rupert Smith

unread,
Jan 10, 2017, 9:09:01 AM1/10/17
to Elm Discuss
On Monday, January 9, 2017 at 11:24:57 AM UTC, Rupert Smith wrote:
In my case, I am using server side rendering just for (relatively) static content, so there is practically no application state. I am pretty much there with this simple application model as far as being isomorphic goes.

So I have client and server side renderings of the site now fully working and looking identical.

Server rendered content is under /content/slug but client rendered is under /editor/#slug. For that reason, I have to pass down a function that is used to create links from slugs, into the view:

type alias LinkBuilder msg =
    String -> Html.Attribute msg

view : LinkBuilder msg -> Model.Content -> Html msg

Interestingly, as the server side can only render Html Never, I was able to constrain it to doing just that and have the type checker ensure it is enforceable:

Html.map never <| ContentView.view contentLinker content

This binds the type parameter 'msg' to Never, ensuring it has not been bound to some Msg type. This will be a useful check, because the next step is to pass some kind of editing function into the view too, which will render content in such a way that it does generate events but I need to make sure I don't accidentally introduce some code that will prevent the server side rendering from working.

The principal content type I am using is markdown, and this is rendered with Markdown.toHtml. So I need a function that gives me Markdwon.toHtml for server mode, and one that gives me that or a textbox for client mode.

I'd like if the mouse hovers over an editable item for a while or the user clicks on one, that some kind of box appears around it with a toolbar at the top. Not sure yet if this will work best outwith the normal page flow, stacked above it, or sit within it. I'll try stacking it above it first, and using the techniques described here to get the size and position of the content being worked with:


That is a rough outline of the editing function and how it will be injected into the view logic that is otherwise fully shared between client and server.

Rupert Smith

unread,
Jan 10, 2017, 9:14:08 AM1/10/17
to Elm Discuss
On Tuesday, January 10, 2017 at 2:09:01 PM UTC, Rupert Smith wrote:
view : LinkBuilder msg -> Model.Content -> Html msg

I forgot to mention, the view function does not take the template to apply the content to to produce html, because it is looked up. Within the Content there is something called ContentType which provides the names of 2 templates, the layout and the template - its the same concept as handlebars express uses. The layout is often used to render the page header and footer, and the template for the page body, this allows the same content to be used with different layouts more easily and provides a nice degree of flexibility. The lookup to the layout and template functions is hard coded into 2 Dicts that map their names onto the right functions.

Jen-Mei Wu

unread,
Jan 10, 2017, 11:36:47 PM1/10/17
to Elm Discuss


On Monday, January 9, 2017 at 7:32:56 AM UTC-8, Rupert Smith wrote:
A wee problem with this. I don't see how a page can be partially rendered server side then passed to the client to complete, when using a virtual dom. Suppose for example that my pages are running with Main.fullscreen(), I can't just take the DOM that was rendered on the server, set it up as the virtual dom, and then have the client make changes to it as deltas to the DOM. I could just delete all of the server rendered DOM and replace it with the client rendered one through ELM, but you will see the screen blink as this happens.

Sorry to hear this. Was hoping there was a way to generate Virtual DOM compatible HTML on the server side (a la ReactDOMServer.renderToString). Does anyone know if there's a particularly difficult hurdling block for this or if it's just a thing that no one has gotten around to because it hasn't been important enough for anyone yet?

I'm totally new to Elm. At work we're evaluating some new technology directions, mostly looking at JS frameworks. But Elm keeps coming up. Being able to write a universal (aka isomorphic) app is a big deal to us, though, as it makes a big difference on user experience/performance.


Rupert Smith

unread,
Jan 11, 2017, 4:43:03 AM1/11/17
to Elm Discuss
On Wednesday, January 11, 2017 at 4:36:47 AM UTC, Jen-Mei Wu wrote:
On Monday, January 9, 2017 at 7:32:56 AM UTC-8, Rupert Smith wrote:
A wee problem with this. I don't see how a page can be partially rendered server side then passed to the client to complete, when using a virtual dom. Suppose for example that my pages are running with Main.fullscreen(), I can't just take the DOM that was rendered on the server, set it up as the virtual dom, and then have the client make changes to it as deltas to the DOM. I could just delete all of the server rendered DOM and replace it with the client rendered one through ELM, but you will see the screen blink as this happens.

Sorry to hear this. Was hoping there was a way to generate Virtual DOM compatible HTML on the server side (a la ReactDOMServer.renderToString). Does anyone know if there's a particularly difficult hurdling block for this or if it's just a thing that no one has gotten around to because it hasn't been important enough for anyone yet?

From the React docs:

"If you call ReactDOM.render() on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience."

How does React know that a node has been server rendered? Is there some special attribute set on it to indicate this?

I'm guessing the idea just hasn't been explored in Elm yet. Perhaps with a little hacking on Elms virtual dom code it can be done.

Rupert Smith

unread,
Jan 11, 2017, 4:54:38 AM1/11/17
to Elm Discuss
On Wednesday, January 11, 2017 at 9:43:03 AM UTC, Rupert Smith wrote:
How does React know that a node has been server rendered? Is there some special attribute set on it to indicate this?
 
Actually, there is a clue in the following docs for renderToStaticMarkup():

"Similar to renderToString, except this doesn't create extra DOM attributes such as data-reactid, that React uses internally. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save lots of bytes."

So I guess it inserts a data-reactid atrtibute on the node, and the vitual dom rendering code uses that to know how to treat it differently.

Jen-Mei Wu

unread,
Jan 11, 2017, 1:39:12 PM1/11/17
to Elm Discuss

On Wednesday, January 11, 2017 at 1:54:38 AM UTC-8, Rupert Smith wrote:
So I guess it inserts a data-reactid atrtibute on the node, and the vitual dom rendering code uses that to know how to treat it differently.

Yep. It also adds checksums that the client verifies.

Rupert Smith

unread,
Jan 11, 2017, 2:58:25 PM1/11/17
to Elm Discuss
How does that work? Does the client build the section of the dom corresponding to a server side rendered section, then compare the checksums, and only re-create that section of the dom if its checksuming fails? If the checksum passes, and the dom has event handlers on, then it walks down the actual dom and attaches the event handlers?

You know, I'm thinking this might be something we could try hacking onto the existing Elm vdom code, and contribute back if it turns out well. Given that we know that React manages to do it, I feel like it is achievable.
Reply all
Reply to author
Forward
0 new messages