ClojureScript

程式碼分割

本指南需要 ClojureScript 1.10.238 或更新版本,並假設您已熟悉快速開始.

隨著客戶端應用程式變得越來越大,只載入實際執行特定邏輯螢幕所需的程式碼會變得更加理想。先前 ClojureScript 的 :modules 編譯器選項允許這種程式碼分割,但此功能僅在 :advanced 編譯下才能運作,而且使用者仍然必須管理這些分割的載入。:modules 也需要手動明確放置許多條目才能產生最佳分割,否則相依性會被移到 :cljs-base

所有這些問題現在都已在 ClojureScript 中直接解決。本指南將引導您完成一個簡單專案的程式碼分割,並示範這些新的增強功能。

建立一個簡單專案

建立一個專案資料夾

mkdir -p hello-modules
cd hello-modules
mkdir src

建立一個類似以下的 deps.edn 檔案

{:deps {org.clojure/clojurescript {:mvn/version "1.11.54"}}}

建立一個類似以下的 build.edn 檔案

{:output-dir "out"
 :asset-path "/out"
 :browser-repl false
 :modules {:foo {:entries #{foo.core}
                 :output-to "out/foo.js"}
           :bar {:entries #{bar.core}
                 :output-to "out/bar.js"}}}

現在建立一個 index.html 檔案

<html>
    <body>
         <button id="button">Load Bar!</button>
         <script src="out/cljs_base.js" type="text/javascript"></script>
         <script src="out/foo.js" type="text/javascript"></script>
    </body>
</html>

來源程式碼

建立 foo.core 命名空間

mkdir -p src/foo
touch src/foo/core.cljs

編輯此檔案使其看起來像以下內容

(ns foo.core
  (:require [goog.dom :as gdom]
            [goog.events :as events]
            [cljs.loader :as loader])
  (:import [goog.events EventType]))

(println "I'm foo!")

(events/listen (gdom/getElement "button") EventType.CLICK
  (fn [e]
    (loader/load :bar
      (fn []
        ((resolve 'bar.core/woz))))))

(loader/set-loaded! :foo)

請注意不熟悉的命名空間 cljs.loader。這個命名空間提供一個 Google Closure ModuleManager 單例來管理程式碼分割的載入。這個管理器將會使用你在 :modules 中定義的模組圖進行初始化。

當使用者點擊按鈕時,我們會載入 :bar 模組並調用 bar.core 命名空間中存在的函數。請注意我們使用 resolve。這是因為我們無法直接調用我們從未要求的內容。如果我們在沒有 resolve 的情況下嘗試這樣做,ClojureScript 編譯器將會在編譯期間發出未宣告的變數警告。

最後,請注意必須透過 cljs.loader/set-loaded! 手動將模組標記為已載入。如果沒有這樣做,相依性可能會被多次載入,這可能會導致不可預測的行為。

建立 bar.core 命名空間

mkdir -p src/bar
touch src/bar/core.cljs
(ns bar.core
  (:require [cljs.loader :as loader]))

(println "I'm bar!")

(defn woz []
  (println "WOZ!"))

(loader/set-loaded! :bar)

建置專案

建置您的專案並啟動內建的 HTTP 伺服器

clj -M -m cljs.main -v -co build.edn -c -s

點擊按鈕。您將會看到 :bar 模組被載入,並且另一個命名空間中的函數被調用。

發佈版本

建置您的專案

clj -M -m cljs.main -co build.edn -O advanced -c -s

導覽至 https://127.0.0.1:9000/index.html。您的應用程式即使經過進階編譯也應該能正常運作。

變更 foo.core 以採用像 cljs.reader 的新 require。重新建置。

您應該會看到 cljs.reader 被移動到 :foo 模組,但不會移動到 :bar

如果您檢查 out 中的分割檔案,您會看到 foo.jsbar.js 大。

其他注意事項

由於分割中的程式碼是在 JavaScript 的全域範圍中執行的,有時它可能會干擾同一頁面上載入的其他 JavaScript(例如,分析),這可能會導致不可預測的行為。如果這對您的應用程式來說是一個問題,請透過指定 :rename-prefix 編譯器選項來為產生的 JavaScript 中的所有變數加上前綴。

原始作者:David Nolen