├── env
├── prod
│ └── cljs
│ │ └── football
│ │ └── prod.cljs
└── dev
│ └── cljs
│ └── football
│ └── dev.cljs
├── public
├── index.html
└── css
│ └── index.css
├── README.md
├── src
└── football
│ ├── data.cljs
│ └── core.cljs
└── project.clj
/env/prod/cljs/football/prod.cljs:
--------------------------------------------------------------------------------
1 | (ns football.prod
2 | (:require [football.core :as core]))
3 |
4 | ;;ignore println statements in prod
5 | (set! *print-fn* (fn [& _]))
6 |
7 | (core/init!)
8 |
--------------------------------------------------------------------------------
/env/dev/cljs/football/dev.cljs:
--------------------------------------------------------------------------------
1 | (ns ^:figwheel-no-load football.dev
2 | (:require [football.core :as core]
3 | [figwheel.client :as figwheel :include-macros true]))
4 |
5 | (enable-console-print!)
6 |
7 | (figwheel/watch-and-reload
8 | :websocket-url "ws://localhost:3449/figwheel-ws"
9 | :jsload-callback core/mount-root)
10 |
11 | (core/init!)
12 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a version of the [VueReactPerf](https://github.com/footballradar/VueReactPerf) benchmark implemented using [Reagent](http://reagent-project.github.io/). The original benchmark is discussed [here](https://engineering.footballradar.com/a-fairer-vue-of-react-comparing-react-to-vue-for-dynamic-tabular-data-part-2/?utm_content=buffer0e901).
2 |
3 | Prerequisites:
4 |
5 | * [JDK](http://www.azul.com/downloads/zulu/)
6 | * [Leiningen](https://leiningen.org/)
7 |
8 | To build the benchmark in development mode run:
9 |
10 | lein figwheel
11 |
12 | To build the optimized version for release run:
13 |
14 | lein release
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/public/css/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: "Devanagari Sangam MN"
3 | }
4 |
5 | table {
6 | border-spacing: 0;
7 | border-collapse: collapse;
8 | }
9 |
10 | tr {
11 | border-bottom: 1px solid #e0e0e0;
12 | padding: 5px;
13 | }
14 |
15 | td, th {
16 | padding: 0;
17 | height: 100%;
18 | white-space: nowrap;
19 | }
20 |
21 | .cell--teams {
22 | padding-left:25px
23 | }
24 |
25 |
26 | .cards {
27 | display: flex;
28 | justify-content: center;
29 | }
30 |
31 | .cards__card {
32 | padding: 5px;
33 | }
34 |
35 | .cards__card--yellow {
36 | background-color: #fff68f;
37 | }
38 |
39 | .cards__card--red {
40 | background-color: #f44343
41 | }
42 |
43 | .player {
44 | display: flex;
45 | justify-content: space-between;
46 | }
47 |
48 | .player__name {
49 | padding: 0 0 0 5px;
50 | margin: 0;
51 | display: flex;
52 | flex-direction: column;
53 | }
54 |
55 | .player__effort {
56 | width: 20px;
57 | }
58 |
59 | .player__effort--low {
60 | background-color: #f77b7b;
61 | }
62 |
63 | .player__effort--high {
64 | background-color: #49B687;
65 | }
66 |
67 | .u-center {
68 | text-align: center;
69 | }
70 |
71 | .u-small {
72 | font-size: 10px;
73 | }
74 |
--------------------------------------------------------------------------------
/src/football/data.cljs:
--------------------------------------------------------------------------------
1 | (ns football.data
2 | (:require [reagent.core :as reagent]))
3 |
4 | (defonce games (reagent/atom nil))
5 |
6 | (defn generate-fake-player []
7 | {:name (-> js/faker .-name (.findName))
8 | :effort-level (rand-int 10)
9 | :invited-next-week? (> (rand) 0.5)})
10 |
11 | (defn generate-fake-game []
12 | {:id (-> js/faker .-random (.uuid))
13 | :clock 0
14 | :score {:home 0 :away 0}
15 | :teams {:home (-> js/faker .-address (.city))
16 | :away (-> js/faker .-address (.city))}
17 | :outrageous-tackles 0
18 | :cards {:yellow 0 :red 0}
19 | :players (mapv generate-fake-player (range 4))})
20 |
21 | (defn generate-games [game-count]
22 | (reset! games (mapv generate-fake-game (range game-count))))
23 |
24 | (defn maybe-update [game prob path f]
25 | (if (< (rand-int 100) prob)
26 | (update-in game path f)
27 | game))
28 |
29 | (defn update-rand-player [game idx]
30 | (-> game
31 | (assoc-in [:players idx :effort-level] (rand-int 10))
32 | (assoc-in [:players idx :invited-next-week?] (> (rand) 0.5))))
33 |
34 | (defn update-game [game]
35 | (-> game
36 | (update :clock inc)
37 | (maybe-update 5 [:score :home] inc)
38 | (maybe-update 5 [:score :away] inc)
39 | (maybe-update 8 [:cards :yellow] inc)
40 | (maybe-update 2 [:cards :red] inc)
41 | (maybe-update 10 [:outrageous-tackles] inc)
42 | (update-rand-player (rand-int 4))))
43 |
44 | (defn update-game-at-interval [interval idx]
45 | (swap! games update idx update-game)
46 | (js/setTimeout update-game-at-interval interval interval idx))
47 |
48 | (def event-interval 1000)
49 |
50 | (defn update-games [game-count]
51 | (dotimes [i game-count]
52 | (swap! games update i update-game)
53 | (js/setTimeout #(update-game-at-interval event-interval i)
54 | (* i event-interval))))
55 |
--------------------------------------------------------------------------------
/src/football/core.cljs:
--------------------------------------------------------------------------------
1 | (ns football.core
2 | (:require
3 | [football.data :as data]
4 | [reagent.core :as reagent]))
5 |
6 | (defn player-component [{:keys [name invited-next-week? effort-level]}]
7 | [:td
8 | [:div.player
9 | [:p.player__name
10 | [:span name]
11 | [:span.u-small (if invited-next-week? "Doing well" "Not coming again")]]
12 | [:div {:class-name (str "player__effort "
13 | (if (< effort-level 5)
14 | "player__effort--low"
15 | "player__effort--high"))}]]])
16 |
17 | (defn game-component [game]
18 | [:tr
19 | [:td.u-center (:clock game)]
20 | [:td.u-center (-> game :score :home) "-" (-> game :score :away)]
21 | [:td.cell--teams (-> game :teams :home) "-" (-> game :teams :away)]
22 | [:td.u-center (:outrageous-tackles game)]
23 | [:td
24 | [:div.cards
25 | [:div.cards__card.cards__card--yellow (-> game :cards :yellow)]
26 | [:div.cards__card.cards__card--red (-> game :cards :red)]]]
27 | (for [player (:players game)]
28 | ^{:key player}
29 | [player-component player])])
30 |
31 | (defn games-component []
32 | [:tbody
33 | (for [game @data/games]
34 | ^{:key game}
35 | [game-component game])])
36 |
37 | (defn games-table-component []
38 | [:table
39 | [:thead
40 | [:tr
41 | [:th {:width "50px"} "Clock"]
42 | [:th {:width "50px"} "Score"]
43 | [:th {:width "200px"} "Teams"]
44 | [:th "Outrageous Tackles"]
45 | [:th {:width "100px"} "Cards"]
46 | [:th {:width "100px"} "Players"]
47 | [:th {:width "100px"} ""]
48 | [:th {:width "100px"} ""]
49 | [:th {:width "100px"} ""]
50 | [:th {:width "100px"} ""]]]
51 | [games-component]])
52 |
53 | (defn home-page []
54 | [games-table-component])
55 |
56 | (defn mount-root []
57 | (reagent/render [home-page] (.getElementById js/document "app")))
58 |
59 | (def game-count 50)
60 |
61 | (defn init! []
62 | (data/generate-games game-count)
63 | (data/update-games game-count)
64 | (mount-root))
65 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject football "0.1.0-SNAPSHOT"
2 | :description "FIXME: write description"
3 | :url "http://example.com/FIXME"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :dependencies [[org.clojure/clojure "1.8.0" :scope "provided"]
8 | [org.clojure/clojurescript "1.9.495" :scope "provided"]
9 | [reagent "0.6.1"]]
10 |
11 | :plugins [[lein-cljsbuild "1.1.5"]
12 | [lein-figwheel "0.5.9"]]
13 |
14 | :min-lein-version "2.5.0"
15 |
16 | :clean-targets ^{:protect false}
17 | [:target-path
18 | [:cljsbuild :builds :app :compiler :output-dir]
19 | [:cljsbuild :builds :app :compiler :output-to]]
20 |
21 | :resource-paths ["public"]
22 |
23 | :figwheel {:http-server-root "."
24 | :nrepl-port 7002
25 | :nrepl-middleware ["cemerick.piggieback/wrap-cljs-repl"]
26 | :css-dirs ["public/css"]}
27 |
28 | :cljsbuild {:builds {:app
29 | {:source-paths ["src" "env/dev/cljs"]
30 | :compiler
31 | {:main "football.dev"
32 | :output-to "public/js/app.js"
33 | :output-dir "public/js/out"
34 | :asset-path "js/out"
35 | :source-map true
36 | :optimizations :none
37 | :pretty-print true}
38 | :figwheel
39 | {:open-urls ["http://localhost:3449/index.html"]}}
40 | :release
41 | {:source-paths ["src" "env/prod/cljs"]
42 | :compiler
43 | {:output-to "public/js/app.js"
44 | :output-dir "public/js/release"
45 | :externs ["public/vendor/js/faker.min.js"]
46 | :closure-warnings
47 | {:externs-validation :off :non-standard-jsdoc :off}
48 | :asset-path "js/out"
49 | :optimizations :advanced
50 | :pretty-print false}}}}
51 |
52 | :aliases {"release" ["do" "clean" ["cljsbuild" "once" "release"]]}
53 |
54 | :profiles {:dev {:dependencies [[figwheel-sidecar "0.5.9"]
55 | [org.clojure/tools.nrepl "0.2.12"]
56 | [com.cemerick/piggieback "0.2.2-SNAPSHOT"]]}})
57 |
--------------------------------------------------------------------------------