What ways are there of running Elm server side?

1,685 views
Skip to first unread message

Rupert Smith

unread,
Nov 23, 2016, 4:29:58 PM11/23/16
to Elm Discuss
https://github.com/ElmCast/elm-node

Any others?

Also, are they very tied to nodejs? I'm wondering if the javascript interpreter that comes with Java could run it?

I'm looking for ways I could render Html views using Elm, but in such a way that some of the view code can be shared between browser and server side. Generally content to render views from will be in Java, so it would make things easier if I could run Elm in a JVM. Hope this is not too crazy.

Noah Hall

unread,
Nov 23, 2016, 4:35:21 PM11/23/16
to elm-d...@googlegroups.com
The canoncial server-side Elm example is the take-home,
https://github.com/noredink/take-home, written by me. AFAIK it is
still the only full stack-Elm application. It also lists good reasons
as to not take that approach and why it should be avoided at all
costs.

If you want to render code on the server side, you can use
https://github.com/eeue56/elm-server-side-renderer/ which is also
written by me. While it's labelled a work in progress, we use it for
our production tests at NoRedInk and have been doing so for a while
now.

You'll need to set up a port to pull the generated string out, but
it's trivial bit of work to do with the elm-server-side-renderer
project. Just take a look at how something like elm-test pulls values
out through a port.
> --
> 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.

Rupert Smith

unread,
Nov 23, 2016, 4:44:05 PM11/23/16
to Elm Discuss
On Wednesday, November 23, 2016 at 9:35:21 PM UTC, Noah Hall wrote:
The canoncial server-side Elm example is the take-home,
https://github.com/noredink/take-home, written by me. AFAIK it is
still the only full stack-Elm application. It also lists good reasons
as to not take that approach and why it should be avoided at all
costs.

If you want to render code on the server side, you can use
https://github.com/eeue56/elm-server-side-renderer/ which is also
written by me. While it's labelled a work in progress, we use it for
our production tests at NoRedInk and have been doing so for a while
now.

You'll need to set up a port to pull the generated string out, but
it's trivial bit of work to do with the elm-server-side-renderer
project. Just take a look at how something like elm-test pulls values
out through a port.

Thanks man, that sounds interesting. There doesn't appear to be a huge amount of javascript involved, so I guess that makes it fairly portable as to which javascript engine it can be run on?

Rupert Smith

unread,
Nov 23, 2016, 4:44:47 PM11/23/16
to Elm Discuss
On Wednesday, November 23, 2016 at 9:44:05 PM UTC, Rupert Smith wrote:
Thanks man, that sounds interesting. There doesn't appear to be a huge amount of javascript involved, so I guess that makes it fairly portable as to which javascript engine it can be run on?

I've got used to writing Html in Elm now, finding it hard to go back to the idea of stuff like handlebars templates... 

Rupert Smith

unread,
Dec 2, 2016, 5:51:20 AM12/2/16
to Elm Discuss
On Wednesday, November 23, 2016 at 9:35:21 PM UTC, Noah Hall wrote:
The canoncial server-side Elm example is the take-home,
https://github.com/noredink/take-home, written by me. AFAIK it is
still the only full stack-Elm application. It also lists good reasons
as to not take that approach and why it should be avoided at all
costs.

An impressive effort and very brave of you to do all this work and then say don't do this rather than stick at something that is not working out. At any rate, I don't want to do a full stack with Elm.
 
If you want to render code on the server side, you can use
https://github.com/eeue56/elm-server-side-renderer/ which is also
written by me. While it's labelled a work in progress, we use it for
our production tests at NoRedInk and have been doing so for a while
now.

I've been a bit busy recently but can start looking at this today. As I say, plan is to try and run it under Java Nashorn (Java's default javascript engine).  Should be interesting...

Rupert Smith

