Search code examples
clojurescriptreagent

How do you deploy a clojurescript reagent app?


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

Solution

  • 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.