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/50e4e710-0667-4505-b4e4-e39a39fa35d6%40googlegroups.com.

Reply via email to