@@ -989,7 +989,7 @@ NOTE: `:duct/logger` is often defined as an optional dependency, via a
989989*refset*. Without explicitly specifying this as one of the keys, the
990990migrator will run without logging.
991991
992- === Database-Driven Todos
992+ === Database Integration
993993
994994Now that we have a database table and a web server, it's time to put the
995995two together. The database we pass to the index function can be used to
@@ -1102,6 +1102,92 @@ The second addition is the `new-todo` function. This inserts a new row
11021102into the todo table, then returns a "`303 See Other`" response that will
11031103redirect the browser back to the index page.
11041104
1105- If we reset via the REPL and check http://localhost:3000/, you should
1105+ If you reset via the REPL and check http://localhost:3000/, you should
11061106see a text input box at the bottom of the todo list, allowing more todo
11071107items to be added.
1108+
1109+ === ClojureScript
1110+
1111+ At this point we're hitting the limitations of what we can do with HTML
1112+ alone. JavaScript allows for more sophisticated user interaction, and in
1113+ the Clojure ecosystem we have _ClojureScript_, a version of Clojure that
1114+ compiles to JavaScript.
1115+
1116+ You be unsurprised to learn that Duct has a module for compiling
1117+ ClojureScript. As always we begin with our dependencies, and add the
1118+ '`cljs`' module.
1119+
1120+ .deps.edn
1121+ [,clojure]
1122+ ----
1123+ {:deps {org.clojure/clojure {:mvn/version "1.12.0"}
1124+ org.duct-framework/main {:mvn/version "0.1.5"}
1125+ org.duct-framework/module.cljs {:mvn/version "0.5.0"}
1126+ org.duct-framework/module.logging {:mvn/version "0.6.5"}
1127+ org.duct-framework/module.web {:mvn/version "0.12.0"}
1128+ org.duct-framework/module.sql {:mvn/version "0.7.1"}
1129+ org.xerial/sqlite-jdbc {:mvn/version "3.47.0.0"}
1130+ com.github.seancorfield/next.jdbc {:mvn/version "1.3.955"}}
1131+ :aliases {:duct {:main-opts ["-m" "duct.main"]}}}
1132+ ----
1133+
1134+ As before, we can load these dependencies by either restarting the REPL,
1135+ or by using the `(sync-deps)` command.
1136+
1137+ Next, the `:duct.module/cljs` key needs to be added to the Duct
1138+ configuration file.
1139+
1140+ .duct.edn
1141+ [,clojure]
1142+ ----
1143+ {:vars {jdbc-url {:default "jdbc:sqlite:todo.db"}}
1144+ :system
1145+ {:duct.module/logging {}
1146+ :duct.module/sql {}
1147+ :duct.module/cljs
1148+ {:builds {:client todo.client}}
1149+ :duct.module/web
1150+ {:features #{:site}
1151+ :handler-opts {:db #ig/ref :duct.database/sql}
1152+ :routes [["/" {:get :todo.routes/index
1153+ :post :todo.routes/new-todo}]]}}}
1154+ ----
1155+
1156+ The module requires a `:builds` option to be set. This connects a
1157+ build name to a ClojureScript namespace, or collection of namespaces. In
1158+ the above example, the `todo.client` namespace will be compiled to the
1159+ `target/cljs/client.js` JavaScript file. When Duct is started, this will
1160+ be accessible at: <http://localhost:3000/cljs/client.js>.
1161+
1162+ Before `todo.client` can be compiled, we first need to write it. In
1163+ order to check everything works, we'll have it trigger an JavaScript
1164+ alert.
1165+
1166+ .src/todo/client.cljs
1167+ [,clojure]
1168+ ----
1169+ (ns todo.client)
1170+
1171+ (js/alert "Hello World")
1172+ ----
1173+
1174+ In order to test this script compiles correct, we'll add the script to
1175+ our `index` function in the `todo.routes` namespace.
1176+
1177+ [,clojure]
1178+ ----
1179+ (defn index [{:keys [db]}]
1180+ (fn [_request]
1181+ [:html {:lang "en"}
1182+ [:head
1183+ [:title "Todo"]
1184+ [:script {:src "/cljs/client.js"}]]
1185+ [:body
1186+ [:ul
1187+ (for [rs (jdbc/execute! db [list-todos])]
1188+ [:li (:todo/description rs)])
1189+ [:li (create-todo-form)]]]]))
1190+ ----
1191+
1192+ If you restart the REPL and check http://localhost:3000, you should see
1193+ the alert.
0 commit comments