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 模块管理器单例来管理代码分割的加载。此管理器将使用您在 :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 更改为接受新的 require,例如 cljs.reader。重新构建。

您应该看到 cljs.reader 被移动到 :foo 模块中,但没有移动到 :bar 中。

如果您检查 out 中的分割文件,您将看到 foo.jsbar.js 大。

其他说明

由于分割中的代码在 JavaScript 的全局范围内运行,因此有时它可能会干扰在同一页面上加载的其他 JavaScript(例如分析),这可能会导致不可预测的行为。如果这对您的应用程序来说是一个问题,请通过指定 :rename-prefix 编译器选项来为生成的 JavaScript 中的所有变量添加前缀。

原作者:David Nolen