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.