shadow-cljs 是一个新开发的 ClojureScript 开发和编译工具.
之前编译主要是 lein-cljsbuild, boot-cljs, lein-figwheel,
如今新的工具 Lumo 和 shadow-cljs 也能够完成编译工做了.
特别是 shadow-cljs 的功能覆盖开发当中不少场景, 对 JavaScript 开发者更友好.
对于前端开发者来讲, shadow-cljs 上手也很是简单, 不须要去管 JVM 的事情.
安装 shadow-cljs 很是简单, 经过 npm 的命令来就行了:前端
npm install -g shadow-cljs
好比你有一个 ClojureScript 项目, 命名空间叫 app
, 对应目录结构:node
$ tree src/ src/ └── app ├── lib.cljs └── main.cljs
就像 Webpack 同样, 编译以前须要有一些配置, 源码在哪里, 编译到哪里, 之类的,
因为 ClojureScript 有着本身的依赖管理工具, 因此依赖也要写在这个文件里:webpack
{:source-paths ["src/"] :dependencies [] :builds {:app {:output-dir "target/" :asset-path "." :target :browser :modules {:main {:entries [app.main]}} :devtools {:after-load app.main/reload!}}}}
几个关键的参数大概的意思:git
:target
表示编译目标, 这里选择 :browser
, 生成代码用于在浏览器当中运行.:devtools
表示开发环境的设置, 这里我设置了热替换完成以后执行函数 app.main/reload!
:asset-path
资源存储的路径, 相对于 target/
, 也影响到网页上引用代码. 默认彷佛是 ./
.更多的参数能够到文档站点上查阅: http://doc.shadow-cljs.org/github
配置完成以后能够用 shadow-cljs
命令来编译代码, 经常使用的子命令有:web
shadow-cljs compile app # 每一个文件直接编译到对应一个 js 文件 shadow-cljs release app # 编译, 进行代码合并和优化, 以及清除 dead code
其中的 app
就是配置里的 :app
, 也叫 build id. 也就是说会有多个 build id 能够配置.shell
开发过程当中, 最经常使用的是 watch
命令, 它就像 webpack-dev-server,
ClojureScript 相比 js 来讲每一个函数反作用更少, 因此更适合进行热替换,
基于上边的配置, 在每次文件更新, 浏览器就会进行代码热替换, 而后会触发 app.main/reload!
函数:npm
shadow-cljs watch app # 启动编译器, 监视文件更新自动编译
ClojureScript 有一些基础的静态检查功能, 至关于增强的 lint 工具,
因此编译当中会检查代码代码并打印警告, 以及的浏览器当中弹出警告内容.json
此外命令行工具还提供了其余一些开发当中用到的功能:浏览器
shadow-cljs cljs-repl app # 有 watch 服务的状况下, 再启动一个链接到浏览器的 REPL shadow-cljs check app # 进行 release 以前能够作一些检查 shadow-cljs release app --debug # 生成 release 的代码, 同时生成 SourceMaps 等用于调试
更多的子命令能够查阅 http://doc.shadow-cljs.org/
shadow-cljs 支持多个编译目标, 也就是对应 :target
的配置, 通常有:
:browser
运行在浏览器的代码:node-script
运行在 Node.js 的代码:node-library
能够被 Node.js JavaScript 代码调用的模块:npm-module
遵循 CommonJS 语法的独立的 js 文件我使用最可能是 :browser
, 功能完善, 已经可以胜任目前网页应用的开发需求了,
并且 :browser
模式的打包也逐渐成熟了, 补上了一些 Webpack 中的经常使用功能.
在某些只能经过 Webpack 打包状况下, 可使用 :npm-module
做为一种兼容模式, :npm-module
模式编译的代码符合 CommonJS 规范, 能够被 Webpack 用于打包(注意这样打包带上 ClojureScript 的 runtime 代码是挺大的).
:node-script
用于开发 Node.js 脚本, 这里热替换也是基本一致的配置.
至于 :node-library
我还没用过, 参考文档应该是暴露结构给 Node.js 脚本调用.
关于这些模式具体的用途, 我搜集了一些例子, 能够参考:
除了上面的例子, shadow-cljs 的配置项还有很多, 我拿本身的脚手架配置做为例子:
{:source-paths ["src"] :dependencies [[mvc-works/hsl "0.1.2"] [mvc-works/shell-page "0.1.3"] [mvc-works/verbosely "0.1.0-rc"] [respo/ui "0.1.9"] [respo/reel "0.2.0-alpha3"] [respo "0.6.4"]] :http {:host "localhost" :port 8081} :open-file-command ["subl" ["%s:%s:%s" :file :line :column]] :builds {:browser {:target :browser :output-dir "target/browser" :asset-path "/browser" :modules {:main {:entries [app.main] :depends-on #{:lib}} :lib {:entries [respo.core respo.macros respo.comp.inspect]}} :devtools {:after-load app.main/reload! :http-root "target" :http-port 7000} :release {:output-dir "dist/" :module-hash-names true :build-options {:manifest-name "cljs-manifest.json"}}} :ssr {:target :node-script :output-to "target/ssr.js" :main app.render/main! :devtools {:after-load app.render/main!}}}}
其中出现了些前面没有有道的配置, 我拎出来解释一下:
shadow-cljs 内置了一个 HTTP 服务器用于网页的调试,
须要在 :devtools
的配置当中添加 HTTP 相关的配置:
:devtools {:http-root "target" :http-port 7000}
watch
模式当中遇到代码存在顺发错误, 浏览器上会有界面显示 warning,
shadow-cljs 支持点击代码打开编辑器对应的行, 经过配置打开文件的命令,
传输我用 Sublime Text 打开, 这个命令当中精确到行列:
:open-file-command ["subl" ["%s:%s:%s" :file :line :column]]
前端单页面应用倾向于生成代码到 vendor.js
和 main.js
两个文件,
shadow-cljs 支持将生成代码拆分为多个文件, 这里就拆分红了 main.js
和 lib.js
,
而且, 其中指定了 main
对 lib
的依赖, 以及 lib
包含哪些命名空间:
:modules {:main {:entries [app.main] :depends-on #{:lib}} :lib {:entries [respo.core respo.macros respo.comp.inspect]}}
开发环境的配置, 除了经常使用的 :after-load
, 还有 :before-load
等:
:devtools {:after-load app.main/reload!}
注意 :release
的配置是写在 :browser
配置内部的, 表示覆盖重复的配置,
这是 shadow-cljs 提供的一个简写, 你也能够本身专门写一遍 :release
的配置.
好比说 :output-dir "dist/"
就覆盖了外面的配置 :output-dir "target/"
.:module-hash-names
声明对生成的文件名加上 MD5 方便放 CDN.
最后一行的配置是重命名 manifest.json
文件, 其中包含前面生成的带 MD5 的文件名,:
:release {:output-dir "dist/" :module-hash-names true :build-options {:manifest-name "cljs-manifest.json"}}}
:release
的配置可也支持别的配置, 好比这里的 8
表示 Hash 的长度,
manifest 文件除了 JSON, 也能够经过文件后缀支持生成 EDN 文件:
:release {:output-dir "dist/" :module-hash-names 8 :build-options {:manifest-name "assets.edn"}}}
能够看不少随着 Webpack 而在前端普遍使用的功能, 在 shadow-cljs 当中作了很多的支持.
代码拆包之后, shadow-cljs 很差作异步加载, 这个是有些不足, 能够向官方反馈.
shadow-cljs 2.x 版本带来了在 :browser
编译目标的 npm 模块的支持, 注意写法:
(ns app.main (:require ["hsl" :as hsl])) (hsl 200 80 80)
:node-script
编译目标或者 :npm-module
当中也支持这样写:
(def hsl (js/require "hsl")) (hsl 200 80 80)
由于 require
在 Node 当中直接是函数, 在前端也能够被 Webpack 进一步处理.
大部分 npm 模块均可以直接用到的 ClojureScript 项目当中.
除此以外, Lumo 和官方的 ClojureScript 编译器也改善了对 npm 模块支持.
shadow-cljs 的文章已经作得比较完善, 能够访问 http://doc.shadow-cljs.org 查阅.
若是遇到问题或者想要反馈, 能够经过下面两个地址提交:
https://github.com/thheller/s...
https://clojureverse.org/c/pr...
英语够好的话甚至直接到聊天室上找到做者, 做者在欧洲, 注意时差:
https://clojurians.slack.com/...2017 年秋天至今 shadow-cljs 做者都在很积极更新功能,不少的 bug 都以很是快的速度修复了, 让 shadow-cljs 更加友好.