I know that the good Evan is going to release soon the version 0.19 that probably will implement the server side rendering.
Nonetheless I want to try a little experiment with one of the SPA that I am working on.
As suggested by this article I used the elm-static-package.
But before running the script I needed to change couple of things in main.elm.
I use Navigation.program instead of Html.program.
The Navigation.program is expecting
init : Navigation.Location -> ( Model, Cmd Msg )
view : Model -> Html Msg
But elm-static=package
is expecting
view : Html Msg
So first I created an initLocation
function that would create a location object:
initLocation : Navigation.Location
initLocation =
{ hash = ""
, host = "localhost:3000"
, hostname = "localhost"
, href = "http://localhost:3000/"
, origin = "http://localhost:3000"
, password = "XXX"
, pathname = "/"
, port_ = "3000"
, protocol = "http:"
, search = ""
, username = "XXX"
}
Then I created a function that return the model:
initModel : Navigation.Location -> Model
initModel location =
...
Then I rename the view to initView
initView : Model -> Html Msg
initView model =
...
My original init function is now
init : Navigation.Location -> ( Model, Cmd Msg )
init location =
( (initModel location), (initCmd location) )
So my main function is
main : Program Never Model Msg
main =
Navigation.program Types.UrlChange
{ init = init
, view = initView
, update = update
, subscriptions = (\_ -> Sub.none)
}
At this point the function view, that is the one used by default by the package elm-static-html, is like:
view : Html Msg
view =
initView (initModel initLocation)
Perfect! Exactly the signature that we needed. A view that would just return Html Msg
There is still a problem. Running elm-static-html, Elm complain that the document.location doesn’t exists. Because in Node it actually doesn’t exists. If I remove the main
function the problem disappear. But the app will not be functional. As a dirty fix I added these few lines inside node_modules/elm-static-html/index.js
:
global.document = global.document || {};
global.document.location = global.document.location || {
hash: "",
host: "localhost:3000",
hostname: "localhost",
href: "http://localhost:3000/",
origin: "http://localhost:3000",
pathname: "/",
port: "3000",
protocol: "http:",
search: "",
};
Now the html is generated properly.
Now the complicated part is to embed this html in the pages and make Elm to activate and overwrite this html from the client side.
From here there are several option. One is what is called hydration
that would let Elm to plug its virtual DOM in the existing html.
Another is to just replace the html page with the one created by Elm.
A third possibility, in case you are Server Side Rendering for SEO purpose, is to detect Googlebot and give it the rendered page while server the SPA version to human users.
If you are interested in Server Side Rendering you may be also interested in