-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
shadow.clj
148 lines (123 loc) · 5.12 KB
/
shadow.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
(ns mentat.clerk-utils.build.shadow
"Utilities for generating custom Clerk viewer CLJS builds via `shadow-cljs`."
(:require [clojure.string]
[clojure.java.shell :refer [sh]]
[shadow.cljs.devtools.config :as shadow.config]
[shadow.cljs.devtools.server :as shadow.server]
[shadow.cljs.devtools.server.runtime :as runtime]
[shadow.cljs.devtools.server.util :as shadow.util]
[shadow.cljs.devtools.server.npm-deps :as npm-deps]
[shadow.cljs.devtools.api :as shadow.api]))
(def ^:private windows?
(clojure.string/starts-with?
(System/getProperty "os.name")
"Windows"))
(def npm-cmd
"System-specific NPM command, tuned for Windows or non-Windows."
(if windows? "npm.cmd" "npm"))
(def shadow-version
"Shadow version of the currently-loaded `shadow-cljs` dependency."
(shadow.util/find-version))
(def shadow-npm-dep
"Schema for the NPM dependency for `shadow-cljs` associated with the
currently loaded `shadow-cljs` JVM library."
{:id "shadow-cljs"
:version shadow-version})
(def ^:no-doc build-id ::clerk)
(def output-dir
"Output directory for our controlled `shadow-cljs` build."
".clerk/shadow-cljs")
(def js-path
"Location of the generated JS code."
(str output-dir "/main.js"))
(defn clerk-build-config
"Given sequence `cljs-namespaces` of symbols naming ClojureScript namspaces,
returns a `:builds` entry for a `shadow-cljs` build of Clerk's viewer JS.
The resulting build will include all supplied namespaces, plus Clerk's
`nextjournal.clerk.static-app` namespace.`"
[cljs-namespaces]
(let [entries (into ['nextjournal.clerk.static-app]
cljs-namespaces)]
{:build-id build-id
:target :esm
:runtime :browser
:modules {:main {:entries entries}}
:output-dir output-dir
:compiler-options
{:infer-externs :auto :optimizations :advanced}
:js-options {:output-feature-set :es8}}))
(defn server-config
"Returns a full, normalized `shadow-cljs` config with no `:builds` registered
beyond the defaults.
This config is sufficient to start a `shadow-cljs` server."
[m]
(-> (shadow.config/normalize m)
(->> (merge shadow.config/default-config))
(update :builds #(merge shadow.config/default-builds %))
(assoc :user-config (shadow.config/load-user-config))))
(defn install-npm-deps!
"This command:
- Triggers an `npm install`
- Installs any dependency referenced by a `deps.cljs` file on the classpath
- Installs these dependencies into the calling project's `package.json` file.
Unlike `shadow-cljs`'s native `npm-deps/main`, this command also
installs [[shadow-npm-dep]], negating any need to tell the user to have
versions match or to remember to do this install themselves."
[]
(let [package-json (npm-deps/read-package-json ".")
deps (->> (npm-deps/get-deps-from-classpath)
(cons shadow-npm-dep)
(npm-deps/resolve-conflicts)
(remove #(npm-deps/is-installed? % package-json)))]
(when (seq package-json)
(println "Running npm install...")
(println
(:out
(sh npm-cmd "install"))))
(npm-deps/install-deps {} deps)))
(defn stop-watch!
"Shuts down the `shadow-cljs` server (if running) and stops the build watcher
for the custom Clerk viewer build."
[]
(when (runtime/get-instance)
(shadow.api/stop-worker build-id)
(shadow.server/stop!)))
(defn watch!
"Given some sequence `cljs-namespaces` of symbols representing ClojureScript
namespaces,
- installs all required npm dependencies with [[install-npm-deps!]]
- builds a custom Clerk viewer bundle with these namespaces included - starts
a `shadow-cljs` watcher process that recompiles the bundle on any file change
- serves the generated JS from a `shadow-cljs` server.
Optionally takes a map of config options:
- `:port`: overrides the port from which `shadow-cljs` serves the JS.
Returns a map with the following keys:
- `:js-url`: URL with the JS location
- `:stop-fn`: No-arg function to call to kill the watcher. (You can also kill
it with [[stop-watch!]].)"
([cljs-namespaces]
(watch! cljs-namespaces {}))
([cljs-namespaces {:keys [port] :or {port 8765}}]
(let [config (server-config {:dev-http {port output-dir}})
build-config (clerk-build-config cljs-namespaces)]
(install-npm-deps!)
(shadow.server/start! config)
(if (shadow.api/worker-running? build-id)
(prn "Watcher already running!")
(shadow.api/with-runtime
(shadow.api/watch build-config)))
{:js-url (str "http://localhost:" port "/main.js")
:stop-fn stop-watch!})))
(defn release!
"Given some sequence `cljs-namespaces` of symbols representing ClojureScript
namespaces,
- installs all required npm dependencies with [[install-npm-deps!]]
- generates a release build of custom Clerk viewer JS.
Returns the path of the generated JS."
[cljs-namespaces]
(let [config (clerk-build-config cljs-namespaces)]
(install-npm-deps!)
(shadow.api/with-runtime
(shadow.api/release* config {})
nil)
js-path))