From 2a93334a43a3813ca9a20b3108913282cabe3cd3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 17 May 2022 21:07:22 +0200 Subject: [PATCH] Browser repl (#24) --- README.md | 53 +++++++++- bb.edn | 25 ++++- deps.edn | 10 +- resources/public/cljs/nrepl_playground.cljs | 15 +++ resources/public/index.html | 38 ++++--- resources/public/nrepl.html | 14 +++ shadow-cljs.edn | 2 + src/scittle/core.cljs | 27 +++-- src/scittle/nrepl.cljs | 45 ++++++++ src/scittle/reagent.cljs | 108 ++------------------ 10 files changed, 208 insertions(+), 129 deletions(-) create mode 100644 resources/public/cljs/nrepl_playground.cljs create mode 100644 resources/public/nrepl.html create mode 100644 src/scittle/nrepl.cljs diff --git a/README.md b/README.md index 764fed7..c2b2917 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,57 @@ for a minimal full stack web application. See [releases](https://github.com/babashka/scittle/releases) for links to [JSDelivr](https://www.jsdelivr.com) to get versioned artifacts. +## Serving assets + +To serve assets you can use the +[babashka.http-server](https://github.com/babashka/http-server) dependency (with +babashka or Clojure JVM): + +``` clojure +(require '[babashka.http-server :as http]) +(http/serve {:port 1341 :dir "resoures/public"} +@(promise) ;; wait until process is killed +``` + +### REPL + +To connect to a Scittle REPL from your editor, scittle provides an nREPL +implementation. To run the nREPL server you need to follow these steps: + +In babashka or Clojure JVM, use the +[sci.nrepl](https://github.com/babashka/sci.nrepl) dependency and run: + +``` +(require 'sci.nrepl.browser-server :as nrepl) +(nrepl/start! {:nrepl-port 1339 :websocket-port 1340}) +``` + +This will run an nREPL server on port 1339 and a websocket server on port 1340. +Your editor's nREPL client will connect to port 1339 and your browser, running +scittle, will connect to port 1340. The nREPL server forwards messages to the +browser via the websocket connection. + +In your scittle website, you will need to include the following, in addition to +the normal routine: + +``` + + +``` + +Also include the CLJS file that you want to evaluate with nREPL: + +``` + +``` + +Then visit `cljs/script.cljs` in your editor and connect to the nREPL server, +and start evaluating! + +See the `resources/public/nrepl.html` file for an example. When you run `bb dev` +in this repository, and then open `http://localhost:1341/nrepl.html` you should +be able evaluate expressions in `resources/public/cljs/nrepl_playground.cljs`. + ## Tasks Run `bb tasks` to see all available tasks: @@ -33,6 +84,6 @@ Idea by Arne Brasseur a.k.a [plexus](https://github.com/plexus). ## License -Copyright © 2021 Michiel Borkent +Copyright © 2021 - 2022 Michiel Borkent Distributed under the EPL License. See LICENSE. diff --git a/bb.edn b/bb.edn index 1eef13f..9a89e71 100644 --- a/bb.edn +++ b/bb.edn @@ -1,4 +1,10 @@ -{:tasks +{:deps {io.github.babashka/sci.nrepl + #_{:local/root "../sci.nrepl"} + {:git/sha "c14b5b4ef4390ff206cdb71f763f327799f5e853"} + io.github.babashka/http-server + {:git/sha "b38c1f16ad2c618adae2c3b102a5520c261a7dd3"}} + + :tasks {:requires ([babashka.fs :as fs] [cheshire.core :as json] [babashka.process :as p :refer [process]]) @@ -8,8 +14,23 @@ (fs/delete-tree ".cpcache") (fs/delete-tree ".shadow-cljs"))} + shadow:watch {:doc "Development build. Starts webserver and watches for changes." + :task (clojure "-M:dev -m shadow.cljs.devtools.cli watch main")} + + http-server {:doc "Starts http server for serving static files" + :requires ([babashka.http-server :as http]) + :task (do (http/serve {:port 1341 :dir "resources/public"}) + (println "Serving static assets at http://localhost:1341"))} + + browser-nrepl {:doc "Start browser nREPL" + :requires ([sci.nrepl.browser-server :as bp]) + :task (bp/start! {})} + + -dev {:depends [shadow:watch browser-nrepl http-server]} + dev {:doc "Development build. Starts webserver and watches for changes." - :task (clojure "-M:dev -m shadow.cljs.devtools.cli watch main")} + :task (do (run '-dev {:parallel true}) + (deref (promise)))} prod {:doc "Builds production artifacts." :task (clojure {:extra-env {"SCI_ELIDE_VARS" "true"}} diff --git a/deps.edn b/deps.edn index fbc1235..f9461c6 100644 --- a/deps.edn +++ b/deps.edn @@ -2,12 +2,18 @@ :deps {org.clojure/clojure {:mvn/version "1.10.3"} - org.babashka/sci {:mvn/version "0.3.1"} + org.babashka/sci {:mvn/version "0.3.5"} reagent/reagent {:mvn/version "1.1.0"} cljsjs/react {:mvn/version "17.0.2-0"} cljsjs/react-dom {:mvn/version "17.0.2-0"} cljsjs/react-dom-server {:mvn/version "17.0.2-0"} - cljs-ajax/cljs-ajax {:mvn/version "0.8.3"}} + cljs-ajax/cljs-ajax {:mvn/version "0.8.3"} + + io.github.babashka/sci.nrepl + #_{:local/root "../sci.nrepl"} + {:git/sha "e83421ce9349c36df56a2eb936196dbb65b0de63"} + io.github.babashka/sci.configs + {:git/sha "fcd367c6a6115c5c4e41f3a08ee5a8d5b3387a18"}} :aliases {:dev diff --git a/resources/public/cljs/nrepl_playground.cljs b/resources/public/cljs/nrepl_playground.cljs new file mode 100644 index 0000000..2c71307 --- /dev/null +++ b/resources/public/cljs/nrepl_playground.cljs @@ -0,0 +1,15 @@ +(ns nrepl-playground) + +(+ 1 2 3) + +(-> + (js/document.getElementsByTagName "body") + first + (.append + (doto (js/document.createElement "p") + (.append + (js/document.createTextNode "there"))))) + +(defn foo []) + +(js/alert "Isn't this cool? :)") diff --git a/resources/public/index.html b/resources/public/index.html index 82ea23f..c2720e5 100644 --- a/resources/public/index.html +++ b/resources/public/index.html @@ -19,10 +19,10 @@ (def state (r/atom {:clicks 0})) (defn my-component [] - [:div - [:p "Clicks: " (:clicks @state)] - [:p [:button {:on-click #(swap! state update :clicks inc)} - "Click me!"]]]) + [:div + [:p "Clicks: " (:clicks @state)] + [:p [:button {:on-click #(swap! state update :clicks inc)} + "Click me!"]]]) (rdom/render [my-component] (.getElementById js/document "app")) @@ -41,15 +41,15 @@ (require '[goog.object :as gobject]) (doseq [code code-tags] - (let [src (.getAttribute code "data-src") - req (js/XMLHttpRequest.)] - (.open req "GET" src true) - (set! (.-onload req) - (fn [] - (let [response (gobject/get req "response")] - (set! (.-innerText code) response) - (.highlightElement js/hljs code)))) - (.send req))) + (let [src (.getAttribute code "data-src") + req (js/XMLHttpRequest.)] + (.open req "GET" src true) + (set! (.-onload req) + (fn [] + (let [response (gobject/get req "response")] + (set! (.-innerText code) response) + (.highlightElement js/hljs code)))) + (.send req))) @@ -60,7 +60,7 @@
-
+

Scittle

What is this?

@@ -73,7 +73,7 @@ To embed scittle in your website, it is recommended to use the links published to the releases - page. + page. Include scittle.js and write a script tag where type is set @@ -90,7 +90,7 @@ When you have a file on your server, say cljs/script.cljs, you can load it using the src attribute:

-<script src="cljs/script.cljs" type="application/x-scittle"></script>
+        <script src="cljs/script.cljs" type="application/x-scittle"></script>
     
@@ -118,6 +118,12 @@ Click me! + +

REPL

+ + To connect to a REPL with Scittle, + see README.md +

Examples