Liking cljdoc? Tell your friends :D

hive-hot.core

Hot-reload registry built on clj-reload.

Extends tonsky/clj-reload with:

  • Named component registry
  • Event-driven listeners (for hive-events integration)
  • Status tracking and introspection
  • Cascade control
  • Watcher integration with coordinated debouncing
  • Scoped reload: load the changes under a set of source roots, drag in their dependents, DECLINE every other change — with a per-file baseline so a declined change stays pending for the reload that owns it (clj-reload keeps one scalar :since for the whole image)

Design: Composition over reimplementation.

Hot-reload registry built on clj-reload.

Extends tonsky/clj-reload with:
- Named component registry
- Event-driven listeners (for hive-events integration)
- Status tracking and introspection
- Cascade control
- Watcher integration with coordinated debouncing
- Scoped reload: load the changes under a set of source roots, drag in
  their dependents, DECLINE every other change — with a per-file baseline
  so a declined change stays pending for the reload that owns it
  (clj-reload keeps one scalar :since for the whole image)

Design: Composition over reimplementation.
raw docstring

add-listener!clj

(add-listener! listener-id listener-fn)

Add a reload event listener.

Events:

  • {:type :reload-start}
  • {:type :reload-success :unloaded [...] :loaded [...] :ms elapsed}
  • {:type :reload-error :failed ns :error ex}
  • {:type :component-callback :component id :callback :on-reload|:on-error}
Add a reload event listener.

Events:
- {:type :reload-start}
- {:type :reload-success :unloaded [...] :loaded [...] :ms elapsed}
- {:type :reload-error :failed ns :error ex}
- {:type :component-callback :component id :callback :on-reload|:on-error}
sourceraw docstring

ensure-init!clj

(ensure-init! opts)

init! when not yet initialized, else extend-init! — the idempotent way for a host to declare the dirs it needs without resetting a baseline another caller established. Returns {:initialized? true :fresh? bool :dirs :added}.

`init!` when not yet initialized, else `extend-init!` — the idempotent way
for a host to declare the dirs it needs without resetting a baseline another
caller established. Returns {:initialized? true :fresh? bool :dirs :added}.
sourceraw docstring

extend-init!clj

(extend-init! {:keys [dirs no-reload no-unload]})

Extend an initialized registry: union dirs, no-reload and no-unload into clj-reload's config WITHOUT resetting the change baseline or the per-file view — a change declined before this call is still pending after it. No-op when nothing is new. Restarts the file watcher, when one is running, over the union.

Returns {:dirs [...] :added [...]}.

Extend an initialized registry: union `dirs`, `no-reload` and `no-unload`
into clj-reload's config WITHOUT resetting the change baseline or the
per-file view — a change declined before this call is still pending after
it. No-op when nothing is new. Restarts the file watcher, when one is
running, over the union.

Returns {:dirs [...] :added [...]}.
sourceraw docstring

find-namespacesclj

(find-namespaces pattern)

Find namespaces matching a pattern. Delegates to clj-reload/find-namespaces.

Find namespaces matching a pattern.
Delegates to clj-reload/find-namespaces.
sourceraw docstring

get-componentclj

(get-component component-id)

Get component registration by ID.

Get component registration by ID.
sourceraw docstring

init!clj

(init!)
(init! opts)

Initialize hive-hot with source directories.

Options (passed to clj-reload/init):

  • :dirs - Source directories (default: ["src"])
  • :no-reload - Namespaces to never reload
  • :no-unload - Namespaces to reload but not unload
  • :since - Epoch ms the change baseline starts from (default: now). A file modified after it counts as changed on the first reload; pass the JVM start time so edits made before this init are not silently taken as the baseline.

Resets the per-file baseline. Use ensure-init! to extend an initialized registry without resetting it.

Example:

