Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revive Tailwind CSS Compilation #246

Merged
merged 28 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ jobs:
- name: 🔧 Setup Google Cloud SDK
uses: google-github-actions/setup-gcloud@v0.3.0

- name: 🔧 NPM install
run: npm install

- name: 📓 Build Clerk Book
run: clojure -J-Dclojure.main.report=stderr -X:demo:nextjournal/clerk :git/sha '"${{ github.sha }}"' :git/url '"https://github.com/nextjournal/clerk"' :paths '["book.clj"]'

Expand Down
4 changes: 3 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
org.babashka/cli {:mvn/version "0.5.40"}}
:extra-paths ["notebooks"]
:exec-fn nextjournal.clerk/build!
:exec-args {:paths-fn nextjournal.clerk.builder/clerk-docs}
:exec-args {:paths-fn nextjournal.clerk.builder/clerk-docs
:compile-css true}
:main-opts ["-m" "babashka.cli.exec"]
:jvm-opts ["-Dclojure.main.report=stdout"]
:nextjournal.clerk/aliases [:demo]}
:sci {:extra-deps {applied-science/js-interop {:mvn/version "0.3.3"}
org.babashka/sci {:mvn/version "0.5.34"}
Expand Down
5 changes: 1 addition & 4 deletions notebooks/markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ and render back to hiccup with customisable elements.
(def renderers
(assoc md.transform/default-hiccup-renderers
:doc (partial md.transform/into-markup [:div.viewer-markdown])
:ruler (fn [_ _]
[:hr.mt-1.mb-10
{:style {:border "10px solid magenta"
:border-radius "10px"}}])))
:ruler (constantly [:hr.mt-1.mb-10.border-0.w-full.h-5.bg-fuchsia-900.rounded-full])))

(def hiccup
(md.transform/->hiccup renderers sliced))
Expand Down
2 changes: 1 addition & 1 deletion resources/stylesheets/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
darkMode: "class",
content: ["./public/build/index.html", "./public/build/**/*.html", "./build/viewer.js"],
content: ["./tw/viewer.js", "./tw/**/*.edn"],
safelist: ['dark'],
theme: {
extend: {},
Expand Down
2 changes: 1 addition & 1 deletion resources/viewer-js-hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3CdrarFnse5u5D3b8hfjwcAa6Npa
3qePCgpcmuVcJNqR8mK6LSfWdRT2
13 changes: 10 additions & 3 deletions src/nextjournal/clerk.clj
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@

(defn ^:private normalize-opts [opts]
(set/rename-keys opts #_(into {} (map (juxt identity #(keyword (str (name %) "?")))) [:bundle :browse :dashboard])
{:bundle :bundle?, :browse :browse?, :dashboard :dashboard?}))
{:bundle :bundle?, :browse :browse?, :dashboard :dashboard? :compile-css :compile-css?}))

