Elmish.Boot
- Package
- purescript-elmish
- Repository
- collegevine/purescript-elmish
Support for the most common case entry point - i.e. mounting an Elmish
component (i.e. ComponentDef
structure) to an HTML DOM element with a
known ID, with support for server-side rendering.
The function boot
returns what we call BootRecord
- a record of three
functions:
* `mount` -
takes HTML element ID and props¹, creates an instance of
the component, and mounts it to the HTML element in question
* `hydrate` -
same as `mount`, but expects the HTML element to already
contain pre-rendered HTML inside. See React docs for more
on server-side rendering: https://reactjs.org/docs/react-dom.html#hydrate
* `renderToString` -
meant to be called on the server (e.g. by running the code
under NodeJS) to perform the server-side render. Takes props¹
and returns a `String` containing the resulting HTML.
The idea is that the PureScript code would export such BootRecord
for
consumption by bootstrap JavaScript code in the page and/or server-side
NodeJS code (which could be written in PureScript or not). For "plain React"
scenario, the JavaScript code in the page would just call mount
. For
"server-side rendering", the server would first call renderToString
and
serve the HTML to the client, and then the client-side JavaScript code
would call hydrate
.
¹ "props" here is a parameter used to instantiate the component (see example below). It is recommended that this parameter is a JavaScript record (hence the name "props"), because it would likely need to be
supplied by some bootstrap JavaScript code.
Example:
-- PureScript:
module Foo(bootRecord) where
type Props = { hello :: String, world :: Int }
component :: Props -> ComponentDef Aff Message State
component = ...
bootRecord :: BootRecord Props
bootRecord = boot component
// Server-side JavaScript NodeJS code
const foo = require('output/Foo/index.js')
const fooHtml = foo.bootRecord.renderToString({ hello: "Hi!", world: 42 })
serveToClient("<html><body><div id='foo'>" + fooHtml + "</div></body></html>")
// Client-side HTML + JS:
<html>
<body>
<div id='foo'>
... server-side-rendered HTML goes here
</div>
</body>
<script src="foo_bundle.js" />
<script>
Foo.bootRecord.hydrate('foo', { hello: "Hi!", world: 42 })
</script>
</html>
#boot Source
boot :: forall props state msg. (props -> ComponentDef Aff msg state) -> BootRecord props
Creates a boot record for the given component. See comments for this module.
#defaultMain Source
defaultMain :: forall state msg. { def :: ComponentDef Aff msg state, elementId :: String } -> Effect Unit
This function supports the simplest (almost toy?) use case where there is
no server, no server-side rendering, all that exists is an HTML page that
loads the JS bundle (compiled from PureScript), and expects the bundle to
breath life into the page. For this case, declare your bundle entry point
(i.e. your main
function) as a call to defaultMain
, passing it DOM
element ID to bind to and the UI component to bind to it.
Example:
module Main
import MyComponent(def)
import Elmish.Boot as Boot
main :: Effect Unit
main = Boot.defaultMain { elementId: "app", def: def }