(init! {:dirs ["src" "dev"]
        :no-reload '#{user}})
Initialize hive-hot with source directories.

Options (passed to clj-reload/init):
- :dirs      - Source directories (default: ["src"])
- :no-reload - Namespaces to never reload
- :no-unload - Namespaces to reload but not unload
- :since     - Epoch ms the change baseline starts from (default: now). A
               file modified after it counts as changed on the first reload;
               pass the JVM start time so edits made before this init are
               not silently taken as the baseline.

Resets the per-file baseline. Use `ensure-init!` to extend an initialized
registry without resetting it.

Example:
```clojure
(init! {:dirs ["src" "dev"]
        :no-reload '#{user}})
```
sourceraw docstring

init-with-watcher!clj

(init-with-watcher!)
(init-with-watcher!
  {:keys [dirs claim-checker debounce-ms no-reload no-unload]
   :or {dirs ["src"] claim-checker (constantly #{}) debounce-ms 100}
   :as opts})

Initialize hive-hot with file watcher and coordinating debouncer.

This wires together:

  • FileWatcher (from hive-hot.watcher)
  • CoordinatingDebouncer (from hive-hot.debounce)
  • reload! for actual reloading

Options:

  • :dirs - Source directories to watch (default: ["src"])
  • :claim-checker - Function returning set of claimed files (default: (constantly #{}))
  • :debounce-ms - Debounce window in ms (default: 100)
  • :no-reload - Namespaces to never reload
  • :no-unload - Namespaces to reload but not unload

clj-reload is initialized through ensure-init!: an already-initialized registry is EXTENDED with the dirs, never reset, so a change made between init and watch is not silently taken as the baseline.

The claim-checker is typically created via:

(events/make-claim-checker logic/get-all-claims)

When a file changes:

  1. FileWatcher detects change
  2. Debouncer checks claim-checker
    • If file is claimed: buffer until released
    • If unclaimed: apply debounce-ms window
  3. After debounce: emit :file/changed, call reload!

Example:

;; Basic usage (no coordination)
(init-with-watcher! {:dirs ["src" "dev"]})

;; With claim-aware coordination
(init-with-watcher!
  {:dirs ["src"]
   :claim-checker (events/make-claim-checker logic/get-all-claims)})

Returns :watching on success.

Initialize hive-hot with file watcher and coordinating debouncer.

This wires together:
- FileWatcher (from hive-hot.watcher)
- CoordinatingDebouncer (from hive-hot.debounce)
- reload! for actual reloading

Options:
- :dirs          - Source directories to watch (default: ["src"])
- :claim-checker - Function returning set of claimed files
                   (default: (constantly #{}))
- :debounce-ms   - Debounce window in ms (default: 100)
- :no-reload     - Namespaces to never reload
- :no-unload     - Namespaces to reload but not unload

clj-reload is initialized through `ensure-init!`: an already-initialized
registry is EXTENDED with the dirs, never reset, so a change made between
init and watch is not silently taken as the baseline.

The claim-checker is typically created via:
```clojure
(events/make-claim-checker logic/get-all-claims)
```

When a file changes:
1. FileWatcher detects change
2. Debouncer checks claim-checker
   - If file is claimed: buffer until released
   - If unclaimed: apply debounce-ms window
3. After debounce: emit :file/changed, call reload!

Example:
```clojure
;; Basic usage (no coordination)
(init-with-watcher! {:dirs ["src" "dev"]})

;; With claim-aware coordination
(init-with-watcher!
  {:dirs ["src"]
   :claim-checker (events/make-claim-checker logic/get-all-claims)})
```

Returns :watching on success.
sourceraw docstring

list-componentsclj

(list-components)

List all registered component IDs.

List all registered component IDs.
sourceraw docstring

reg-hotclj

(reg-hot component-id {:keys [ns on-reload on-error] :as opts})

Register a component for hot-reload callbacks.

Options:

  • :ns - Namespace symbol (required)
  • :on-reload - Callback after successful reload (fn [])
  • :on-error - Callback on reload failure (fn [exception])

Note: clj-reload handles dependency tracking automatically. Use this for application-level callbacks (restart server, etc).

Example:

(reg-hot :http-server
  {:ns 'my.server
   :on-reload #(println "Server code reloaded!")})
Register a component for hot-reload callbacks.

Options:
- :ns        - Namespace symbol (required)
- :on-reload - Callback after successful reload (fn [])
- :on-error  - Callback on reload failure (fn [exception])

Note: clj-reload handles dependency tracking automatically.
Use this for application-level callbacks (restart server, etc).

Example:
```clojure
(reg-hot :http-server
  {:ns 'my.server
   :on-reload #(println "Server code reloaded!")})
```
sourceraw docstring

reload!clj

(reload!)
(reload! opts)

Reload changed namespaces and their dependents.

Without :only this is (reload-scoped! nil opts): every change the registry's per-file baseline has not seen, under every tracked dir — which includes the changes an earlier SCOPED reload declined.

Options:

  • :only - :loaded | :all | #"pattern" — clj-reload's explicit selection, passed straight through (bypasses the baseline)
  • :throw - Throw on error (default: false, returns result map)

Emits events via hive-events:

  • :hot/reload-start before reload
  • :hot/reload-success or :hot/reload-error after

Returns: {:success bool :unloaded [ns ...] :loaded [ns ...] :failed ns-or-nil :error message-or-nil :exception throwable-or-nil :ms elapsed}

Example:

(reload!)                        ; Reload changed
(reload! {:only :all})           ; Reload everything
(reload! {:only #".*-test"})   ; Reload matching
Reload changed namespaces and their dependents.

Without :only this is `(reload-scoped! nil opts)`: every change the
registry's per-file baseline has not seen, under every tracked dir — which
includes the changes an earlier SCOPED reload declined.

Options:
- :only  - :loaded | :all | #"pattern" — clj-reload's explicit selection,
           passed straight through (bypasses the baseline)
- :throw - Throw on error (default: false, returns result map)

Emits events via hive-events:
- :hot/reload-start before reload
- :hot/reload-success or :hot/reload-error after

Returns:
{:success bool
 :unloaded [ns ...]
 :loaded [ns ...]
 :failed ns-or-nil
 :error message-or-nil
 :exception throwable-or-nil
 :ms elapsed}

Example:
```clojure
(reload!)                        ; Reload changed
(reload! {:only :all})           ; Reload everything
(reload! {:only #".*-test"})   ; Reload matching
```
sourceraw docstring

reload-all!clj

(reload-all!)

Force reload of all namespaces.

Use sparingly - prefer reload! for incremental reloads.

Force reload of all namespaces.

Use sparingly - prefer reload! for incremental reloads.
sourceraw docstring

reload-scoped!clj

(reload-scoped! roots)
(reload-scoped! roots opts)

Reload the changes under roots — and only those.

clj-reload holds ONE changed-set across every tracked dir, so a plain reload loads whatever any co-tenant has saved anywhere. This pass admits the changed files under roots, drags in the namespaces that depend on them (the cascade has to recompile those against the new vars, wherever they live), and DECLINES every other change: those files keep their baseline and stay pending for the reload that owns their root. roots nil or empty means every tracked dir.

Returns clj-reload's result plus: :success bool :ms elapsed :scoped? true when roots were given :roots the canonical roots :skipped [ns-string ...] changed outside the roots, NOT loaded :dragged [ns-string ...] changed outside the roots, loaded as dependents :unchanged? true when nothing under the roots had changed — no pass ran :multi-file {ns [path ...]} loaded namespaces found in more than one file

Reload the changes under `roots` — and only those.

clj-reload holds ONE changed-set across every tracked dir, so a plain reload
loads whatever any co-tenant has saved anywhere. This pass admits the
changed files under `roots`, drags in the namespaces that depend on them
(the cascade has to recompile those against the new vars, wherever they
live), and DECLINES every other change: those files keep their baseline and
stay pending for the reload that owns their root. `roots` nil or empty means
every tracked dir.

Returns clj-reload's result plus:
  :success    bool
  :ms         elapsed
  :scoped?    true when roots were given
  :roots      the canonical roots
  :skipped    [ns-string ...]  changed outside the roots, NOT loaded
  :dragged    [ns-string ...]  changed outside the roots, loaded as dependents
  :unchanged? true when nothing under the roots had changed — no pass ran
  :multi-file {ns [path ...]}  loaded namespaces found in more than one file
sourceraw docstring

remove-listener!clj

(remove-listener! listener-id)

Remove a reload event listener.

Remove a reload event listener.
sourceraw docstring

reset-all!clj

(reset-all!)

Reset all registrations and the per-file baseline. Use in tests.

Reset all registrations and the per-file baseline. Use in tests.
sourceraw docstring

scope-planclj

(scope-plan roots)

What a scoped reload of roots WOULD do — no effects.

Compares every tracked file's mtime against this registry's per-file baseline (falling back to clj-reload's :since), splits the changed files by root, and closes the wanted namespaces forward over the current require graph. roots nil or empty means every tracked dir.

Returns {:roots [canonical root ...] nil when unscoped :want [File ...] changed under the roots — loaded :dragged [File ...] changed outside, but a dependent of a wanted namespace — loaded, since the cascade must recompile it anyway :skipped [File ...] changed outside, unrelated — DECLINED; stays pending for its own root :mask #{ns ...} namespaces pinned :no-reload for the run :since long | nil the :since window the run needs, nil when there is nothing to load :old-since long}

What a scoped reload of `roots` WOULD do — no effects.

Compares every tracked file's mtime against this registry's per-file
baseline (falling back to clj-reload's :since), splits the changed files by
root, and closes the wanted namespaces forward over the current require
graph. `roots` nil or empty means every tracked dir.

Returns
  {:roots     [canonical root ...]   nil when unscoped
   :want      [File ...]             changed under the roots — loaded
   :dragged   [File ...]             changed outside, but a dependent of a
                                     wanted namespace — loaded, since the
                                     cascade must recompile it anyway
   :skipped   [File ...]             changed outside, unrelated — DECLINED;
                                     stays pending for its own root
   :mask      #{ns ...}              namespaces pinned :no-reload for the run
   :since     long | nil             the :since window the run needs, nil
                                     when there is nothing to load
   :old-since long}
sourceraw docstring

statusclj

(status)

Get current hot-reload status.

Returns: {:initialized? bool :components {...} :listener-count n :dirs [...] tracked source dirs (when initialized) :since ms clj-reload's change baseline (when initialized) :pending [ns ...] namespaces changed on disk that no reload has loaded yet (when initialized)}

Get current hot-reload status.

Returns:
{:initialized? bool
 :components {...}
 :listener-count n
 :dirs [...]           tracked source dirs (when initialized)
 :since ms             clj-reload's change baseline (when initialized)
 :pending [ns ...]     namespaces changed on disk that no reload has loaded
                       yet (when initialized)}
sourceraw docstring

stop-watcher!clj

(stop-watcher!)

Stop the file watcher if running.

Stop the file watcher if running.
sourceraw docstring

unreg-hotclj

(unreg-hot component-id)

Unregister a component.

Unregister a component.
sourceraw docstring

watcher-statusclj

(watcher-status)

Get watcher status.

Returns nil if not watching, or map with:

  • :watching? true
  • :dirs watched directories
Get watcher status.

Returns nil if not watching, or map with:
- :watching? true
- :dirs watched directories
sourceraw docstring

watching-pathsclj

(watching-paths)

Get list of directories being watched. Returns empty vector if not watching.

Get list of directories being watched.
Returns empty vector if not watching.
sourceraw docstring

with-reloadcljmacro

(with-reload & body)

Execute body, then reload.

Useful for REPL development:

(with-reload
  (spit "src/my/service.clj" new-code))
Execute body, then reload.

Useful for REPL development:
```clojure
(with-reload
  (spit "src/my/service.clj" new-code))
```
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close