关于发送代码到 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 里加上对应的功能.晚点再说了... 估计接下来会有一些新闻, 到时候再更新了.

相关文章
相关标签/搜索