Skip to content

Commit

Permalink
Fix #343: support :reload for reloading CLJS namespaces and JS code (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
borkdude authored Nov 7, 2024
1 parent a68d2c9 commit 637ef83
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 26 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ on: [push, pull_request]

jobs:
build:

runs-on: windows-latest

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

steps:
- name: Git checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -34,8 +37,8 @@ jobs:
cli: latest
bb: latest

- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
# - name: Setup tmate session
# uses: mxschmitt/action-tmate@v3

- name: Run tests
run: |
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ For a list of breaking changes, check [here](#breaking-changes).

[Nbb](https://github.com/babashka/nbb): Scripting in Clojure on Node.js using [SCI](https://github.com/babashka/sci)

## 1.3.195 (2024-11-07)

- [#343](https://github.com/babashka/nbb/issues/343): support `:reload` for reloading CLJS namespaces and JS code

## 1.3.194 (2024-10-23)

- Fix issue with loading `cljs.spec.alpha` by upgrading shadow-cljs
Expand Down
67 changes: 43 additions & 24 deletions src/nbb/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,28 @@
(defn register-module [mod internal-name]
(swap! loaded-modules assoc internal-name mod))

(defn load-js-module [libname internal-name]
(defn debug [& xs]
(binding [*print-fn* *print-err-fn*]
(apply prn xs)))

(defn load-js-module [libname internal-name reload?]
(-> (if-let [resolve (:resolve @ctx)]
(-> (resolve libname)
(.catch
(fn [_]
((.-resolve (:require @ctx)) libname))))
(js/Promise.resolve ((.-resolve (:require @ctx)) libname)))
(.then (fn [path]
(esm/dynamic-import
(let [path (if (and windows? (fs/existsSync path))
(str (url/pathToFileURL path))
path)]
path))))
(let [file-url (if (str/starts-with? (str path) "file:")
path
(when (and (or windows? reload?) (fs/existsSync path))
(str (url/pathToFileURL path))))
path (if (and reload?
;; not "node:fs" etc
file-url)
(str file-url "?uuid=" (random-uuid))
(or file-url path))]
(esm/dynamic-import path))))
(.then (fn [mod]
(register-module mod internal-name)
mod))))
Expand Down Expand Up @@ -237,7 +246,8 @@
feat (load-module feat libname as refer rename libspecs ns-opts)
(string? libname)
(let [libname (if (str/starts-with? libname "./")
(path/resolve (path/dirname (:file ns-opts)) libname)
(path/resolve (path/dirname (or (:file ns-opts) "."))
libname)
libname)
[libname properties*] (split-libname libname)
munged (munge libname)
Expand Down Expand Up @@ -266,24 +276,27 @@
(sci/add-class! internal-subname mod-field)
(sci/add-import! current-ns internal-subname field))))))
(handle-libspecs (next libspecs) ns-opts))
mod (js/Promise.resolve
(->
(or
;; skip loading if module was already loaded
(some-> (get @loaded-modules internal-name)
js/Promise.resolve)
(load-js-module libname internal-name)
;; else load module and register in loaded-modules under internal-name
)
(.then (fn [mod]
(if properties
(gobj/getValueByKeys mod properties)
mod)))))]
mod (let [reload? (contains? (:opts ns-opts) :reload)]
(js/Promise.resolve
(->
(or
;; skip loading if module was already loaded
(and (not reload?)
(some-> (get @loaded-modules internal-name)
js/Promise.resolve))
(load-js-module libname internal-name reload?)
;; else load module and register in loaded-modules under internal-name
)
(.then (fn [mod]
(if properties
(gobj/getValueByKeys mod properties)
mod))))))]
(-> mod
(.then after-load)))
:else
;; assume symbol
(if (sci/eval-form (ctx/get-ctx) (list 'clojure.core/find-ns (list 'quote libname)))
(if (and (not (contains? (:opts ns-opts) :reload))
(sci/eval-form (ctx/get-ctx) (list 'clojure.core/find-ns (list 'quote libname))))
;; built-in namespace
(do (sci/binding [sci/ns (:ns ns-opts)
sci/file (:file ns-opts)]
Expand Down Expand Up @@ -336,11 +349,14 @@
ns-obj (sci/binding [sci/ns @sci/ns]
(sci/eval-form (ctx/get-ctx) (list 'do (list* 'ns ns-name other-forms) '*ns*)))
libspecs (mapcat rest require-forms)
ns-opts (into #{} (filter keyword? libspecs))
libspecs (remove keyword? libspecs)
opts (assoc opts :ns ns-obj)]
(handle-libspecs libspecs opts)))
(handle-libspecs libspecs (assoc opts :opts ns-opts))))

(defn eval-require [require-form]
(let [args (rest require-form)
args (remove keyword? args)
libspecs (mapv #(sci/eval-form (ctx/get-ctx) %) args)
sci-ns @sci/ns
sci-file @sci/file]
Expand Down Expand Up @@ -681,8 +697,11 @@
(if *old-require*
(apply old-require args)
(await (.then (identity ;; with-async-bindings {sci/file @sci/file}
(handle-libspecs args {:ns @sci/ns
:file @sci/file}))
(let [opts (into #{} (filter keyword? args))
args (remove keyword? args)]
(handle-libspecs args {:ns @sci/ns
:file @sci/file
:opts opts})))
(fn [_]))))))

(def ^:dynamic *file* sci/file) ;; make clj-kondo+lsp happy
Expand Down
9 changes: 9 additions & 0 deletions test-scripts/reload.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(ns reload
(:require ["./reload.js"] :reload))

(defonce my-atom (atom 0))

(swap! my-atom inc)

(def x js/globalThis.x)

3 changes: 3 additions & 0 deletions test-scripts/reload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var x = globalThis.x || 0;
globalThis.x = x + 1;

8 changes: 8 additions & 0 deletions test/nbb/main_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,14 @@ result")
(fn [val]
(is (number? val))))))

(deftest-async reload-test
(is (.then (nbb/load-string "(require 'reload)
(require 'reload :reload)
[@reload/my-atom reload/x]")
(fn [val]
(is (= [2 2] val))))))

(defn init []
(t/run-tests 'nbb.main-test 'nbb.test-test))

0 comments on commit 637ef83

Please sign in to comment.