Skip to content

Commit d9cab25

Browse files
authored
Fix server side rendering (#730)
Fixes #706.
1 parent c3ae5b3 commit d9cab25

File tree

6 files changed

+43
-16
lines changed

6 files changed

+43
-16
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ jobs:
269269
- name: Run Playwright tests against static assets
270270
run: |
271271
bb test:static-app :sha ${{ github.sha }} :skip-install true
272-
bb test:static-app :skip-install true :url https://snapshots.nextjournal.com/clerk/book/${{ github.sha }}/book/index.html :index false :selector "span:has-text(\"Book of Clerk\")"
272+
bb test:static-app :skip-install true :url https://snapshots.nextjournal.com/clerk/book/${{ github.sha }}/book/index.html :index false :selector "h1:has-text(\"Book of Clerk\")"
273+
bb test:static-app :skip-install true :url https://snapshots.nextjournal.com/clerk-ssr/build/${{ github.sha }}/index.html :index false :selector "h1:has-text(\"Rule 30\")"
273274
274275
deploy:
275276
needs: [build-and-upload-viewer-resources, test]

src/nextjournal/clerk/builder.clj

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -163,18 +163,36 @@
163163
:path->doc path->doc
164164
:paths (vec (keys path->doc)))))
165165

166+
(defn- node-ssr!
167+
[{:keys [viewer-js state]
168+
:or {viewer-js
169+
;; for local REPL testing
170+
"./public/js/viewer.js"}}]
171+
(sh {:in (str "import '" viewer-js "';"
172+
"globalThis.CLERK_SSR = true;"
173+
"console.log(nextjournal.clerk.sci_env.ssr(" (pr-str (pr-str state)) "))")}
174+
"node"
175+
"--abort-on-uncaught-exception"
176+
"--experimental-network-imports"
177+
"--input-type=module"
178+
"--trace-warnings"))
179+
180+
(comment
181+
(declare so) ;; captured in REPL in ssr! function
182+
(node-ssr! {:state so})
183+
)
184+
166185
(defn ssr!
167186
"Shells out to node to generate server-side-rendered html."
168187
[{:as static-app-opts :keys [report-fn resource->url]}]
169188
(report-fn {:stage :ssr})
170-
(let [{duration :time-ms :keys [result]}
171-
(eval/time-ms (sh {:in (str "import '" (resource->url "/js/viewer.js") "';"
172-
"console.log(nextjournal.clerk.sci_env.ssr(" (pr-str (pr-str static-app-opts)) "))")}
173-
"node"
174-
"--abort-on-uncaught-exception"
175-
"--experimental-network-imports"
176-
"--input-type=module"
177-
"--trace-warnings"))
189+
(let [doc (get (:path->doc static-app-opts) (:current-path static-app-opts))
190+
static-app-opts (-> (assoc static-app-opts :doc doc)
191+
(dissoc :path->doc)
192+
(assoc :render-router :serve))
193+
{duration :time-ms :keys [result]}
194+
(eval/time-ms (node-ssr! {:viewer-js (resource->url "/js/viewer.js")
195+
:state static-app-opts}))
178196
{:keys [out err exit]} result]
179197
(if (= 0 exit)
180198
(do
@@ -203,9 +221,9 @@
203221
(spit (fs/file out-path (str (or (not-empty path) "index") ".edn"))
204222
(viewer/->edn doc))
205223
(spit out-html (view/->html (-> static-app-opts
206-
(dissoc :path->doc)
207224
(assoc :current-path path)
208225
(cond-> ssr? ssr!)
226+
(dissoc :path->doc)
209227
cleanup))))))
210228
(when browse?
211229
(browse/browse-url (if-let [server-url (and (= out-path "public/build") (webserver/server-url))]

src/nextjournal/clerk/render.cljs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,8 @@
847847
:status (.-status r)
848848
:headers (.-headers r)})))))
849849
(then read-response+show-progress)
850-
(then (fn [edn] (set-state! {:doc (read-string edn)}) {:ok true}))
850+
(then (fn [edn]
851+
(set-state! {:doc (read-string edn)}) {:ok true}))
851852
(catch (fn [e] (js/console.error "Fetch failed" e)
852853
(set-state! {:doc {:nextjournal/viewer {:render-fn (constantly [:<>])} ;; FIXME: make :error top level on state
853854
:nextjournal/value {:error (viewer/present e)}}})

src/nextjournal/clerk/render/hooks.cljs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@
7575
(defn use-ref
7676
"React hook: useRef. Can also be used like an atom."
7777
([] (use-ref nil))
78-
([init] (specify-atom! (react/useRef init))))
78+
([init] (if (unchecked-get js/globalThis "CLERK_SSR")
79+
(atom init)
80+
(specify-atom! (react/useRef init)))))
7981

8082
(defn ^:private eval-fn
8183
"Invoke (f x) if f is a function, otherwise return f"

src/nextjournal/clerk/sci_env.cljs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
[applied-science.js-interop :as j]
1616
[cljs.math]
1717
[cljs.reader]
18+
[cljs.repl]
1819
[clojure.string :as str]
1920
[edamame.core :as edamame]
2021
[goog.object]

ui_tests/playwright_tests.cljs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,20 @@
5252
(p/do (goto page url)
5353
(.waitForLoadState page "networkidle")
5454
(p/let [selector (or (:selector @!opts) "div")
55-
loc (.locator page selector)
56-
loc (.first loc #js {:timeout 10000})]
57-
(is (.isVisible loc #js {:timeout 10000})))))
55+
_ (prn :selector selector)
56+
loc (.locator page selector #js {:timeout 10000})
57+
loc (.first loc #js {:timeout 10000})
58+
_ (.waitFor loc #js {:state "visible"})
59+
visible? (.isVisible loc)]
60+
(is visible?))))
5861
([page url link]
5962
(p/let [txt (.innerText link)]
6063
(println "Visiting" (str url "#/" txt))
6164
(p/do (.click link)
6265
(p/let [loc (.locator page "div")
6366
loc (.first loc #js {:timeout 10000})
64-
visible? (.isVisible loc #js {:timeout 10000})]
67+
_ (.waitFor loc #js {:state "visible"})
68+
visible? (.isVisible loc)]
6569
(is visible?))))))
6670

6771
(deftest index-page-test

0 commit comments

Comments
 (0)