unread,
Dec 2, 2016, 7:41:43 AM12/2/16
to Elm Discuss
On Friday, December 2, 2016 at 10:51:20 AM UTC, Rupert Smith wrote:
If you want to render code on the server side, you can use
https://github.com/eeue56/elm-server-side-renderer/ which is also
written by me. While it's labelled a work in progress, we use it for
our production tests at NoRedInk and have been doing so for a while
now.

I've been a bit busy recently but can start looking at this today. As I say, plan is to try and run it under Java Nashorn (Java's default javascript engine).  Should be interesting...

First thing, I upgraded the code to Elm 0.18. I created a branch for that here: 


I'm not sure the tests are actually running or what I might need to do to run them with elm-test. When I run the script I get:

 Successfully generated tests.js
 event: Ok "hello"

And trying to run directly with elm-test yields:

$ elm-test BasicTests.elm 
 Success! Compiled 0 modules.                                        
 Successfully generated /tmp/elm_test_116112-28044-4b4y0v.js
 event: Ok "hello"
 The test run failed because it encountered a runtime exception:
 [TypeError: testModule.worker is not a function]

I can create a pull request of that branch if you want to incorporate the elm 0.18 ugprade.


Rupert Smith

unread,
Dec 2, 2016, 7:52:48 AM12/2/16
to Elm Discuss
On Friday, December 2, 2016 at 12:41:43 PM UTC, Rupert Smith wrote:
I'm not sure the tests are actually running or what I might need to do to run them with elm-test.

Seems elm-test has moved on quite a bit from 1.x versions. But 'elm-test init' spits out an example of to use it, so I will try and follow that.

Rupert Smith

unread,
Dec 2, 2016, 9:39:18 AM12/2/16
to Elm Discuss
I've got the tests running now. 3 fail. I'm guessing this is because the internal representation of the DOM has changed as Elm has changed? It seems the attribute "width" is being treated differently to other attributes. Would it be correct to just adjust the tests to match what they are outputting and take that as correct?

 Running 53 tests. To reproduce these results, run: elm-test --seed 466964471

↓ BasicTests
✗ empty divs with many attributes get attributes as a string

    "<div class=\"dog\" value=\"cat\"></div>"
    ╷
    │ Expect.equal
    ╵
    "<div class=\"dog\" value=\"cat\" width=\"50\"></div>"


↓ BasicTests
✗ empty divs with many attributes are decoded to empty div nodes with attributes

    NodeEntry { tag = "div", children = [], facts = { styles = Dict.fromList [], events = Nothing, attributes = Just { width = "50" }, attributeNamespace = Nothing, stringOthers = Dict.fromList [("className","dog"),("value","cat")], boolOthers = Dict.fromList [] }, descendantsCount = 0 }
    ╷
    │ Expect.equal
    ╵
    NodeEntry { tag = "div", children = [], descendantsCount = 0, facts = { styles = Dict.fromList [], events = Nothing, attributes = Nothing, attributeNamespace = Nothing, stringOthers = Dict.fromList [("className","dog"),("value","cat"),("width","50")], boolOthers = Dict.fromList [] } }


↓ BasicTests
✗ query by attribute finds all nodes

    []
    ╷
    │ Expect.equal
    ╵
    [NodeEntry { tag = "div", children = [], descendantsCount = 0, facts = { styles = Dict.fromList [], events = Nothing, attributes = Nothing, attributeNamespace = Nothing, stringOthers = Dict.fromList [("className","dog"),("value","cat"),("width","50")], boolOthers = Dict.fromList [] } }]



TEST RUN FAILED

Duration: 43 ms
Passed:   50
Failed:   3

Rupert Smith

