Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,10 @@ the Weasel REPL.

## Example

An example project is included in the `weasel-example` subdirectory of
this project.
The `weasel-example` subdirectory has a small, self-contained project with a
step-by-step tutorial that drives a Weasel REPL into both a web page and a Node
process. It uses the Clojure CLI and runs against this repo's source, so it's a
good way to try the current code end to end.

## Need help?

Expand Down
13 changes: 5 additions & 8 deletions weasel-example/.gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
pom.xml
*jar
/lib/
/classes/
/out/
/out-node/
/target/
.lein-deps-sum
.lein-repl-history
.lein-plugins/
/checkouts/
/.cpcache/
.nrepl-port
*.jar
pom.xml
98 changes: 88 additions & 10 deletions weasel-example/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,100 @@
# Weasel example

## Build
A small project that shows a Weasel REPL driving two targets: a web page and a
Node process. It uses the Clojure CLI (`deps.edn`) and depends on the Weasel
checkout next to it (`:local/root ".."`), so it always runs against the source
in this repo. In your own project you'd depend on a released version instead:

Run:
```clojure
{:deps {weasel/weasel {:mvn/version "0.8.0"}}}
```

You'll need the [Clojure CLI](https://clojure.org/guides/install_clojure), and
Node for the non-browser part.

## Browser

Compile the example:

```sh
clojure -M:build
```

Start a Weasel REPL. The quickest way is a plain terminal REPL, no editor
needed:

```sh
./scripts/start-repl
```

It prints `<< waiting for client to connect ... ` and blocks until the page
connects. In another terminal, serve the project over HTTP and open it:

```sh
python3 -m http.server 8000
# now visit http://localhost:8000
```

Serve it over `http://localhost`, not `file://`: a `file://` page has an opaque
origin that the REPL server rejects, and Closure's dev-mode script loading needs
a real HTTP origin anyway.

Once the page loads it connects back to the REPL, and the terminal drops you at a
`cljs.user=>` prompt running in the browser:

```clojure
cljs.user=> (js/document.getElementById "afield")
cljs.user=> (set! (.-value (js/document.getElementById "afield")) "hi from the REPL")
cljs.user=> weasel-example.foo/baz
456
```

`lein cljsbuild once`
Reload the page and the REPL reconnects on its own - auto-reconnect is on by
default, so you can keep your REPL session across reloads and server restarts.

To fetch the dependencies and build `weasel_example.js`.
### From an editor instead

## REPL
If you'd rather drive it from CIDER, Calva, or another nREPL client, start an
nREPL server with piggieback:

```sh
clojure -M:repl
```

Start a `lein repl` and enter this:
Connect your editor to the port it prints, then start the Weasel REPL from the
session:

```clojure
(require 'weasel.repl.websocket)
(cider.piggieback/cljs-repl
(weasel.repl.websocket/repl-env :ip "0.0.0.0" :port 9001))
(cider.piggieback/cljs-repl (weasel.repl.websocket/repl-env :port 9001))
```

(CIDER users can skip the form: `cider-jack-in-cljs` ships a built-in `weasel`
REPL type.)

## Node

The same client runs outside the browser. Compile the Node entry point:

```sh
clojure -M:node-build
```

Start a Weasel REPL as above (`./scripts/start-repl`), then run the compiled
client:

```sh
node out-node/main.js
```

It connects back over Node's native `WebSocket` - no browser, no extra
dependencies - and the REPL is now evaluating inside the Node process:

```clojure
cljs.user=> (.-version js/process)
cljs.user=> (+ 1 2)
3
```

