The work above seems to be enough to get a Cider repl and code reload (from 
shadow-cljs) working. So if you start the ring server with clojure -A:run 
and then run a shadow-cljs repl on the :build id it will hot reload your 
cljs code.

On Thursday, 30 April 2020 11:06:43 UTC+1, Jag Gunawardana wrote:
>
> One things I forgot. For a landing/marketing page, the main business aim 
> is to get someone to signup/in so the difference between the prod and dev 
> app is that for dev, I use a redirect (as per the signup link), in 
> production I have an Nginx rule that redirects the user to an application 
> page. As I use the same docker in all environments I specify this with an 
> env var. Not sure anyone needs this detail, but it explains when I have to 
> two app setups.
>
> On Thursday, 30 April 2020 11:01:21 UTC+1, Jag Gunawardana wrote:
>>
>> Quick background:
>>
>> I often use static site generators for landing pages, marketing pages 
>> etc. Hugo is normally my goto product for this as the themes are good and 
>> it is easy enough to change them, but recently I felt that there has to be 
>> a better way when you want something (just slightly) beyond a static page. 
>> I also have limited time to learn things, and my Go templating was very 
>> rusty. I use more Clojure(script) these days, so thought that there must be 
>> a simple way to generate static pages from something like hiccup, with a 
>> bit of Clojurescript interaction where needed. I also wanted to have a 
>> sensible dev setup so that I wouldn't have to constantly stop and start 
>> servers. Finally I've tried to move to shadow cljs for Clojurescript, and 
>> I've tried to use deps.edn rather than lein/boot, so I wanted to keep doing 
>> this. I started with looking at Juxt Edge as I've had some success with 
>> this for servers in the past, but it seemed a bit heavy handed for my 
>> requirements. I found the following very helpful pages:
>>
>> https://github.com/magnars/stasis
>> https://cjohansen.no/building-static-sites-in-clojure-with-stasis
>> http://nickgeorge.net/programming/building-my-static-clojure-website/
>> and post that started this discussion above.
>>
>> I have the following directory structure:
>>
>> src/clj/mypages    for Clojure
>> src/cljs/mypages  for Clojurescript  
>> resources/public/css
>> resources/public/js
>> resources/public/images
>>
>> Using the following:
>> deps.edn
>>
>> {:paths ["src/clj" "resources" "src/cljs"]
>>  :deps
>>  {org.clojure/clojure       {:mvn/version "1.10.1"}
>>   org.clojure/clojurescript {:mvn/version "1.10.597"}
>>   ring                      {:mvn/version "1.8.0"}
>>   ring/ring-defaults        {:mvn/version "0.3.2"}
>>   hiccup/hiccup             {:mvn/version "1.0.5"}
>>   stasis                    {:mvn/version "2.5.0"}
>>   optimus                   {:mvn/version "0.20.2"}
>>   com.taoensso/timbre       {:mvn/version "4.10.0"}}
>>
>>  :aliases
>>  {:cljs
>>   {:extra-deps {thheller/shadow-cljs {:mvn/version "2.8.93"}}
>>    :main-opts ["-m" "shadow.cljs.devtools.cli" "release" "build"] }
>>   :run
>>   {:main-opts ["-m" "mypages.server"]}
>>   :build
>>   {:main-opts ["-m" "mypages.static"]}}}
>>
>> shadow-cljs.edn
>>
>> ;; shadow-cljs configuration
>> {:source-paths
>>  ["src/cljs"]
>>
>>  :dependencies []
>>
>>  :builds
>>  {:build     {:target     :browser
>>               :output-dir "resources/public/js/"
>>               :asset-path "/public//js/"
>>               :modules    {:main {:init-fn mypages.helpers/init}}
>>               :dev        {:devtools        {:repl-pprint true}}
>>               :devtools   {:console-support false}}}}
>>
>> some standard ring code for development web server:
>>
>> src/clj/mypages/server.clj
>>
>> (ns mypages.server
>>   (:require [ring.adapter.jetty :refer [run-jetty]]
>>             [ring.middleware.reload :refer [wrap-reload]]
>>             [taoensso.timbre :as log]
>>             [mypages.pages.web :refer [dev-app prod-app]]))
>>
>> (defonce server (atom nil))
>>
>> (defn start-server! [& [port mode]]
>>   (log/debug "Mode: " mode)
>>   (reset! server
>>           (run-jetty
>>            (case mode
>>              "dev" (wrap-reload #'dev-app)
>>              "prod" (wrap-reload #'prod-app)
>>              (wrap-reload #'dev-app))
>>            {:port (if port (Integer/parseInt port) 8080)
>>             :join? false})))
>>
>> (defn stop-server! []
>>   (when @server
>>     (.stop @server)
>>     (reset! server nil)))
>>
>> (def -main start-server!)
>>
>> stasis needs some code to help generate the markup, and we use optimus to 
>> tidy up, optimise and serve assets. I only serve some css out of the 
>> resources/public dir, but you could dump some html in there is you wanted 
>> to. This is in src/clj/mypages/pages/web.clj
>>
>> (ns mypages.pages.web
>>   (:require [stasis.core :as stasis]
>>             [optimus.assets :as assets]
>>             [optimus.optimizations :as optimizations]
>>             [optimus.prime :as optimus]
>>             [optimus.strategies :refer [serve-live-assets]]
>>             [mypages.pages.layout :as layout]))
>>
>> (defn home-page [request]
>>   (layout/landing-page request))
>>
>> (defn get-assets []
>>   (assets/load-assets "public" [#".*\.(jpg|svg|png|js)$"]))
>>
>> (defn get-public []
>>   (merge (stasis/slurp-directory "resources/public" #".*\.(html|css)$" 
>> :encoding "UTF-8")
>>          {"/" home-page}))
>>
>> (defn get-dev []
>>   (merge (get-public)
>>          {"/signup/" layout/redirect}))
>>
>> (defn create-app [f]
>>   (optimus/wrap
>>    (stasis/serve-pages f)
>>    get-assets
>>    optimizations/all
>>    serve-live-assets))
>>
>> (def dev-app
>>   (create-app get-dev))
>>
>> (def prod-app
>>   (create-app get-public))
>>
>> I have some template like functions that allow me to wrap the content 
>> (which I could possibly write in Markdown later e.g. blog posts) in 
>> src/clj/mypages/pages/layout.clj:
>>
>> (ns mypages.pages.layout
>>   (:require [hiccup.page :refer [html5]]
>>             [stasis.core :as stasis]))
>>
>> (defn redirect [request]
>>   (html5
>>    [:head
>>     [:meta {:http-equiv "refresh" :content "0; URL='
>> https://server.com/auth/signup'"}]]))
>>
>> (defn landing-page [request content]
>>   (html5
>>    [:head
>>     [:meta {:charset "utf-8"}]
>>     [:meta {:name    "viewport"
>>             :content "width=device-width, initial-scale=1.0"}]
>>     [:title "MyPages"]
>>     [:link {:rel "stylesheet" :href "
>> https://cdn.jsdelivr.net/npm/bulma@0.8.2/css/bulma.min.css"}]
>>     [:link {:rel "stylesheet" :href "/css/styles.css"}]
>>     [:script {:type "text/javascript" :src "/js/main.js"}]
>>     [:script {:defer true :src "
>> https://use.fontawesome.com/releases/v5.3.1/js/all.js"}]]
>>    [:body [:p content]])
>>
>> Then some code to generate the static pages when I want them in 
>> src/clj/mypages/static.clj
>>
>> (ns mypages.static
>>   (:require
>>    [stasis.core :as stasis]
>>    [optimus.export]
>>    [optimus.optimizations :as optimizations]
>>    [mypages.pages.web :as web]))
>>
>> (def export-dir "static")
>>
>> (defn export! []
>>   (let [assets (optimizations/all (web/get-assets) {})]
>>     (stasis/empty-directory! export-dir)
>>     (optimus.export/save-assets assets export-dir)
>>     (stasis/export-pages (web/get-public) export-dir {:optimus-assets 
>> assets})))
>>
>> (def -main export!)
>>
>> Finally I have my Clojurescript in src/cljs/mypages/helpers.cljs
>>
>> (ns mypages.helpers)
>>
>> (defn ^:export somefunc []
>>   (js/alert "Not available yet .... sorry"))
>>
>> (defn ^:export init []
>>   (js/alert "All ready now"))
>>
>> To build the Clojurescript you can use either of:
>>
>> npx shadow-cljs release build
>>
>> or
>>
>> clojure -A:cljs
>>
>>
>> To work on the static pages, use:
>>
>> clojure -A:run
>>
>> This will reload when you change them.
>>
>> If you are making changes to the cljs regularly there is probably a neat 
>> of using the shadow-cljs dev web server and doing some sort of reload, but 
>> I haven't needed that yet, so have not done this. If anyone does, then 
>> please post up how.
>>
>> I add pages and required clojurescript and once this is ready I build the 
>> static site by first building the Clojurescript (as above), then build the 
>> static pages:
>>
>> clojure -A:build
>>
>> I then package it all up into a Docker with nginx serving the site. I use 
>> a Makefile in the CI to do this.
>>
>> The setup is fairly simple and could do with some refinement (hot reload 
>> of js would be next). I like that it gets me to something working quickly 
>> and it would be easy to being in something like Reagent if a few React 
>> components are needed. I really wanted something that was small and 
>> generated fast loading sites. I use re-frame for SPAs, but for some work 
>> this is overkill and this setup is better. I hope that this is of use, 
>> please ask any questions.
>>
>> Regards
>> Jag
>>
>>
>> On Wednesday, 29 April 2020 19:37:45 UTC+1, Blake Miller wrote:
>>>
>>> Jag,
>>>
>>> I think what you described is worth sharing. I like the simplicity of 
>>> that approach and the efficiency of the final artifact.
>>>
>>> -Blake
>>>
>>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/b40e6328-6766-49b6-b176-48b43a453c38%40googlegroups.com.

Reply via email to