Advanced usage
Building and deploying
Deku for fun and profit (but mostly profit)
One way to make money with Deku is to ask all your developer friends to send you a dollar in the mail when they use Deku. Then, they can recruit their friends, who will send them a dollar and send you a nominal commission. And so forth and so on.
Another way is building and deploying apps. This section focuses on the latter.
Single Page Apps
Most PureScript apps export their main function as main
from a file called Main.purs
. This is then imported into an index.js
file, which is the entry point for a single-page app (SPA).
Deku is no different. Take the following Main.purs
.
module Main where
import Prelude
import Deku.Toplevel (runInBody)
import Effect (Effect)
import ExampleAssitant (ExampleSignature)
import Deku.Control (text_)
import Deku.Toplevel (runInBody)
main :: Effect Unit
main = void $ runInBody (text_ "I’m main!")
You would then define your index.js
thusly:
import { main } from "./output/Main/";
main();
From here, you can use any old bundler, like vite
or esbuild
to bundle the index into a simple html file and deploy to your hosting service of choice.
SSG, SSR and Vercel
Deku can also be deployed as server-side generated html or server-side rendered app. The easiest way to do this is to use vike
for your build and vercel
for your deploy.
To render your page as HTML, you can use ssrInBody
from Deku.Toplevel
.
module Main where
import Prelude
import Deku.Toplevel (runInBody)
import Effect (Effect)
import ExampleAssitant (ExampleSignature)
import Deku.Control (text_)
import Deku.Toplevel (ssrInBody)
main :: Effect Unit
main = void $ ssrInBody (text_ "I’m main!")
This needs a server-side DOM polyfill like jsdom
to work. The docs you’re reading are built this way. Check out the source code for this page and be bedazzled by the magic of its pre-rendered HTML.
If you’re just building a static site, you can use ssrInBody
and ignore the return value. However, most sites, including this one, have interactive bits. In that case, stash the output of ssrInBody
and feed it to hydrateInBody
as the first argument.
module MyAwesomeApp where
myAwesomeApp = text_ "I’m awesome!"
-- after which one does ...
module SSR where
import Prelude
import Deku.Toplevel (runInBody)
import Effect (Effect)
import ExampleAssitant (ExampleSignature)
import Deku.Control (text_)
import MyAwesomeApp (myAwesomeApp)
import Deku.Toplevel (ssrInBody, SSROutput)
ssr :: Effect SSROutput
ssr = ssrInBody myAwesomeApp
-- followed by ...
module Hydrate where
import Prelude
import Deku.Toplevel (runInBody)
import Effect (Effect)
import ExampleAssitant (ExampleSignature)
import Deku.Control (text_)
import MyAwesomeApp (myAwesomeApp)
import Deku.Toplevel (hydrateInBody, SSROutput)
hydrate :: SSROutput -> Effect Unit
hydrate cache = hydrateInBody cache myAwesomeApp
After the initial argument to hydrateInBody
, the signature is identical to the veritable workhorse runInBody
that you've been using all along.
Render the right app
If you render an app using ssrInBody
and then hydrate a different app using hydrateInBody
, I can't even begin to describe the ill fate that will befall you. Even writing about it makes one's fingers ache. Don't do it. Hydrate the same app you rendered!
For a no-frills example of SSR, check out vike-deku-minimal
. For an example that uses client-side routing like these docs, check out vike-deku-client-routing
. In both of these examples, SSROutput
is serialized to and from JSON.