Once that executes, open `index.html` in your browser and *voila*, your REPL is connected
to the browser.
That's the whole point of the native-WebSocket client: a REPL-driven workflow in
any modern JavaScript runtime, the browser being just one of them.
29 changes: 29 additions & 0 deletions weasel-example/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{:paths ["src"]

;; This in-repo example depends on the Weasel checkout next to it, so it always
;; exercises the current source. In your own project you'd instead pull a
;; released version, e.g. {weasel/weasel {:mvn/version "0.8.0"}}.
:deps {weasel/weasel {:local/root ".."}}

:aliases
{;; clojure -M:build compile the browser example into out/
:build {:main-opts ["-m" "cljs.main"
"-O" "none"
"-d" "out"
"-o" "out/main.js"
"-c" "weasel-example.example"]}

;; clojure -M:node-build compile the Node example into out-node/
:node-build {:main-opts ["-m" "cljs.main"
"-t" "node"
"-O" "none"
"-d" "out-node"
"-o" "out-node/main.js"
"-c" "weasel-example.node"]}

;; clojure -M:repl start an nREPL server with piggieback, so you can
;; connect an editor and piggieback a Weasel REPL onto it
:repl {:extra-deps {nrepl/nrepl {:mvn/version "1.3.1"}
cider/piggieback {:mvn/version "0.6.0"}}
:main-opts ["-m" "nrepl.cmdline"
"--middleware" "[cider.piggieback/wrap-cljs-repl]"]}}}
18 changes: 8 additions & 10 deletions weasel-example/index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Websocket browser-connected REPL through nREPL with Piggieback</title>
<title>Weasel example</title>
</head>
<body>
<div id="content">
<script type="text/javascript" src="out/goog/base.js"></script>
<script type="text/javascript" src="weasel_example.js"></script>
<input type="text" name="afield" id="afield"/>
<script type="text/javascript">
goog.require('weasel_example.example');
</script>
</div>
<h1>Weasel example</h1>
<p>This page is wired to a Weasel REPL. Open your editor's REPL (or the
terminal REPL) and start evaluating ClojureScript here.</p>
<input type="text" id="afield" placeholder="poke me from the REPL">
<script src="out/main.js"></script>
</body>
</html>
27 changes: 0 additions & 27 deletions weasel-example/project.clj

This file was deleted.

10 changes: 4 additions & 6 deletions weasel-example/scripts/start-repl
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#!/bin/sh

CLJSC_CP=$(lein classpath)
# Start a plain terminal Weasel REPL (no editor / nREPL needed). Build the
# browser example first with `clojure -M:build`, then serve index.html over
# http://localhost and open it once this REPL is waiting for a client.

java -server -cp $CLJSC_CP clojure.main -e "
(require '[cljs.repl :as r])
(require '[weasel.repl.websocket :as w])
(r/repl (w/repl-env))
"
exec clojure -M -e "(require '[cljs.repl :as r] '[weasel.repl.websocket :as w]) (r/repl (w/repl-env))"
9 changes: 4 additions & 5 deletions weasel-example/src/weasel_example/example.cljs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
(ns weasel-example.example
(:require [weasel.repl :as repl]
[weasel-example.foo :as foo :refer [baz]]))
[weasel-example.foo :as foo]))

;; Connect back to the Weasel REPL server. Auto-reconnect is on by default, so
;; this survives page reloads and server restarts on its own.
(when-not (repl/alive?)
(repl/connect "ws://localhost:9001"))

(if (repl/alive?)
(println "Loaded example"))

(repl/alive?)
(println "weasel-example loaded; foo/baz =" foo/baz)
9 changes: 2 additions & 7 deletions weasel-example/src/weasel_example/foo.cljs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
(ns weasel-example.foo
[:require [weasel.repl :as repl]])

;;; an auxillary namespace that exposes some symbols, for testing
;;; cross-NS analysis at the REPL.
"An auxiliary namespace exposing a couple of vars, to show cross-namespace
analysis working at the REPL.")

(def foo 1234)
(def baz 456)

(if (repl/alive?)
(println "Loaded foo"))
11 changes: 11 additions & 0 deletions weasel-example/src/weasel_example/node.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(ns weasel-example.node
"A non-browser entry point. Compiled for Node, this connects back to the same
Weasel REPL server over the platform's native WebSocket - no browser involved.
The open connection keeps the Node process alive, so once you run it you can
evaluate ClojureScript in it from the REPL."
(:require [weasel.repl :as repl]
[weasel-example.foo :as foo]))

(repl/connect "ws://localhost:9001" :verbose false)

(println "weasel-example Node client connected; foo/foo =" foo/foo)
Loading