How do you deploy a clojurescript reagent app?

722 views Asked by At

Reducing the problem to the simplest form:

$ lein new reagent experiment
$ cd experiment
$ lein do clean, uberjar
$ cat >index.html <<EOF
<html>
  <head>
    <meta charset="utf-8">
    <meta content="width=device-width, initial-scale=1" name="viewport">
    <link href="resources/public/css/site.css" rel="stylesheet" type="text/css">
  </head>
  <body class="body-container">
    Hello World
    <div id="app">
      <script src="target/cljsbuild/public/js/app.js" type="text/javascript"></script>
    </div>
  </body>
</html>
EOF

Pointing the browser to localhost:5000 works when using 'foreman start', but does not when serving out of nginx. (Meaning, putting this directory in a directory served by nginx will load the css and js, will show "Hello World", but the javascript has errors.) The following two errors appear in the browser's console:

app.js:451 Error rendering component (in Vn)
(anonymous) @ app.js:451
app.js:471 Uncaught Error: Assert failed: Invalid Hiccup form: [nil]
 (in Vn)
(valid-tag? tag)
    at Mk (app.js:471)
    at Jk (app.js:473)
    at Dk (app.js:475)
    at Ik (app.js:470)
    at Mk (app.js:472)
    at Jk (app.js:473)
    at bk (app.js:449)
    at app.js:451
    at uj (app.js:428)
    at vj (app.js:429)
    at Tj (app.js:448)
    at t.render (app.js:451)
    at p._renderValidatedComponentWithoutOwnerOrContext (app.js:25)
    at p._renderValidatedComponent (app.js:25)
    at performInitialMount (app.js:25)
    at p.mountComponent (app.js:25)
    at Object.mountComponent (app.js:27)
    at performInitialMount (app.js:25)
    at p.mountComponent (app.js:25)
    at Object.mountComponent (app.js:27)
    at i (app.js:26)
    at r.perform (app.js:27)
    at u (app.js:26)
    at r.perform (app.js:27)
    at Object.batchedUpdates (app.js:26)
    at Object.a [as batchedUpdates] (app.js:27)
    at Object._renderNewRootComponent (app.js:26)
    at Object._renderSubtreeIntoContainer (app.js:26)
    at Sk (app.js:476)
    at app.js:554
    at app.js:554
    at app.js:555
2

There are 2 answers

4
kanaka On BEST ANSWER

Okay, I believe something about your nginx configuration is breaking the clientside secretary routing. As you noted a similar error happens if you load the file from the filesystem (file://.../index.html).

One thing that the default reagent template doesn't provide is a default route for ".../index.html". I suspect that might help in the nginx case. I would add the following to src/cljs/experiment/core.cljs and rebuild:

(secretary/defroute "/index.html" []
  (session/put! :current-page #'home-page))

With that change, I was able to successfully load the page by serving it using the standard nginx docker container (and then browsing to localhost:5001):

docker run --name nginx -v `pwd`:/usr/share/nginx/html:ro -d -p 5001:80 nginx

You might want to compare the default configuration of that nginx docker image to your own configuration to determine what the root cause of your issue is.

0
Brian On

There were two problems here, both of which kanaka's help was instrumental in ferreting out.

  1. the incoming url from nginx included "/index.html", for which there was not a secretary route. See kanaka's solution above.
  2. the secretary routes assume urls are off of root. In my case, this app is one of many, so it resided in a subfolder at https://www.murphydye.com/experiment/index.html.

One solution for this is to modify #'current-page as such:

(defn current-page []
  [:div (or (session/get :current-page) #'home-page)])

This gets us to the home-page when nothing matches, and also solves problem #1 (we no longer need the additional defroute "/index.html").

I say "one solution" because as you click links, the url bar will again assume it is off of root, e.g., click the about link and the url bar will show /about, not /experiment/about. Everything works because it doesn't go to the server to load the erroneous url, but bookmarking it will not work. There is surely another way to handle this, but this solves both problems sufficiently for now.

Thanks again kanaka!