luminus-framework/luminus

How to include ClojureScript into HTML page?

nenadmitrovic opened this issue · 1 comments

I am following guestbook example from the book Web Development With Clojure 3rd edition. I am struggling with including ClojureScript namespace into HTML document. Everything is working fine with example where I have one core.cljs. With that file, only I have to do is to include this piece of code into home.html document:

{% extends "base.html" %}
{% block content %}
<input id="token" type="hidden" value="{{csrf-token}}">
<div id="content"></div>
{% endblock %}
{% block page-scripts %}
{% script "/js/app.js" %}
{% endblock %}

As I mentioned, everything is ok in this situation. But when I created additional ClojureScript file and name it test.cljs and included that in the same way in the new HTML document named test.html I see errors in the console such as "Target container is not a DOM element.". I think that something is wrong with this part:

{% block page-scripts %}
{% script "/js/app.js" %}
{% endblock %}

But I can't figure out how to solve this. Actually, my question maybe should be: How to include ClojureScript into HTML file?. Is the only way this piece of code?

{% block page-scripts %}
{% script "/js/app.js" %}
{% endblock %}

Or, maybe I should change {% script "/js/app.js" %} part of this snippet?

Or even better, when I create simple HTML file without extending any base.html file, how to add clojurescript namespace, how to reference it? You know, like javascript helloworld example

<script src="myscripts.js"></script>

How to do this in ClojureScript?

Hi there,
Cljsbuild will compile all ClojureScript files that are in your source paths (which are also required by your main namespace) into a single JavaScript file. In the case of the guestbook app in Web Development with Clojure 3rd Edition, the file is /js/app.js, and the main is guestbook.core. If you wish to add a new namespace, say guestbook.foo, you'd have to create a file src/cljs/guestbook/foo.cljs that could look like this:

(ns guestbook.foo)

(defn pop-up []
  (js/alert "Hello from foo!"))

and then require it from guestbook.core like so:

(ns guestbook.core
  (:require [guestbook.foo :as foo]))

and then you could call (foo/pop-up) from guestbook.core and have a nice alert pop up.

If you want two different pages with different behaviour, there are a few ways to achieve this.

The first is using modules to compile different JavaScript files by declaring different main namespaces. See here for more details. With this approach, you can include different script tags in your HTML to require the different compiled files like you describe.

The more common approach in my experience is to use front-end routing to simulate multiple pages. This will be covered in Chapter 7, and will use Reitit Frontend. This allows you to run different code based on the URL in the browser, and can use the HTML5 History API to navigate without requesting a full page from the server.

Hope that helps. Let me know if you have any other questions.

Happy Coding!