mkdir -p hello-modules
cd hello-modules
mkdir src
本指南需要 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.js
比 bar.js
大。
由于分割中的代码在 JavaScript 的全局范围内运行,因此有时它可能会干扰在同一页面上加载的其他 JavaScript(例如分析),这可能会导致不可预测的行为。如果这对您的应用程序来说是一个问题,请通过指定 :rename-prefix
编译器选项来为生成的 JavaScript 中的所有变量添加前缀。
原作者:David Nolen