[笔记] Figwheel 后端替换, 和尝试 Cumulo

这篇笔记只是整理一下几个遇到的坑, 意义不大, 遇到问题搜到看下就好了
单纯 Figwheel 在之前的文章梳理过了, 用在后端其实也是一样

Figwheel 提供了和 Webpack 类似的方案, 可以的后端使用热替换
https://github.com/bhauman/lein-figwheel/wiki/Node.js-development-with-figwheel
大致上就是修改配置指定 :target :nodejs, 直接生成相应的代码
然后对应文件用 node 命令运行, 就会自动连接 WebSocket 处理更新
具体操作安装 Wiki 走一遍, 或者用现在 template 尝试一下就知道了
https://github.com/malyn/figwheel-node-template
也可以用 node-inspector 的 node-debug 命令, 虽然代码比较难看

同时启动多个 Figwheel 服务端

因为是前后端的代码一起做替换, 就需要启动两个, 至少 Webpack 是怎么做的
在 Figwheel 里我尝试一下, 然而一个文件只有一个端口配置
无奈之下 Twitter 上问作者, 很快回复我了
https://twitter.com/jiyinyiyong/status/686553171833913344
原来 Figwheel 是支持的, 但是要在一个命令里启动两份配置,
比如我的两个配置分别是 server-devweb-dev, 就这样写:

rlwrap lein figwheel server-dev web-dev

而两个服务端的 REPL 可以通过 :cljs/quit 触发提示来切换
这样基本的功能是达到了的, 使用过程也没遇到其他问题

diff/patch 方案

Cumulo 在 JavaScript 环境当中有 JSON Patch 整套规范的
http://jsonpatch.com/
https://tools.ietf.org/html/rfc6902
Clojure 对应的数据格式是 EDN, 然而 EDN 是没有明确的格式
我找到两个包, 选择了 star 数量较多的 differ 包
https://github.com/wagjo/diff-cljs/

其中也遇到问题, 比如 diff 结果格式比较奇怪, 作者热心给解答了
https://github.com/Skinney/differ/issues/15
Diff 结果和 JSON 这边不同, 使用的格式是修改和删除分开标记
比如 [{} {:a 0}] 实际上对应的是 [altertions removals]
就是说这次对比, 没有修改, 但是有 :a 被删除了, 所有有个标记
总之就是没有明确的 spec, 只有可行的方案.. 性能对我来说目前是足够了

异步事件

实际上用 Clojure 没有看到有用时间机制的, 没有 Node 那么赤裸裸的回调函数
那么, 当我要对 WebSocket 对象化的接口进行封装时怎么办呢?
我反应过来, 原来要用 core.async, 通过 channel 作为事件的传输方案
http://stackoverflow.com/questions/21400464/cant-seem-to-require-or-in-clojurescript

首先遇到的问题是 ClojureScript 当中需要引用 cljs.core.async namespace
由于 JavaScript 环境的特殊性, 两者代码是分开的, 不能直接引用
其次 >!! 这种 blocking 的操作在 ClojureScript 当中不存在
只能通过添加 go block 在代码内部调用了
另外, 还需要用 go 搭配 looprecur 保持持续的 channel 处理
思路有点怪, 但大致可以理解为现在 channel 都是单向的, 语法简单粗暴一些

Reagent Atom

Reagent 的 Atom 我还没熟练, 按照组件传递元素时细节有点奇怪
首先是 Atom 类型的数据需要用 @a 也就是 (deref a) 来调用
swap!reset! 不会对 HashMap 数据进行报错, 所以要自己注意,
具体意思看文章 http://www.lispcast.com/atom-problem

另外有时候更新不能很好地传递, 我怀疑是闭包里的 Atom 引用有其特性
大体上应该是这样一个问题, 就是 Reagent 的组件是用函数模拟的, 比如这样:

(def a-comp []
  (let [a (atom {})]
    (fn [props]
      [:div nil a])))

(def b-comp []
  [a-comp {:value "demo"}])

其中 a-comp 的返回值是一个函数, 而且在 b-comp 调用到
我最初把参数或者说 props 写在开头的 a-comp 中, 发现数据不更新
其实移动到 fn 的参数里就好了, 这样就要推测 Reagent 的机制了
其中的 let 在 Reagent 中以闭包形式模拟 React state 机制的
也就是说 a-comp 只会被调用一次, 因此会更新的参数必须写在 fn
到官网的复杂例子看, 大致能印证. 不过官网是没明确提示的样子

你可能感兴趣的:(clojurescript,figwheel)