Skip to content

Commit f65d018

Browse files
committed
cleanup loader docs, add shadow.lazy
1 parent 3754cda commit f65d018

File tree

2 files changed

+119
-20
lines changed

2 files changed

+119
-20
lines changed

docs/UsersGuide.html

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3717,7 +3717,7 @@ <h3 id="CodeSplitting"><a class="anchor" href="#CodeSplitting"></a><a class="lin
37173717
</ul>
37183718
</div>
37193719
<div class="paragraph">
3720-
<p>One good configuration for this would be to have one common module that is shared between all the pages. Then one for each page.</p>
3720+
<p>One possible configuration for this would be to have one common module that is shared between all the pages. Then one for each page.</p>
37213721
</div>
37223722
<div class="listingblock">
37233723
<div class="title">Example config with multiple <code>:modules</code></div>
@@ -3787,18 +3787,80 @@ <h3 id="CodeSplitting"><a class="anchor" href="#CodeSplitting"></a><a class="lin
37873787
<div class="sect3">
37883788
<h4 id="_loading_code_dynamically"><a class="anchor" href="#_loading_code_dynamically"></a><a class="link" href="#_loading_code_dynamically">7.3.1. Loading code dynamically</a></h4>
37893789
<div class="paragraph">
3790-
<p>These days Single-Page-Apps (SPA) are becoming more popular and they work similarly only that instead of letting the Server decide which JS to include to Client does it by itself.</p>
3790+
<p>The more dynamic your website gets, the more dynamic your requirements may get. The server may not always know what the client may end up needing. Therefore, it is possible to have the client load code dynamically when needed.</p>
3791+
</div>
3792+
<div class="paragraph">
3793+
<p>There are a couple ways of loading code dynamically. <code>shadow.lazy</code> is the most convenient and easiest.</p>
3794+
</div>
3795+
<div class="sect4">
3796+
<h5 id="_using_shadow_lazy"><a class="anchor" href="#_using_shadow_lazy"></a><a class="link" href="#_using_shadow_lazy">Using shadow.lazy</a></h5>
3797+
<div class="paragraph">
3798+
<p>As <a href="https://clojureverse.org/t/shadow-lazy-convenience-wrapper-for-shadow-loader-cljs-loader/3841">announced here</a> shadow-cljs provides a convenience method for referring to potentially lazy loaded code.</p>
3799+
</div>
3800+
<div class="listingblock">
3801+
<div class="content">
3802+
<pre class="CodeRay highlight"><code data-lang="clojure">(<span class="keyword">ns</span> <span class="namespace">demo.app</span>
3803+
(<span class="symbol">:require</span>
3804+
[shadow.lazy <span class="symbol">:as</span> lazy]
3805+
[shadow.cljs.modern <span class="symbol">:refer</span> (js-await)]))
3806+
3807+
(<span class="keyword">def</span> <span class="function">x-lazy</span> (lazy/loadable demo.thing/x))
3808+
3809+
(<span class="keyword">defn</span> <span class="function">on-event</span> [e]
3810+
(js-await [x (lazy/load x-lazy)]
3811+
(x e)))</code></pre>
3812+
</div>
3813+
</div>
3814+
<div class="paragraph">
3815+
<p>Let&#8217;s assume that the <code>on-event</code> function above is called when something in your app happens, for example when the user clicked a button. The <code>lazy/loadable</code> configured what that thing will be. The <code>lazy/load</code> will actually load it. This may require an async network hop, so it will go async at this point. In the body of the <code>js-await</code> above <code>x</code> will be whatever <code>demo.thing/x</code> was at the time of loading it.</p>
3816+
</div>
3817+
<div class="listingblock">
3818+
<div class="content">
3819+
<pre class="CodeRay highlight"><code data-lang="clojure">(<span class="keyword">ns</span> <span class="namespace">demo.thing</span>)
3820+
(<span class="keyword">defn</span> <span class="function">x</span> [e]
3821+
<span class="string"><span class="delimiter">&quot;</span><span class="content">hello world</span><span class="delimiter">&quot;</span></span>)</code></pre>
3822+
</div>
3823+
</div>
3824+
<div class="paragraph">
3825+
<p>In this case it would be the function, which we can call directly.</p>
3826+
</div>
3827+
<div class="paragraph">
3828+
<p>You do not need to worry about specifying which module this code ended up in. The compiler will figure that out during compilation. The <code>loadable</code> macro also allows more complex references.</p>
3829+
</div>
3830+
<div class="listingblock">
3831+
<div class="content">
3832+
<pre class="CodeRay highlight"><code data-lang="clojure">(<span class="keyword">def</span> <span class="function">xy</span> (lazy/loadable [demo.thing/x demo.other/y]))
3833+
3834+
(<span class="keyword">def</span> <span class="function">xym</span> (lazy/loadable {<span class="symbol">:x</span> demo.thing/x
3835+
<span class="symbol">:y</span> demo.other/y}))</code></pre>
3836+
</div>
3837+
</div>
3838+
<div class="paragraph">
3839+
<p>If you load <code>xy</code> the result will be a vector with two things. If you load <code>xym</code> it&#8217;ll be a map. You may include vars that span multiple modules that way. The loader will ensure all modules are loaded before continuing.</p>
3840+
</div>
37913841
</div>
37923842
<div class="sect4">
37933843
<h5 id="_using_shadow_cljs_s_built_in_loader_support"><a class="anchor" href="#_using_shadow_cljs_s_built_in_loader_support"></a><a class="link" href="#_using_shadow_cljs_s_built_in_loader_support">Using shadow-cljs&#8217;s built-in Loader Support</a></h5>
3844+
<div class="admonitionblock important">
3845+
<table>
3846+
<tr>
3847+
<td class="icon">
3848+
<div class="title">Important</div>
3849+
</td>
3850+
<td class="content">
3851+
This is the low level version, which the above is built upoin. Use it if you want to build your own abstraction for async loading. The above is much more convenient to use.
3852+
</td>
3853+
</tr>
3854+
</table>
3855+
</div>
37943856
<div class="paragraph">
37953857
<p>The compiler supports generating the required data for using the <code>shadow.loader</code> utility namespace. It exposes a simple interface to let you load modules on-demand at runtime.</p>
37963858
</div>
37973859
<div class="paragraph">
37983860
<p>You only need to add <code>:module-loader true</code> to your build config. The loader will always be injected into the default module (the one everything else depends on).</p>
37993861
</div>
38003862
<div class="paragraph">
3801-
<p>At runtime you may use the <code>shadow.loader</code> namespace to load modules. You may also load a module eagerly by just using a <code>&lt;script&gt;</code> tag in your page.</p>
3863+
<p>At runtime you may use the <code>shadow.loader</code> namespace to load modules. You may also still load a module eagerly by just using a <code>&lt;script&gt;</code> tag in your page.</p>
38023864
</div>
38033865
<div class="listingblock">
38043866
<div class="content">
@@ -3855,6 +3917,9 @@ <h5 id="_using_shadow_cljs_s_built_in_loader_support"><a class="anchor" href="#_
38553917
<div class="paragraph">
38563918
<p>You can check if a module is loaded using <code>(loaded? "module-name")</code>.</p>
38573919
</div>
3920+
<div class="paragraph">
3921+
<p>You can read more about a more practical example in this blog post about <a href="https://code.thheller.com/blog/shadow-cljs/2019/03/03/code-splitting-clojurescript.html"> Code-Splitting ClojureScript</a>. This is only a basic overview.</p>
3922+
</div>
38583923
<div class="sect5">
38593924
<h6 id="_loader_costs"><a class="anchor" href="#_loader_costs"></a><a class="link" href="#_loader_costs">Loader Costs</a></h6>
38603925
<div class="paragraph">
@@ -3865,15 +3930,10 @@ <h6 id="_loader_costs"><a class="anchor" href="#_loader_costs"></a><a class="lin
38653930
<div class="sect4">
38663931
<h5 id="_using_the_standard_clojurescript_api"><a class="anchor" href="#_using_the_standard_clojurescript_api"></a><a class="link" href="#_using_the_standard_clojurescript_api">Using the Standard ClojureScript API</a></h5>
38673932
<div class="paragraph">
3868-
<p>The generated code is capable of using the standard ClojureScript <code>cljs.loader</code> API. See the
3869-
<a href="https://clojurescript.org/news/2017-07-10-code-splitting">documentation</a> on the ClojureScript
3870-
website for instructions.</p>
3933+
<p>The generated code is capable of using the standard ClojureScript <code>cljs.loader</code> API. See the <a href="https://clojurescript.org/news/2017-07-10-code-splitting">documentation</a> on the ClojureScript website for instructions.</p>
38713934
</div>
38723935
<div class="paragraph">
3873-
<p>The advantage of using the standard API is that your code will play well with others. This
3874-
may be of particular importance to library authors. The disadvantage is that the dynamic module
3875-
loading API in the standard distribution is currently somewhat less easy-to-use than the
3876-
support in <code>shadow-cljs</code>.</p>
3936+
<p>The advantage of using the standard API is that your code will play well with others. This may be of particular importance to library authors. The disadvantage is that the dynamic module loading API in the standard distribution is currently somewhat less easy-to-use than the support in <code>shadow-cljs</code>.</p>
38773937
</div>
38783938
</div>
38793939
</div>

