Separate prerender code using dom-server and browser JS code

Requiring react-dom-server with React 15.4 in browser code would increase
filesize by about 100KB. This change separates the pre-render code to
a different file which is only used by a separate Lein profile.
This commit is contained in:
Juho Teperi 2017-03-11 00:36:23 +02:00
parent 4c568256f2
commit 8ff70c7eb9
7 changed files with 115 additions and 86 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ reagent.iml
outsite/bundle.js outsite/bundle.js
outsite/bundle.min.js outsite/bundle.min.js
node_modules node_modules
pre-render

View File

@ -70,16 +70,25 @@ push-gh-pages: build-gh-pages
git push origin gh-pages:gh-pages git push origin gh-pages:gh-pages
# build site and push to reagent-project's doc site # build site and push to reagent-project's doc site
push-project-docs: build-gh-pages push-project-docs: gen-site
git push --force \ # sanity check
https://github.com/reagent-project/reagent-project.github.io.git \ test -f $(SITEDIR)/index.html
gh-pages:master test ! -e $(OUTPUTDIR)
rm -fr tmp
git clone git@github.com:reagent-project/reagent-project.github.io.git tmp
rm -fr tmp/*
cp -r $(SITEDIR)/* tmp/
cd tmp && \
git add . && git commit -m "Updated" && \
git push
rm -rf tmp
# build site into a gh-pages branch # build site into a gh-pages branch
build-gh-pages: gen-site gh-pages-add build-gh-pages: gen-site gh-pages-add
gen-site: clean gen-site: clean
lein with-profile prod cljsbuild once lein with-profile prod cljsbuild once
lein with-profile prerender cljsbuild once
# copy contents of $(SITEDIR) to branch gh-pages # copy contents of $(SITEDIR) to branch gh-pages
gh-pages-add: gh-pages-add:

View File

@ -1,8 +1,8 @@
var cljsLoad = require("./cljs-load"); var cljsLoad = require("./cljs-load");
var srcFile = "outsite/public/js/main.js"; var srcFile = "pre-render/main.js";
var outputDirectory = "outsite/public/js/out/"; var outputDirectory = "pre-render/out/";
var devFile = "reagenttest/runtests.js"; var devFile = "reagenttest/runtests.js";
var beep = "\u0007"; var beep = "\u0007";
@ -15,7 +15,7 @@ if (typeof location === "undefined") {
var gensite = function () { var gensite = function () {
console.log("Loading " + srcFile); console.log("Loading " + srcFile);
var optNone = cljsLoad.load(srcFile, outputDirectory, devFile); var optNone = cljsLoad.load(srcFile, outputDirectory, devFile);
sitetools.core.genpages({"opt-none": optNone}); sitetools.server.genpages({"opt-none": optNone});
} }
var compileFail = function () { var compileFail = function () {

View File

@ -0,0 +1,4 @@
(ns reagentdemo.server
"Used to pre-render HTML files."
(:require [reagentdemo.core]
[sitetools.server]))

View File

@ -2,7 +2,6 @@
(:require [clojure.string :as string] (:require [clojure.string :as string]
[goog.events :as evt] [goog.events :as evt]
[reagent.core :as r] [reagent.core :as r]
[reagent.dom.server :as server]
[reagent.debug :refer-macros [dbg log dev?]] [reagent.debug :refer-macros [dbg log dev?]]
[reagent.interop :as i :refer-macros [$ $!]]) [reagent.interop :as i :refer-macros [$ $!]])
(:import goog.History (:import goog.History
@ -103,81 +102,8 @@
(defn main-content [] (defn main-content []
(get-in @config [:current-page :content])) (get-in @config [:current-page :content]))
;;; Static site generation
(defn base [page]
(let [depth (->> page to-relative (re-seq #"/") count)]
(->> "../" (repeat depth) (apply str))))
(defn danger [t s]
[t {:dangerouslySetInnerHTML {:__html s}}])
(defn html-template [{:keys [title body-html timestamp page-conf
js-file css-file main-div]}]
(let [main (str js-file timestamp)]
(server/render-to-static-markup
[:html
[:head
[:meta {:charset 'utf-8}]
[:meta {:name 'viewport
:content "width=device-width, initial-scale=1.0"}]
[:base {:href (-> page-conf :page-path base)}]
[:link {:href (str css-file timestamp) :rel 'stylesheet}]
[:title title]]
[:body
[:div {:id main-div} (danger :div body-html)]
(danger :script (str "var pageConfig = "
(-> page-conf clj->js js/JSON.stringify)))
[:script {:src main :type "text/javascript"}]]])))
(defn gen-page [page-path conf]
(emit [:set-page page-path])
(let [conf (merge conf @config)
b (:body conf)
bhtml (server/render-to-string b)]
(str "<!doctype html>\n"
(html-template (assoc conf
:page-conf {:page-path page-path}
:body-html bhtml)))))
(defn fs [] (js/require "fs"))
(defn path [] (js/require "path"))
(defn mkdirs [f]
(doseq [d (reductions #(str %1 "/" %2)
(-> ($ (path) normalize f)
(string/split #"/")))]
(when-not ($ (fs) existsSync d)
($ (fs) mkdirSync d))))
(defn write-file [f content]
(mkdirs ($ (path) dirname f))
($ (fs) writeFileSync f content))
(defn path-join [& paths]
(apply ($ (path) :join) paths))
(defn write-resources [dir {:keys [css-file css-infiles]}]
(write-file (path-join dir css-file)
(->> css-infiles
(map #($ (fs) readFileSync %))
(string/join "\n"))))
;;; Main entry points ;;; Main entry points
(defn ^:export genpages [opts]
(log "Generating site")
(let [conf (swap! config merge (js->clj opts :keywordize-keys true))
conf (assoc conf :timestamp (str "?" (js/Date.now)))
{:keys [site-dir pages]} conf]
(doseq [f (keys pages)]
(write-file (->> f to-relative (path-join site-dir))
(gen-page f conf)))
(write-resources site-dir conf))
(log "Wrote site"))
(defn start! [site-config] (defn start! [site-config]
(swap! config merge site-config) (swap! config merge site-config)
(when r/is-client (when r/is-client

View File

@ -0,0 +1,83 @@
(ns sitetools.server
"Used to pre-render HTML files."
(:require [clojure.string :as string]
[goog.events :as evt]
[reagent.core :as r]
[reagent.dom.server :as server]
[reagent.debug :refer-macros [dbg log dev?]]
[reagent.interop :as i :refer-macros [$ $!]]
[sitetools.core :as tools]))
;;; Static site generation
(defn base [page]
(let [depth (->> page tools/to-relative (re-seq #"/") count)]
(->> "../" (repeat depth) (apply str))))
(defn danger [t s]
[t {:dangerouslySetInnerHTML {:__html s}}])
(defn html-template [{:keys [title body-html timestamp page-conf
js-file css-file main-div]}]
(let [main (str js-file timestamp)]
(server/render-to-static-markup
[:html
[:head
[:meta {:charset 'utf-8}]
[:meta {:name 'viewport
:content "width=device-width, initial-scale=1.0"}]
[:base {:href (-> page-conf :page-path base)}]
[:link {:href (str css-file timestamp) :rel 'stylesheet}]
[:title title]]
[:body
[:div {:id main-div} (danger :div body-html)]
(danger :script (str "var pageConfig = "
(-> page-conf clj->js js/JSON.stringify)))
[:script {:src main :type "text/javascript"}]]])))
(defn gen-page [page-path conf]
(tools/emit [:set-page page-path])
(let [conf (merge conf @tools/config)
b (:body conf)
bhtml (server/render-to-string b)]
(str "<!doctype html>\n"
(html-template (assoc conf
:page-conf {:page-path page-path}
:body-html bhtml)))))
(defn fs [] (js/require "fs"))
(defn path [] (js/require "path"))
(defn mkdirs [f]
(doseq [d (reductions #(str %1 "/" %2)
(-> ($ (path) normalize f)
(string/split #"/")))]
(when-not ($ (fs) existsSync d)
($ (fs) mkdirSync d))))
(defn write-file [f content]
(mkdirs ($ (path) dirname f))
($ (fs) writeFileSync f content))
(defn path-join [& paths]
(apply ($ (path) :join) paths))
(defn write-resources [dir {:keys [css-file css-infiles]}]
(write-file (path-join dir css-file)
(->> css-infiles
(map #($ (fs) readFileSync %))
(string/join "\n"))))
;;; Main entry points
(defn ^:export genpages [opts]
(log "Generating site")
(let [conf (swap! tools/config merge (js->clj opts :keywordize-keys true))
conf (assoc conf :timestamp (str "?" (js/Date.now)))
{:keys [site-dir pages]} conf]
(doseq [f (keys pages)]
(write-file (->> f tools/to-relative (path-join site-dir))
(gen-page f conf)))
(write-resources site-dir conf))
(log "Wrote site"))

View File

@ -37,10 +37,7 @@
:asset-path "js/out"}}}}}] :asset-path "js/out"}}}}}]
:site {:resource-paths ^:replace ["outsite"] :site {:resource-paths ^:replace ["outsite"]
:figwheel {:css-dirs ^:replace ["outsite/public/css"]} :figwheel {:css-dirs ^:replace ["outsite/public/css"]}}
:cljsbuild
{:builds {:client
{:notify-command ["node" "bin/gen-site.js"]}}}}
:prod [:site :prod [:site
{:cljsbuild {:cljsbuild
@ -51,6 +48,14 @@
;; :pseudo-names true ;; :pseudo-names true
:output-dir "target/client"}}}}}] :output-dir "target/client"}}}}}]
:prerender [:prod
{:cljsbuild
{:builds {:client
{:compiler {:main "reagentdemo.server"
:output-to "pre-render/main.js"
:output-dir "pre-render/out"}
:notify-command ["node" "bin/gen-site.js"] }}}}]
:webpack {:cljsbuild :webpack {:cljsbuild
{:builds {:client {:builds {:client
{:compiler {:compiler
@ -74,7 +79,8 @@
"outsite/public/news" "outsite/public/news"
"outsite/public/css" "outsite/public/css"
"outsite/public/index.html" "outsite/public/index.html"
"out"] "out"
"pre-render"]
:cljsbuild {:builds {:client :cljsbuild {:builds {:client
{:source-paths ["src" {:source-paths ["src"