unread,
Dec 5, 2016, 9:11:22 AM12/5/16
to Elm Discuss
On Friday, December 2, 2016 at 10:51:20 AM UTC, Rupert Smith wrote:
Plan is to try and run it under Java Nashorn (Java's default javascript engine).  Should be interesting...

So I have tried running some of the node based elm tools, elm-test and elm-repl under Nashorn. Nashorn requires a shim library to make it node compatible and there are 2 to choose from, Avatar.js and Nodyn.io. Niether worked out of the box and they are both tumbleweed projects, so I think that puts an end to exploring that option.

I don't really need to run these tools under Nashorn, it just might have been convenient to run the repl and run elm-tests to check that tests are behaving the same under Nashorn. But I can always use the pure Elm htlm test runner.

So next plan is to compile a simple example that uses htmlToString to render some HTML and figure out what minimal amount of JS needs to be written to call it, then hope it all runs under Nashorn.

Rupert Smith

unread,
Dec 6, 2016, 5:43:07 AM12/6/16
to Elm Discuss
On Wednesday, November 23, 2016 at 9:35:21 PM UTC, Noah Hall wrote:
You'll need to set up a port to pull the generated string out, but
it's trivial bit of work to do with the elm-server-side-renderer
project. Just take a look at how something like elm-test pulls values
out through a port.

I should have read this more closely, because I spent ages looking at elm-test and wondering how it runs the test Program, and gets results out. In particular it uses testModule.worker to pass the start flags into the program, but I was finding that myModule.worker was undefined. Well of course it is, I was using Html.programWithFlags, when I should have been using Platform.programWithFlags.

Platform.programWithFlags is headerless, so there is no view. Then I look in an elm-test example, and I see that it is indeed using a port to return the results.

I suppose another approach might be to use a Program type that does have a view, set up the javascript environment in such a way that it polyfills enough of the browser environment that the 'normalRenderer' will be able to work. Then render the HTML to the view and extract it from there? It might make server side rendering more naturally fit into Elm to define a particular Program type for it, that has a view.

Will go with the port for now.

Rupert Smith

unread,
Dec 6, 2016, 10:36:27 AM12/6/16
to Elm Discuss
On Tuesday, December 6, 2016 at 10:43:07 AM UTC, Rupert Smith wrote:
Will go with the port for now.

There is something slightly annoying about the port, and that is that processing the Cmd to call the port happens through setTimeout(function, millis). This needs polyfilled on Nashorn, and uses Platform.runLater() which runs it in an internal thread on the JavaFX engine.

All I want is an evaluation of a function from Value -> String (input Json output rendered Html as a String). I don't really need to make use of the event driven side of Elm at all.

To avoid doing this, I think I will go the route of defining some new program types for static rendering server side. I may also want static program types that produce Strings or Json. Once I've got rendering of static Html working, I will look into moving all my code generation templates over to Elm from StringTemplate. I really like having Elm as a functional language for templating, it beats any crappy templating engine I've ever tried.

I'm just now writing a constructor for StringPrograms, that will apply htmlToString. I'm sticking with the Platform.Program type to provide the structure to my Programs, 'flags' is taken as the input type, 'model' as the output type, and 'init' is a function from the input to output types. The msg type is Never, and subsciptions and updates are filled in with noops.

I'll need to crank some javascript for my program types to provide a convenient way to get hold of them in javascript land. Using a trick similar to how Platform.program makes itself reachable from the outwith the Elm compiled code:

function program(impl)
{
return function(flagDecoder)
{
return function(object, moduleName)
{
object['worker'] = function worker(flags)
{

'object' is the elm module, and I can set whatever fields I want on it when constructing a program. I just need to set up a function to pass in the input type and get back the output type.

Here are my Program types and the constructor signature that I am working on for programs that render Html to a String:

type alias HtmlProgram =
    Program Value (Html Never) Never


type alias JsonProgram =
    Program Value Value Never


type alias StringProgram =
    Program Value String Never

htmlToStringProgram : { init : Value -> Html Never } -> StringProgram

I've been able to get Elm running on Nashorn now. Its not fast... I think Nashorn can be pretty quick, its just that it takes a long time for JIT to kick in and optimize things and the first passes through the code are slow with default settings. It took a minimal amount of polyfilling on Nashorn to support it. All code is on github:


Reply all
Reply to author
Forward
0 new messages