ClojureScript

外部函式庫的全域匯出

2017 年 7 月 30 日
David Nolen

npm 生態系統的整合,有望大幅減少對 Closure 不感知的 JavaScript 依賴項的摩擦。然而,這項工作仍在進行中,絕不排除改進現有的「外部」依賴項問題的解決方案。

ClojureScript 的 :foreign-libs 選項長期以來提供了一種包含 JavaScript 函式庫的方法,這些函式庫不能期望通過 Closure 的進階編譯。透過像 CLJSJS 這樣的社群努力,ClojureScript 開發人員可以相對輕鬆地獲得 ClojureScript 或 Closure 函式庫不易提供的功能。

然而,:foreign-libs 的設計一直存在一個明顯的缺陷 - 這些函式庫被假定為全域載入。外部函式庫匯出的任何 API 都必須透過全域環境存取。

(ns foo
  (:require [cljsjs.react]))

(def react js/React)

因此,外部函式庫不支援任何常用的 :require 功能,例如 :as:refer:rename 等。

雖然這似乎是一個小問題,但多年來,使用者為了取得其他地方沒有的功能,越來越深入 JavaScript 生態系統。對於許多專案來說,這意味著使用像 Webpack 這樣的工具將所有這些依賴項打包成一個單一的外部函式庫。雖然這很方便,但這種方法導致了非慣用的風格,而且如果使用者試圖將這些依賴項遷移到直接從 node_modules 消耗,也會造成障礙。

在下一個版本中,我們將為 :foreign-libs 編譯器選項引入一個簡單的新增功能 - :global-exports。外部函式庫條目現在可以宣告哪個命名空間對應到哪個全域匯出的名稱。

:foreign-libs [{:provides ["cljsjs.react"]
                :global-exports '{cljsjs.react React}}
               {:provides ["cljsjs.react.dom"]
                :global-exports '{cljsjs.react.dom ReactDOM}}]

有了這個簡單的變更,cljsjs.react 現在可以被視為一個常規的命名空間。

(ns foo
  (:require [cljsjs.react :as react :refer [createElement]))

請注意,由於 :global-exports 是一個命名空間對全域匯出的對應,因此利用 Webpack 製作單一外部函式庫的使用者可以輕鬆地對應所有捆綁的函式庫以進行慣用使用。

如果需要,這也提供了到 node_modules 的逐步遷移路徑。例如,使用者可以建立一個宣告在 React 上具有 :npm-depscljsjs.react 成品。由於外部函式庫的使用現在與正常的命名空間使用統一,因此您可以在原始程式碼中不做任何實際變更的情況下,切換到 node_modules 依賴項,只需變更您選擇的依賴項管理工具(Maven、Lein、Boot)中的依賴項即可。

我們認為此功能解決了一個長期存在的痛點,並提供了平穩地遷移到基於 node_modules 的依賴項的路徑。請在 ClojureScript 1.9.854 或更高版本中嘗試。