docs/target-browser.adoc

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Say you have a traditional website with actual different pages.
102102
- `www.acme.com/login` - serving the login form
103103
- `www.acme.com/protected` - protected section that is only available once the user is logged in
104104

105-
One good configuration for this would be to have one common module that is shared between all the pages. Then one for each page.
105+
One possible configuration for this would be to have one common module that is shared between all the pages. Then one for each page.
106106

107107
.Example config with multiple `:modules`
108108
```clojure
@@ -147,15 +147,57 @@ IMPORTANT: The `.js` files must be included in the correct order. The <<BrowserM
147147

148148
=== Loading code dynamically
149149

150-
These days Single-Page-Apps (SPA) are becoming more popular and they work similarly only that instead of letting the Server decide which JS to include to Client does it by itself.
150+
The more dynamic your website gets, the more dynamic your requirements may get. The server may not always know what the client may end up needing. Therefore, it is possible to have the client load code dynamically when needed.
151+
152+
There are a couple ways of loading code dynamically. `shadow.lazy` is the most convenient and easiest.
153+
154+
==== Using shadow.lazy
155+
156+
As https://clojureverse.org/t/shadow-lazy-convenience-wrapper-for-shadow-loader-cljs-loader/3841[announced here] shadow-cljs provides a convenience method for referring to potentially lazy loaded code.
157+
158+
```clojure
159+
(ns demo.app
160+
(:require
161+
[shadow.lazy :as lazy]
162+
[shadow.cljs.modern :refer (js-await)]))
163+
164+
(def x-lazy (lazy/loadable demo.thing/x))
165+
166+
(defn on-event [e]
167+
(js-await [x (lazy/load x-lazy)]
168+
(x e)))
169+
```
170+
171+
Let's assume that the `on-event` function above is called when something in your app happens, for example when the user clicked a button. The `lazy/loadable` configured what that thing will be. The `lazy/load` will actually load it. This may require an async network hop, so it will go async at this point. In the body of the `js-await` above `x` will be whatever `demo.thing/x` was at the time of loading it.
172+
173+
```clojure
174+
(ns demo.thing)
175+
(defn x [e]
176+
"hello world")
177+
```
178+
179+
In this case it would be the function, which we can call directly.
180+
181+
You do not need to worry about specifying which module this code ended up in. The compiler will figure that out during compilation. The `loadable` macro also allows more complex references.
182+
183+
```clojure
184+
(def xy (lazy/loadable [demo.thing/x demo.other/y]))
185+
186+
(def xym (lazy/loadable {:x demo.thing/x
187+
:y demo.other/y}))
188+
```
189+
190+
If you load `xy` the result will be a vector with two things. If you load `xym` it'll be a map. You may include vars that span multiple modules that way. The loader will ensure all modules are loaded before continuing.
151191

152192
==== Using shadow-cljs's built-in Loader Support
153193

194+
IMPORTANT: This is the low level version, which the above is built upoin. Use it if you want to build your own abstraction for async loading. The above is much more convenient to use.
195+
154196
The compiler supports generating the required data for using the `shadow.loader` utility namespace. It exposes a simple interface to let you load modules on-demand at runtime.
155197

156198
You only need to add `:module-loader true` to your build config. The loader will always be injected into the default module (the one everything else depends on).
157199

158-
At runtime you may use the `shadow.loader` namespace to load modules. You may also load a module eagerly by just using a `<script>` tag in your page.
200+
At runtime you may use the `shadow.loader` namespace to load modules. You may also still load a module eagerly by just using a `<script>` tag in your page.
159201

160202
```
161203
{...
@@ -204,20 +246,17 @@ Then the following expressions can be used for loading code:
204246

205247
You can check if a module is loaded using `(loaded? "module-name")`.
206248

249+
You can read more about a more practical example in this blog post about https://code.thheller.com/blog/shadow-cljs/2019/03/03/code-splitting-clojurescript.html[ Code-Splitting ClojureScript]. This is only a basic overview.
250+
207251
===== Loader Costs
208252

209253
Using the loader is very lightweight. It has a few dependencies which you may not be otherwise using. In practice using `:module-loader true` adds about 8KB gzip'd to the default module. This will vary depending on how much of `goog.net` and `goog.events` you are already using, and what level of optimization you use for your release builds.
210254

211255
==== Using the Standard ClojureScript API
212256

213-
The generated code is capable of using the standard ClojureScript `cljs.loader` API. See the
214-
https://clojurescript.org/news/2017-07-10-code-splitting[documentation] on the ClojureScript
215-
website for instructions.
257+
The generated code is capable of using the standard ClojureScript `cljs.loader` API. See the https://clojurescript.org/news/2017-07-10-code-splitting[documentation] on the ClojureScript website for instructions.
216258

217-
The advantage of using the standard API is that your code will play well with others. This
218-
may be of particular importance to library authors. The disadvantage is that the dynamic module
219-
loading API in the standard distribution is currently somewhat less easy-to-use than the
220-
support in `shadow-cljs`.
259+
The advantage of using the standard API is that your code will play well with others. This may be of particular importance to library authors. The disadvantage is that the dynamic module loading API in the standard distribution is currently somewhat less easy-to-use than the support in `shadow-cljs`.
221260

222261
== Output Wrapper [[output-wrapper]]
223262

0 commit comments

Comments
 (0)