ClojureScript

擁抱 JavaScript 工具

2020 年 4 月 24 日
ClojureScript 團隊

ClojureScript 1.10.741 包含一種新的簡化方式,可與現有的 JavaScript 生態系統整合 - bundle 目標。透過這個目標,ClojureScript 編譯器的輸出可以立即交給像 WebpackMetro 這樣的 JavaScript 打包工具,或是任何其他理解 Node.js require 的建置工具。使用這個新目標的 ClojureScript 專案可以自由地從 node_modules 整合函式庫,而無需手寫外部宣告或額外設定,同時仍然可以充分利用 REPL 驅動的開發和進階編譯來優化應用程式的可優化部分。

雖然對 ClojureScript 專案的開發便利性的影響顯而易見,但我們認為 ClojureScript 生態系統的好處更加令人興奮。您現在可以發佈直接依賴 JavaScript 生態系統的 ClojureScript 函式庫,而無需額外的儀式,並確信整個社群都可以從中受益,無論他們可能偏好什麼其他的 JavaScript 和 ClojureScript 建置工具。

如果您想直接切入重點並瀏覽教學,請前往新的指南。若要了解一些歷史和背景,請繼續閱讀。

多年來,我們實作並發佈了各種功能以幫助與 JavaScript 生態系統整合,但事實是,最終結果感覺更像是各種解決方案的拼湊,而不是一氣呵成的東西。其中一些可以歸因於試圖繞過現有的 JavaScript 工具,而不是擁抱它。ClojureScript 大量投資於已有十年歷史的 Google Closure Compiler 專案的進階編譯功能,因此似乎很自然地透過它來處理 Node 模組。

但是自從我們首次透過 Closure 運送 Node 模組處理以來,已經過了將近三年,很明顯,只有極少數最流行的函式庫可以進行進階最佳化。儘管我們仍然認為這裡有前景,但 ClojureScript 社群必須透過開發引人注目的 JavaScript 函式庫來向世界其他地方展示方法,這些函式庫可以被流行的 JavaScript 工具輕鬆使用,但在使用 ClojureScript 建置時仍然可以進行 Closure 的驚人樹狀結構刪減和程式碼分割。像 Rollup.js 這樣的專案的成功表明,如果能帶來顯著的好處,JavaScript 開發人員並不反對堅持更嚴格的風格。同時,我們需要一種更簡單且更容易的方法來完成工作。

António Nuno Monteiro 的原始文章中關於 Node 模組處理的章節中,有一個相當簡短的段落,說明了在 Node.js 下,我們實際上會為我們知道來自 node_modules 的函式庫產生 Node.js require 語句。這是一個很棒的想法,在與 Node.js 互動時產生非常慣用的體驗。在接下來的幾年中,很明顯,使用 ClojureScript 進行 Node.js 開發通常比 Web 開發更簡單。現在不再如此,bundle 目標方法接受這樣的事實:幾乎所有現代 JavaScript 依賴關係解析都是 Node.js require 或 ES6 import。

不過,這只解決了部分問題。我們需要將進階最佳化應用於 ClojureScript 產生的 JavaScript。這導致我們所謂的「外部宣告推斷」。Closure 編譯模型的其中一個缺點是,整合非為 Closure 消費而設計的函式庫需要手動且容易出錯地編寫外部宣告 - 這些檔案可防止 Closure 重新命名它實際看不到的函式庫中的屬性和宣告。由於 Rich Hickey 早期的決定將 ClojureScript 中的全域變數標記為如此,並且 Clojure 提供了一種簡單但有效的類型傳播演算法,可在 ClojureScript 也實作的局部範圍內使用,因此追蹤「外部」值的用法並不像看起來那麼棘手。

結合我們在 Node.js 和外部宣告推斷方面的方法,直接導向 bundle 目標。當然,現在這一切可能看起來都很明顯 - 但處理各種設計目標很容易模糊簡單的答案。透過取得兩個不同的事物 - 一方面是 ClojureScript,另一方面是 JavaScript 工具 - 並實際允許它們保持不同 - 我們可以得到比各部分總和更多的東西。同時,如果更多的 JavaScript 函式庫開始採用有利於積極刪除無用程式碼的程式碼風格,那麼這些選擇都不會排除將所有內容傳遞給 Closure Compiler 的可能性。

這個功能是 ClojureScript 社群中許多討論和一些很棒的專案啟發的結果 - 特別是 re-natalshadow-cljs

祝您編碼愉快!