shadow-cljs 2.x 使用教程

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.jsmain.js 兩個文件,
shadow-cljs 支持將生成代碼拆分爲多個文件, 這裏就拆分紅了 main.jslib.js,
而且, 其中指定了 mainlib 的依賴, 以及 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 很差作異步加載, 這個是有些不足, 能夠向官方反饋.

npm 模塊

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

相關文章
相關標籤/搜索