@@ -20,6 +20,7 @@ module Obelisk.Backend
2020 , runBackendWith
2121 -- * Configuration of backend
2222 , GhcjsWidgets(..)
23+ , GhcjsWasmAssets(..)
2324 , defaultGhcjsWidgets
2425 -- * all.js script loading functions
2526 , deferredGhcjsScript
@@ -73,7 +74,7 @@ data Backend backendRoute frontendRoute = Backend
7374data BackendConfig frontendRoute = BackendConfig
7475 { _backendConfig_runSnap :: !(Snap () -> IO ()) -- ^ Function to run the snap server
7576 , _backendConfig_staticAssets :: !StaticAssets -- ^ Static assets
76− , _backendConfig_ghcjsWidgets :: !(GhcjsWidgets (Text -> FrontendWidgetT (R frontendRoute) ()))
77+ , _backendConfig_ghcjsWidgets :: !(GhcjsWidgets (GhcjsWasmAssets -> FrontendWidgetT (R frontendRoute) ()))
7778 -- ^ Given the URL of all.js, return the widgets which are responsible for
7879 -- loading the script.
7980 } deriving (Generic)
@@ -92,10 +93,14 @@ data GhcjsWidgets a = GhcjsWidgets
9293 -- ^ A script widget, placed in the document body
9394 } deriving (Functor, Generic)
9495
96+data GhcjsWasmAssets = GhcjsWasmAssets
97+ { _ghcjsWasmAssets_allJs :: Text
98+ , _ghcjsWasmAssets_wasm :: Maybe (Text, Text)
99+ }
95100
96101-- | Given the URL of all.js, return the widgets which are responsible for
97102-- loading the script. Defaults to 'preloadGhcjs' and 'deferredGhcjsScript'.
98−defaultGhcjsWidgets :: GhcjsWidgets (Text -> FrontendWidgetT r ())
103+defaultGhcjsWidgets :: GhcjsWidgets (GhcjsWasmAssets -> FrontendWidgetT r ())
99104defaultGhcjsWidgets = GhcjsWidgets
100105 { _ghcjsWidgets_preload = preloadGhcjs
101106 , _ghcjsWidgets_script = deferredGhcjsScript
@@ -134,7 +139,7 @@ defaultStaticAssets = StaticAssets
134139
135140defaultFrontendGhcjsAssets :: StaticAssets
136141defaultFrontendGhcjsAssets = StaticAssets
137− { _staticAssets_processed = "frontend.jsexe.assets"
142+ { _staticAssets_processed = "frontend.wasm.assets"
138143 , _staticAssets_unprocessed = "frontend.jsexe"
139144 }
140145
@@ -167,6 +172,11 @@ renderAllJsPath :: Encoder Identity Identity (R (FullRoute a b)) PageName -> Tex
167172renderAllJsPath validFullEncoder =
168173 renderObeliskRoute validFullEncoder $ FullRoute_Frontend (ObeliskRoute_Resource ResourceRoute_Ghcjs) :/ ["all.js"]
169174
175+renderWasmPaths :: Encoder Identity Identity (R (FullRoute a b)) PageName -> (Text, Text)
176+renderWasmPaths validFullEncoder = (,)
177+ (renderObeliskRoute validFullEncoder $ FullRoute_Frontend (ObeliskRoute_Resource ResourceRoute_Ghcjs) :/ [])
178+ (renderObeliskRoute validFullEncoder $ FullRoute_Frontend (ObeliskRoute_Resource ResourceRoute_Ghcjs) :/ ["frontend.wasm"])
179+
170180serveObeliskApp
171181 :: (MonadSnap m, HasCookies m, MonadFail m)
172182 => (R appRoute -> Text)
@@ -243,11 +253,12 @@ runBackendWith (BackendConfig runSnap staticAssets ghcjsWidgets) backend fronten
243253 Identity r -> case r of
244254 FullRoute_Backend backendRoute :/ a -> serveRoute $ backendRoute :/ a
245255 FullRoute_Frontend obeliskRoute :/ a ->
246− serveDefaultObeliskApp routeToUrl (($ allJsUrl) <$> ghcjsWidgets) (serveStaticAssets staticAssets) frontend publicConfigs $
256+ serveDefaultObeliskApp routeToUrl (($ GhcjsWasmAssets allJsUrl (Just wasmUrls)) <$> ghcjsWidgets) (serveStaticAssets staticAssets) frontend publicConfigs $
247257 obeliskRoute :/ a
248258 where
249259 routeToUrl (k :/ v) = renderObeliskRoute validFullEncoder $ FullRoute_Frontend (ObeliskRoute_App k) :/ v
250260 allJsUrl = renderAllJsPath validFullEncoder
261+ wasmUrls = renderWasmPaths validFullEncoder
251262
252263renderGhcjsFrontend
253264 :: (MonadSnap m, HasCookies m)
@@ -263,13 +274,33 @@ renderGhcjsFrontend urlEnc ghcjsWidgets route configs f = do
263274
264275-- | Preload all.js in a link tag.
265276-- This is the default preload method.
266−preloadGhcjs :: Text -> FrontendWidgetT r ()
267−preloadGhcjs allJsUrl = elAttr "link" ("rel" =: "preload" <> "as" =: "script" <> "href" =: allJsUrl) blank
277+preloadGhcjs :: GhcjsWasmAssets -> FrontendWidgetT r ()
278+preloadGhcjs (GhcjsWasmAssets allJsUrl mWasm) = case mWasm of
279+ Nothing -> elAttr "link" ("rel" =: "preload" <> "as" =: "script" <> "href" =: allJsUrl) blank
280+ Just _ -> pure ()
268281
269282-- | Load the script from the given URL in a deferred script tag.
270283-- This is the default method.
271−deferredGhcjsScript :: Text -> FrontendWidgetT r ()
272−deferredGhcjsScript allJsUrl = elAttr "script" ("type" =: "text/javascript" <> "src" =: allJsUrl <> "defer" =: "defer") blank
284+deferredGhcjsScript :: GhcjsWasmAssets -> FrontendWidgetT r ()
285+deferredGhcjsScript (GhcjsWasmAssets allJsUrl mWasm) = case mWasm of
286+ Nothing -> elAttr "script" ("type" =: "text/javascript" <> "src" =: allJsUrl <> "defer" =: "defer") blank
287+ Just v -> wasmScript v
288+
289+wasmScript :: (Text, Text) -> FrontendWidgetT r ()
290+wasmScript (jsaddleAssets, wasmUrl) = do
291+ let sendMsgWorkerJs = jsaddleAssets <> "/jsaddle_sendMsgWorker.js"
292+ jsaddleJs = jsaddleAssets <> "/jsaddle.js"
293+ workerRunnerJs = jsaddleAssets <> "/worker_runner.js"
294+ elAttr "script" ("type" =: "text/javascript" ) $ text $
295+ "var jsaddle_sendMsgWorkerPath = '" <> sendMsgWorkerJs <> "';"
296+ elAttr "script" ("type" =: "text/javascript" <> "src" =: jsaddleJs) blank
297+ elAttr "script" ("type" =: "text/javascript") $ text $ mconcat $
298+ [ "var jsaddleVals = jsaddleJsInit();"
299+ , "const worker = new Worker(\"" <> workerRunnerJs <> "\");"
300+ , "worker.postMessage({ url: \"" <> wasmUrl <> "\""
301+ , " , jsaddleVals: jsaddleVals }"
302+ , " , [jsaddleVals.jsaddleListener]);"
303+ ]
273304
274305-- | An all.js script which is loaded after waiting for some time to pass. This
275306-- is useful to ensure any CSS animations on the page can play smoothly before