diff --git a/.gitignore b/.gitignore index 2b15657..58fe583 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ gh-pages/ /dist /.clj-kondo/.cache /.clj-kondo/rewrite-clj +/plugins/demo/resources/public/js/ diff --git a/bb.edn b/bb.edn index 802138b..f355484 100644 --- a/bb.edn +++ b/bb.edn @@ -2,10 +2,14 @@ #_{:local/root "../sci.nrepl"} {:git/sha "2f8a9ed2d39a1b09d2b4d34d95494b56468f4a23"} io.github.babashka/http-server - {:git/sha "b38c1f16ad2c618adae2c3b102a5520c261a7dd3"}} + {:git/sha "b38c1f16ad2c618adae2c3b102a5520c261a7dd3"} + io.github.scittle/build + {:local/root "build"} + io.github.babashka/scittle.datascript {:local/root "plugins/datascript"}} :tasks - {:requires ([babashka.fs :as fs] + {:requires ([scittle.build :as build] + [babashka.fs :as fs] [cheshire.core :as json] [babashka.process :as p :refer [process]]) @@ -15,8 +19,7 @@ (fs/delete-tree ".shadow-cljs"))} shadow:watch {:doc "Development build. Starts webserver and watches for changes." - :task (clojure {:extra-env {"SCI_ELIDE_VARS" "true"}} - "-M:dev -m shadow.cljs.devtools.cli watch main")} + :task (build/build *command-line-args* {:action "watch"})} http-server {:doc "Starts http server for serving static files" :requires ([babashka.http-server :as http]) @@ -34,8 +37,7 @@ (deref (promise)))} prod {:doc "Builds production artifacts." - :task (clojure {:extra-env {"SCI_ELIDE_VARS" "true"}} - "-M:dev -m shadow.cljs.devtools.cli release main")} + :task (build/build *command-line-args*)} dist {:doc "Prepare dist folder for npm package" :depends [prod] diff --git a/build/deps.edn b/build/deps.edn new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/build/deps.edn @@ -0,0 +1 @@ +{} diff --git a/build/src/scittle/build.clj b/build/src/scittle/build.clj new file mode 100644 index 0000000..8586003 --- /dev/null +++ b/build/src/scittle/build.clj @@ -0,0 +1,71 @@ +(ns scittle.build + "Provides bb tasks for building and releasing scittle" + (:require + [babashka.classpath :as classpath] + [babashka.fs :as fs] + [babashka.tasks :refer [clojure]] + [clojure.edn :as edn] + [clojure.string :as str])) + +(defn- feature-files + [] + (filter fs/exists? + (map (fn [d] + (fs/file d "scittle_plugin.edn")) + (classpath/split-classpath (classpath/get-classpath))))) + +(defn- read-configs + [files] + (->> files + (mapcat (comp edn/read-string slurp str)))) + +(defn- build-cmd [cmd scittle-dir] + (let [files (feature-files) + feature-configs (read-configs files) + ;; Each ./src/scittle_plugin.edn has a ./deps.edn + feature-dirs (map (comp fs/parent fs/parent) files) + cmd' (if (seq files) + (format "-Sdeps '%s' %s" + {:deps + (merge (into {} + (map (fn [dir] + [(symbol (str (fs/file-name dir) "/deps")) + {:local/root (str dir)}]) + feature-dirs)) + {'scittle/deps {:local/root scittle-dir}})} + cmd) + cmd)] + (when (seq feature-configs) + (println "Building features:" (str/join ", " (map :name feature-configs)) "...")) + (if (seq feature-configs) + (apply str cmd' + (map (fn [m] (format " --config-merge '%s'" (pr-str (:shadow-config m)))) + feature-configs)) + cmd'))) + +(defn- build* + [cmd] + (let [building-outside-scittle? (not (fs/exists? "shadow-cljs.edn")) + scittle-dir (when building-outside-scittle? + (->> (classpath/get-classpath) + classpath/split-classpath + ;; Pull out scittle from local/root or git/url + (some #(when (re-find #"(scittle/[0-9a-f]+|scittle)/src" %) %)) + fs/parent))] + (when building-outside-scittle? + (fs/copy (fs/file scittle-dir "shadow-cljs.edn") "shadow-cljs.edn")) + (let [cmd (build-cmd cmd (str scittle-dir))] + (println "> clojure" cmd) + (clojure {:extra-env {"SCI_ELIDE_VARS" "true"}} cmd)) + (when building-outside-scittle? + (fs/delete "shadow-cljs.edn")))) + +(defn build + "Build scittle shadow builds using clojure cmd and commandline args. Features on + classpath are automatically added. + + Options: + + * :action - compile action, defaults to release, but may also be compile or watch" + [{:keys [action] :or {action "release"}}] + (build* (format "-M -m shadow.cljs.devtools.cli --force-spawn %s main" action))) diff --git a/deps.edn b/deps.edn index 58efc55..ec562ba 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,7 @@ {:paths ["src" "resources"] - :deps {org.clojure/clojure {:mvn/version "1.11.1"} + thheller/shadow-cljs {:mvn/version "2.20.15"} org.babashka/sci {:git/url "https://github.com/babashka/sci" :git/sha "a85c488ee45700bcbe67bc01ab1c27407fff7887"} #_{:local/root "../babashka/sci"} @@ -19,8 +19,8 @@ io.github.babashka/sci.configs #_{:local/root "/Users/borkdude/dev/sci.configs"} {:git/url "https://github.com/babashka/sci.configs" - :git/sha "bf8d209e4aeabb92cb1be04e3d8f789583d5f449"}} + :git/sha "33bd51e53700b224b4cb5bda59eb21b62f962745"}} :aliases {:dev {:extra-paths ["dev"] - :extra-deps {thheller/shadow-cljs {:mvn/version "2.20.15"}}}}} + :extra-deps {}}}} diff --git a/plugins/datascript/deps.edn b/plugins/datascript/deps.edn new file mode 100644 index 0000000..1454ae1 --- /dev/null +++ b/plugins/datascript/deps.edn @@ -0,0 +1,3 @@ +{:deps + {datascript/datascript {:mvn/version "1.3.12"} + io.github.babashka/sci.configs {:git/sha "33bd51e53700b224b4cb5bda59eb21b62f962745"}}} diff --git a/plugins/datascript/src/scittle/datascript.cljs b/plugins/datascript/src/scittle/datascript.cljs new file mode 100644 index 0000000..f3dac97 --- /dev/null +++ b/plugins/datascript/src/scittle/datascript.cljs @@ -0,0 +1,9 @@ +(ns scittle.datascript + {:no-doc true} + (:require [sci.configs.tonsky.datascript :refer [config]] + [scittle.core :as scittle])) + +(defn init [] + (scittle/register-plugin! + ::datascript + config)) diff --git a/plugins/datascript/src/scittle_plugin.edn b/plugins/datascript/src/scittle_plugin.edn new file mode 100644 index 0000000..09eae58 --- /dev/null +++ b/plugins/datascript/src/scittle_plugin.edn @@ -0,0 +1,12 @@ +[{:name scittle/datascript + :namespaces [datascript.core datascript.db] + :js "./scittle.datascript.js" + :shadow-config + {:compiler-options {:externs ["datascript/externs.js"]} + :modules + {:scittle.datascript + {:init-fn scittle.datascript/init + ;; From https://github.com/tonsky/datascript/issues/298#issuecomment-813790783 + :prepend "globalThis.datascript = {};" + :depends-on #{:scittle} + :entries [datascript.core]}}}}] diff --git a/plugins/demo/README.md b/plugins/demo/README.md new file mode 100644 index 0000000..e9f58eb --- /dev/null +++ b/plugins/demo/README.md @@ -0,0 +1,25 @@ +# Demo + +A demo project of a custom scittle build. + +See: + +- `bb.edn` with + - `:deps` which includes: + - a dependency on the `scittle.build` project to build scittle + custom features + - zero or more plugin dependencies + - helpers like static file server + - development `:tasks`. Run `bb dev` for development and `bb release` to produce release artifacts. +- `deps.edn`: this only contains a dependency on scittle itself + +Available plugins are in the `plugins` directory inside the top level directory of this repo. + +Writing a plugin involves writing + +- SCI configuration (this can be shared with users in the [sci.configs](https://github.com/babashka/sci.configs) project +- Adding a `scittle_plugin.edn` file on the plugin's classpath (e.g. in the `src` directory). This EDN file contains: + - `:name`, name of the plugin + - `:namespaces`: the namespaces exposed to SCI + - `:js`: the name of the produced `.js` module file + - `:shadow-config`: the shadow-cljs configuration specific to this plugin +- A `.cljs` file with an `init` function which calls `scittle/register-plugin!`. diff --git a/plugins/demo/bb.edn b/plugins/demo/bb.edn new file mode 100644 index 0000000..516f478 --- /dev/null +++ b/plugins/demo/bb.edn @@ -0,0 +1,20 @@ +{:deps {io.github.babashka/scittle.build {:local/root "../../build"} + ;; datascript plugin + io.github.babashka/scittle.datascript {:local/root "../../plugins/datascript"} + io.github.babashka/http-server + {:git/sha "b38c1f16ad2c618adae2c3b102a5520c261a7dd3"}} + :tasks + {:requires ([scittle.build :as build]) + watch {:doc "Watch build" + :task (build/build {:action "watch"})} + serve {:doc "Starts http server for serving static files" + :requires ([babashka.http-server :as http]) + :task (do (http/serve {:port 1341 :dir "resources/public"}) + (println "Serving static assets at http://localhost:1341"))} + -dev {:depends [watch serve] + :parallel true} + dev {:doc "Run compilation in watch mode and start http server" + :task (do (run '-dev {:parallel true}) + (deref (promise)))} + release {:doc "Release build (advanced compiled JS)" + :task (build/build {})}}} diff --git a/plugins/demo/deps.edn b/plugins/demo/deps.edn new file mode 100644 index 0000000..62915a5 --- /dev/null +++ b/plugins/demo/deps.edn @@ -0,0 +1 @@ +{:deps {io.github.babashka/scittle {:local/root "../.."}}} diff --git a/plugins/demo/resources/public/index.html b/plugins/demo/resources/public/index.html new file mode 100644 index 0000000..a48dfc4 --- /dev/null +++ b/plugins/demo/resources/public/index.html @@ -0,0 +1,14 @@ + + +
+ + + + + + + + diff --git a/plugins/demo/shadow-cljs.edn b/plugins/demo/shadow-cljs.edn new file mode 100644 index 0000000..47e5deb --- /dev/null +++ b/plugins/demo/shadow-cljs.edn @@ -0,0 +1,32 @@ +{:deps + {:aliases [:dev]} + + :dev-http + {8000 "classpath:public"} + + :builds + {:main + {:target :browser + :js-options + {:resolve {"react" {:target :global + :global "React"} + "react-dom" {:target :global + :global "ReactDOM"}}} + :modules + {:scittle {:entries [scittle.core]} + :scittle.nrepl {:entries [scittle.nrepl] + :depends-on #{:scittle}} + :scittle.promesa {:entries [scittle.promesa] + :depends-on #{:scittle}} + :scittle.pprint {:entries [scittle.pprint] + :depends-on #{:scittle}} + :scittle.reagent {:entries [scittle.reagent] + :depends-on #{:scittle}} + :scittle.re-frame {:entries [scittle.re-frame] + :depends-on #{:scittle.reagent + :scittle}} + :scittle.cljs-ajax {:entries [scittle.cljs-ajax] + :depends-on #{:scittle}}} + :build-hooks [(shadow.cljs.build-report/hook)] + :output-dir "resources/public/js" + :devtools {:repl-pprint true}}}}