關於發送代碼到 shadow-cljs 環境執行的細節

聊天記錄長的我都記不住了, 寫博客...html

原由是看到了網上有人寫 Clojure 而後用快捷鍵直接執行代碼,
感受仍是蠻舒服的, 特別是用來教學的時候, 或者試驗一些功能的時候,
由於直接在 REPL 裏寫確定是很累的, 可是寫在編輯器是文件, 很差單獨執行,
而執行某一段選中的代碼, 應該是不錯的辦法.
Lisp 跟 Smalltalk 都搞過...前端

首先, Clojure 是提供了一個功能的, nREPL, 能夠經過網絡發送代碼到一個 REPL,
而後在這個 REPL 裏執行代碼, 獲得執行的輸出結果, 或者執行的報錯.
如今已經知道的有兩種實現, nREPL 和 Socket REPL, 有一些區別,
https://stackoverflow.com/que...
nREPL 是社區裏作了比較久的一個工具, 而 Socket REPL 是官方臨時加的一個小功能,
此外還有 unrepl 是一個新的東西, 還不熟悉. 以及一個不知道啥狀況的 prepl.node

因爲個人代碼是要在 shadow-cljs 鏈接的瀏覽器運行的, 因此整個都要圍繞 shadow-cljs 搞.git

nREPL

shadow-cljs 是支持的 nREPL 的:
https://shadow-cljs.github.io...github

:nrepl {:port 9000 :middleware []}

按照文檔配置好以後, nREPL 的 server 就啓動了.
具體的內容是用 bencode 編碼的, 感受挺邪乎, 仍是 BitTorrent 用的協議,
昨天在羣裏問的時候, 推薦我用 node 類庫來搞這個事情:
https://github.com/rksm/node-...npm

搗騰了一下, 好比端口是 9000 的話, 能夠這樣發送代碼過去:api

n = require 'nrepl-client'
c = n.connect port: 9000

show = (err, result) -> console.error 'Error:', err; console.log 'Result', result

c.eval '(println "code")', show
c.eval '(+ 33 44)', show

而後代碼就會在後臺執行... 從 shadow-cljs 看不到 log, 可是從 API 能拿到返回的 output.瀏覽器

返回的 output 是挺讓人崩潰的, 是一個 Vector, 包含幾個 Map.
中間會帶着一些 id, 以及返回的內容, 結構有點亂. 我手頭沒有留記錄.網絡

Socket REPL

Socket REPL 只是純文本格式的發送 code, 返回執行結果,
shadow-cljs 的運行端口在 target/shadow-cljs/socket-repl.port 文件能夠拿到,
或者經過配置文件去設置:socket

:socket-repl {:port 123}

同時有個私有的去掉 prompt 版本的 Socket REPL, 端口在 target/shadow-cljs/cli-repl.port.
說是內部使用的, 端口隨機, 不建議使用, 那樣我也儘可能不去用吧...

鏈接 Socket REPL 用 TCP 協議直接就好, 參考 Node API 文檔:
https://nodejs.org/api/net.ht...

net = require 'net'
c = net.createConnection port: 51053

c.on 'data', (data) -> console.log data.toString()

c.write '(println 1)\r\n'

返回的 output 就是通常的 REPL 運行的 log, 真的很通常, prompt 對開發工具很不友好.

unrepl

下午剛搜到過, Slack 上也只是剛認到人, 還不知道什麼狀況,
大體的印象是一個新的加 REPL 的方案, 基於 Lumo 作的, 啓動很快,
可是還要再問一下具體能作什麼...
https://github.com/Unrepl/unrepl
https://www.youtube.com/watch...

prepl

這個奇怪的東西仍是 thheller 在 Slack 上說到的, 前幾天的 commit 裏出現的:
https://github.com/clojure/cl...
按照 Reddit 上的提示, 大體是發送代碼, 返回結構化的結果的一個方案,

PREPL allows for (remoteable) streaming in, structured out.
This is useful for many kinds of REPL tooling allowing it to respond differently to eval output vs printing output.

https://www.reddit.com/r/Cloj...
跟 unrepl 類似, 結構化的數據更便於將來開發的工具鏈.
目前還不知道更多的細節, 等到 Clojure 1.10 估計會有一些解釋.

經過 shadow-cljs 轉發代碼到前端

前面的代碼運行的環境是 shadow-cljs 編譯器本身的進程, 不是個人代碼運行的環境,
而 shadow-cljs 當中, 使用 shadow-cljs cljs-repl 是能夠發送代碼到瀏覽器,
thheller 說若是要進一步切換到瀏覽器用的執行環境, 還須要再調用 API:

c.write '(shadow.cljs.devtools.api/repl :build-id)\n'

早幾天的時候有個私有 API 能夠用, 彷佛不建議使用:

c.write '(shadow.cljs.devtools.cli/from-remote "some-uuid" "another-uuid" ["cljs-repl" "browser"])'

from-remote 在源碼當中大概是這樣, 反正我只能看個大概了...
https://github.com/thheller/s...

調用 API 以後再發送代碼, 在瀏覽器就有反應了, 能夠看到 log:

c.write '(println 4444)\n'

總之基於這個原理, 我應該是能在 Calcit Editor 當中實現我想要的功能了.

小結

後面還要在刷一下文檔而後在 Calcit Editor 里加上對應的功能.晚點再說了... 估計接下來會有一些新聞, 到時候再更新了.

相關文章
相關標籤/搜索