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 更加友好.