(defn ^:private started-via-bb-cli? [opts]
(contains? (meta opts) :org.babashka/cli))
Expand Down Expand Up @@ -438,8 +438,15 @@
:dashboard {:desc "Flag to serve a dashboard with the build progress."}
:out-path {:desc "Path to an build output folder, defaults to \"public/build\"."}
:git/sha {:desc "Git sha to use for the backlink."}
:git/url {:desc "Git url to use for the backlink."}}
:order [:paths :paths-fn :index :browse :bundle :dashbaord :out-path :git/sha :git/url]}}
:git/url {:desc "Git url to use for the backlink."}
:compile-css {:desc "Flag to compile all viewer stylesheets and add a minimized CSS file to the output folder.

Assumes tailwind installed, as per
```
npm install -D tailwindcss @tailwindcss/typography
```
"}}
:order [:paths :paths-fn :index :browse :bundle :dashbaord :out-path :git/sha :git/url :compile-css]}}
[build-opts]
(if (:help build-opts)
(if-let [format-opts (and (started-via-bb-cli? build-opts) (requiring-resolve 'babashka.cli/format-opts))]
Expand Down
60 changes: 58 additions & 2 deletions src/nextjournal/clerk/builder.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
(:require [babashka.fs :as fs]
[clojure.java.browse :as browse]
[clojure.set :as set]
[clojure.java.io :as io]
[clojure.string :as str]
[clojure.java.shell :refer [sh]]
[nextjournal.clerk.analyzer :as analyzer]
[nextjournal.clerk.builder-ui :as builder-ui]
[nextjournal.clerk.eval :as eval]
[nextjournal.clerk.parser :as parser]
[nextjournal.clerk.view :as view]
[nextjournal.clerk.webserver :as webserver]))
[nextjournal.clerk.webserver :as webserver]
[nextjournal.clerk.config :as config]))

(def clerk-docs
(into ["CHANGELOG.md"
Expand Down Expand Up @@ -78,6 +81,7 @@
(str "Errored in " duration ". ❌\n")
(str "Done in " duration ". ✅\n"))
:building (str "🔨 Building \"" (:file doc) "\"… ")
:compiling-css "🎨 Compiling CSS… "
:downloading-cache (str "⏬ Downloading distributed cache… ")
:uploading-cache (str "⏫ Uploading distributed cache… ")
:finished (str "📦 Static app bundle created in " duration ". Total build time was " (-> event :total-duration format-duration) ".\n"))))
Expand Down Expand Up @@ -183,8 +187,53 @@
(expand-paths {:paths-fn `my-paths}))
#_(expand-paths {:paths ["notebooks/viewers**"]})

(defn compile-css!
"Compiles a minimal tailwind css stylesheet with only the used styles included, replaces the generated stylesheet link in html pages."
[{:keys [out-path]} docs]
(assert (and (= 0 (:exit (sh "which" "npx"))) (= 0 (:exit (sh "npx" "tailwindcss"))))
"Clerk's CSS optimizaiton failed: node and tailwind need to be installed. Please run `npm install -D tailwindcss @tailwindcss/typography` and retry.")
(let [tw-folder (fs/create-dirs "tw")
tw-input (str tw-folder "/input.css")
tw-config (str tw-folder "/tailwind.config.cjs")
tw-output (str tw-folder "/viewer.css")
tw-viewer (str tw-folder "/viewer.js")]
(spit tw-config (slurp (io/resource "stylesheets/tailwind.config.js")))
;; NOTE: a .cjs extension is safer in case the current npm project is of type module (like Clerk's): in this case all .js files
;; are treated as ES modules and this is not the case of our tw config.
(spit tw-input (slurp (io/resource "stylesheets/viewer.css")))
(spit tw-viewer (slurp (get @config/!resource->url "/js/viewer.js")))
(doseq [{:keys [file viewer]} docs]
(spit (let [path (fs/path tw-folder (str/replace file #"\.(cljc?|md)$" ".edn"))]
(fs/create-dirs (fs/parent path))
(str path))
(pr-str viewer)))
(let [{:as ret :keys [out err exit]}
(sh "npx" "tailwindcss"
"--input" tw-input
"--config" tw-config
;; FIXME: pass inline
;;"--content" (str tw-viewer)
;;"--content" (str tw-folder "/**/*.edn")
"--output" tw-output
"--minify")]
(when-not (= 0 exit)
(throw (ex-info (str "Clerk build! failed\n" out "\n" err) ret))))
(let [content-addressed (fs/file "_data" (str (analyzer/valuehash (slurp tw-output)) ".css"))]
(fs/create-dirs (fs/parent (fs/file out-path content-addressed)))
(when-not (fs/exists? (fs/file out-path content-addressed))
(fs/copy tw-output (fs/file out-path content-addressed)))
(swap! config/!resource->url assoc "/css/viewer.css" (str content-addressed))
;; cleanup
(fs/delete-tree tw-folder))))

#_(fs/delete-tree "public/build")
#_(build-static-app! {:paths ["notebooks/hello.clj" "notebooks/markdown.md" "notebooks/viewers/image.clj"]
:bundle? false
:compile-css? true})

(defn build-static-app! [opts]
(let [{:as opts :keys [paths download-cache-fn upload-cache-fn bundle? report-fn]} (process-build-opts opts)
(let [{:as opts :keys [download-cache-fn upload-cache-fn report-fn compile-css?]}
(process-build-opts opts)
{:keys [expanded-paths error]} (try {:expanded-paths (expand-paths opts)}
(catch Exception e
{:error e}))
Expand Down Expand Up @@ -223,6 +272,10 @@
result)) state (range))
_ (when-let [first-error (some :error state)]
(throw first-error))
_ (when compile-css?
(report-fn {:stage :compiling-css})
(let [{duration :time-ms} (eval/time-ms (compile-css! opts state))]
(report-fn {:stage :done :duration duration})))
{state :result duration :time-ms} (eval/time-ms (write-static-app! opts state))]
(when upload-cache-fn
(report-fn {:stage :uploading-cache})
Expand All @@ -235,3 +288,6 @@
#_(build-static-app! {:paths ["index.clj" "notebooks/rule_30.clj" "notebooks/markdown.md"] :bundle? false :browse? false})
#_(build-static-app! {:paths ["notebooks/viewers/**"]})
#_(build-static-app! {:index "notebooks/rule_30.clj" :git/sha "bd85a3de12d34a0622eb5b94d82c9e73b95412d1" :git/url "https://github.com/nextjournal/clerk"})
#_(swap! config/!resource->url assoc
"/js/viewer.js" (-> config/lookup-url slurp clojure.edn/read-string (get "/js/viewer.js")))
#_(swap! config/!resource->url dissoc "/css/viewer.css")
33 changes: 23 additions & 10 deletions src/nextjournal/clerk/view.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,44 @@
[nextjournal.clerk.viewer :as v]
[hiccup.page :as hiccup]
[clojure.string :as str]
[clojure.java.io :as io]))
[clojure.java.io :as io])
(:import (java.net URI)))

(defn doc->viewer
([doc] (doc->viewer {} doc))
([opts {:as doc :keys [ns file]}]
(binding [*ns* ns]
(-> (merge doc opts) v/notebook v/present))))


#_(doc->viewer (nextjournal.clerk/eval-file "notebooks/hello.clj"))
#_(nextjournal.clerk/show! "notebooks/test.clj")
#_(nextjournal.clerk/show! "notebooks/visibility.clj")

(defn include-viewer-css []
(defn relative? [url]
(and (not (.isAbsolute (URI. url)))
(not (str/starts-with? url "/"))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are both of these checks needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because (= false (.isAbsolute (URI. "/viewer.css")))

#_ (relative? "/hello/css")
#_ (relative? "hello/css")
#_ (relative? "https://cdn.stylesheet.css")

(defn relativize [url current-path]
(str (str/join (repeat (get (frequencies current-path) \/ 0) "../"))
url))

(defn include-viewer-css [{:keys [current-path]}]
(if-let [css-url (@config/!resource->url "/css/viewer.css")]
(hiccup/include-css css-url)
(hiccup/include-css (cond-> css-url
(and current-path (relative? css-url))
(relativize current-path)))
(list (hiccup/include-js "https://cdn.tailwindcss.com?plugins=typography")
[:script (-> (slurp (io/resource "stylesheets/tailwind.config.js"))
(str/replace #"^module.exports" "tailwind.config")
(str/replace #"require\(.*\)" ""))]
(str/replace #"^module.exports" "tailwind.config")
(str/replace #"require\(.*\)" ""))]
[:style {:type "text/tailwindcss"} (slurp (io/resource "stylesheets/viewer.css"))])))

(defn include-css+js []
(defn include-css+js [state]
(list
(include-viewer-css)
(include-viewer-css state)
[:script {:type "module" :src (@config/!resource->url "/js/viewer.js")}]
(hiccup/include-css "https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.css")
(hiccup/include-css "https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&family=Fira+Mono:wght@400;700&family=Fira+Sans+Condensed:ital,wght@0,700;1,700&family=Fira+Sans:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap")))
Expand All @@ -38,7 +51,7 @@
[:head
[:meta {:charset "UTF-8"}]
[:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
(include-css+js)]
(include-css+js state)]
[:body.dark:bg-gray-900
[:div#clerk]
[:script {:type "module"} "let viewer = nextjournal.clerk.sci_env
Expand All @@ -58,7 +71,7 @@ window.ws_send = msg => ws.send(msg)")]]))
[:meta {:charset "UTF-8"}]
[:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
(when current-path (v/open-graph-metas (-> state :path->doc (get current-path) v/->value :open-graph)))
(include-css+js)]
(include-css+js state)]
[:body
[:div#clerk-static-app]
[:script {:type "module"} "let viewer = nextjournal.clerk.sci_env
Expand Down