├── demo.gif
├── resources
├── cljs-externs
│ └── common.js
└── public
│ ├── css
│ └── main.css
│ ├── img
│ ├── electron-logo.png
│ ├── reagent-logo.png
│ └── cljs-logo.svg
│ └── index.html
├── package.json
├── .gitignore
├── Procfile
├── dev_src
└── dev
│ └── core.cljs
├── src
└── tools
│ └── figwheel_middleware.clj
├── .github
└── workflows
│ └── main.yml
├── LICENSE.md
├── electron_src
└── electron
│ └── core.cljs
├── README.md
├── ui_src
└── ui
│ └── core.cljs
└── project.clj
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gonzih/cljs-electron/HEAD/demo.gif
--------------------------------------------------------------------------------
/resources/cljs-externs/common.js:
--------------------------------------------------------------------------------
1 | // Fix warning for the latest CLJS
2 | var goog;
3 |
--------------------------------------------------------------------------------
/resources/public/css/main.css:
--------------------------------------------------------------------------------
1 | .logos img {
2 | width: 100px;
3 | margin-left: 5px;
4 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello-world",
3 | "version": "0.1.0",
4 | "main": "resources/main.js"
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | resources/public/js/
3 | resources/main.js
4 | *-init.clj
5 | figwheel_server.log
6 | .nrepl-port
--------------------------------------------------------------------------------
/resources/public/img/electron-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gonzih/cljs-electron/HEAD/resources/public/img/electron-logo.png
--------------------------------------------------------------------------------
/resources/public/img/reagent-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gonzih/cljs-electron/HEAD/resources/public/img/reagent-logo.png
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | electron: env LEIN_FAST_TRAMPOLINE=y lein trampoline cljsbuild auto electron-dev
2 | ui: env LEIN_FAST_TRAMPOLINE=y lein trampoline figwheel frontend-dev
3 |
--------------------------------------------------------------------------------
/dev_src/dev/core.cljs:
--------------------------------------------------------------------------------
1 | (ns dev.core
2 | (:require [figwheel.client :as fw :include-macros true]
3 | [ui.core]))
4 |
5 | (fw/watch-and-reload
6 | :websocket-url "ws://localhost:3449/figwheel-ws"
7 | :jsload-callback (fn [] (print "reloaded")))
8 |
--------------------------------------------------------------------------------
/src/tools/figwheel_middleware.clj:
--------------------------------------------------------------------------------
1 | (ns tools.figwheel-middleware
2 | (:require [ring.middleware.resource :refer (wrap-resource)]))
3 |
4 | (defn handler [request]
5 | {:status 404
6 | :headers {"Content-Type" "text/html"}
7 | :body (str "Cannot find:" (:uri request))})
8 |
9 | (def app
10 | ;; static resources in resources/public
11 | (wrap-resource handler "public"))
12 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | container:
9 | image: clojure:latest
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Build
13 | run: lein do clean, cljsbuild once electron-dev, cljsbuild once frontend-dev, clean, cljsbuild once electron-release, cljsbuild once frontend-release
14 | env:
15 | JVM_OPTS: -Xmx3200m
16 |
--------------------------------------------------------------------------------
/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello World!
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright © `2015-2017` `Max Gonzih gonzih @ gmail.com`
5 |
6 | Permission is hereby granted, free of charge, to any person
7 | obtaining a copy of this software and associated documentation
8 | files (the “Software”), to deal in the Software without
9 | restriction, including without limitation the rights to use,
10 | copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the
12 | Software is furnished to do so, subject to the following
13 | conditions:
14 |
15 | The above copyright notice and this permission notice shall be
16 | included in all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | OTHER DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/electron_src/electron/core.cljs:
--------------------------------------------------------------------------------
1 | (ns electron.core)
2 |
3 | (def electron (js/require "electron"))
4 | (def app (.-app electron))
5 | (def browser-window (.-BrowserWindow electron))
6 | (def crash-reporter (.-crashReporter electron))
7 |
8 | (def main-window (atom nil))
9 |
10 | (defn init-browser []
11 | (reset! main-window (browser-window.
12 | (clj->js {:width 800
13 | :height 600
14 | :webPreferences {:nodeIntegration true}})))
15 | ; Path is relative to the compiled js file (main.js in our case)
16 | (.loadURL ^js/electron.BrowserWindow @main-window (str "file://" js/__dirname "/public/index.html"))
17 | (.on ^js/electron.BrowserWindow @main-window "closed" #(reset! main-window nil)))
18 |
19 | ; CrashReporter can just be omitted
20 | (.start crash-reporter
21 | (clj->js
22 | {:companyName "MyAwesomeCompany"
23 | :productName "MyAwesomeApp"
24 | :submitURL "https://example.com/submit-url"
25 | :autoSubmit false}))
26 |
27 | (.on app "window-all-closed" #(when-not (= js/process.platform "darwin")
28 | (.quit app)))
29 | (.on app "ready" init-browser)
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/Gonzih/cljs-electron/blob/master/LICENSE.md)
2 | 
3 |
4 | # Clojurified Electron
5 |
6 | 
7 |
8 | My attempt to recreate ClojureScript development workflow while developing desktop apps with [electron](http://electron.atom.io/).
9 |
10 | ## What is currently included
11 |
12 | * ClojureScript (init script and ui code)
13 | * Figwheel for interactive development
14 | * Reagent for UI
15 | * Advanced compilation with externs inference in release compilation targets
16 |
17 | ## Running it
18 |
19 | ```shell
20 | npm install electron -g # install electron binaries
21 |
22 | ```
23 |
24 | ### Terminal
25 | ```shell
26 | lein cooper # compile cljs and start figwheel
27 | electron . # start electron from another terminal
28 | ```
29 |
30 | ### Emacs REPL
31 | ```shell
32 | lein cljsbuild once
33 | ```
34 |
35 | M-x cider-jack-in-cljs
36 | figwheel
37 |
38 | ```shell
39 | electron .
40 | ```
41 |
42 | ## Releasing
43 |
44 | ```shell
45 | lein do clean, cljsbuild once frontend-release, cljsbuild once electron-release
46 | electron . # start electron to test that everything works
47 | ```
48 |
49 | After that you can follow [distribution guide for the electron.](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md)
50 |
51 | The easiest way to package an electron app is by using [electron-packager](https://github.com/maxogden/electron-packager):
52 |
53 | ```shell
54 | npm install electron-packager -g # install electron packager
55 | electron-packager . HelloWorld --platform=darwin --arch=x64 --electron-version=1.4.8 # package it!
56 | ```
57 |
--------------------------------------------------------------------------------
/ui_src/ui/core.cljs:
--------------------------------------------------------------------------------
1 | (ns ui.core
2 | (:require [reagent.core :as reagent :refer [atom]]
3 | [clojure.string :as string :refer [split-lines]]))
4 |
5 | (def join-lines (partial string/join "\n"))
6 |
7 | (enable-console-print!)
8 |
9 | (defonce state (atom 0))
10 | (defonce shell-result (atom ""))
11 | (defonce command (atom ""))
12 |
13 | (defonce proc (js/require "child_process"))
14 |
15 | (defn append-to-out [out]
16 | (swap! shell-result str out))
17 |
18 | (defn run-process []
19 | (when-not (empty? @command)
20 | (println "Running command" @command)
21 | (let [[cmd & args] (string/split @command #"\s")
22 | js-args (clj->js (or args []))
23 | p (.spawn proc cmd js-args)]
24 | (.on p "error" (comp append-to-out
25 | #(str % "\n")))
26 | (.on (.-stderr p) "data" append-to-out)
27 | (.on (.-stdout p) "data" append-to-out))
28 | (reset! command "")))
29 |
30 | (defn root-component []
31 | [:div
32 | [:div.logos
33 | [:img.electron {:src "img/electron-logo.png"}]
34 | [:img.cljs {:src "img/cljs-logo.svg"}]
35 | [:img.reagent {:src "img/reagent-logo.png"}]]
36 | [:pre "Versions:"
37 | [:p (str "Node " js/process.version)]
38 | [:p (str "Electron " ((js->clj js/process.versions) "electron"))]
39 | [:p (str "Chromium " ((js->clj js/process.versions) "chrome"))]]
40 | [:button
41 | {:on-click #(swap! state inc)}
42 | (str "Clicked " @state " times")]
43 | [:p
44 | [:form
45 | {:on-submit (fn [^js/Event e]
46 | (.preventDefault e)
47 | (run-process))}
48 | [:input#command
49 | {:type :text
50 | :on-change (fn [^js/Event e]
51 | (reset! command
52 | ^js/String (.-value (.-target e))))
53 | :value @command
54 | :placeholder "type in shell command"}]]]
55 | [:pre (join-lines (take 100 (reverse (split-lines @shell-result))))]])
56 |
57 | (reagent/render
58 | [root-component]
59 | (js/document.getElementById "app-container"))
60 |
--------------------------------------------------------------------------------
/resources/public/img/cljs-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
28 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject clj-electron "0.1.0-SNAPSHOT"
2 | :license {:name "The MIT License"
3 | :url "https://opensource.org/licenses/MIT"}
4 | :source-paths ["src"]
5 | :description "A hello world application for electron"
6 | :dependencies [[org.clojure/clojure "1.10.0"]
7 | [org.clojure/clojurescript "1.10.520"]
8 | [figwheel "0.5.19"]
9 | [figwheel-sidecar "0.5.19"]
10 | [cider/piggieback "0.4.0"]
11 | [reagent "0.8.1"]
12 | [ring/ring-core "1.7.1"]]
13 | :plugins [[lein-cljsbuild "1.1.7"]
14 | [lein-figwheel "0.5.19"]
15 | [lein-cooper "1.2.2"]]
16 |
17 | :clean-targets ^{:protect false} ["resources/main.js"
18 | "resources/public/js/ui-core.js"
19 | "resources/public/js/ui-core.js.map"
20 | "resources/public/js/ui-out"]
21 | :cljsbuild
22 | {:builds
23 | [{:source-paths ["electron_src"]
24 | :id "electron-dev"
25 | :compiler {:output-to "resources/main.js"
26 | :output-dir "resources/public/js/electron-dev"
27 | :optimizations :simple
28 | :pretty-print true
29 | :cache-analysis true}}
30 | {:source-paths ["ui_src" "dev_src"]
31 | :id "frontend-dev"
32 | :compiler {:output-to "resources/public/js/ui-core.js"
33 | :output-dir "resources/public/js/ui-out"
34 | :source-map true
35 | :asset-path "js/ui-out"
36 | :optimizations :none
37 | :cache-analysis true
38 | :main "dev.core"}}
39 | {:source-paths ["electron_src"]
40 | :id "electron-release"
41 | :compiler {:output-to "resources/main.js"
42 | :output-dir "resources/public/js/electron-release"
43 | :externs ["cljs-externs/common.js"]
44 | :optimizations :advanced
45 | :cache-analysis true
46 | :infer-externs true}}
47 | {:source-paths ["ui_src"]
48 | :id "frontend-release"
49 | :compiler {:output-to "resources/public/js/ui-core.js"
50 | :output-dir "resources/public/js/ui-release-out"
51 | :source-map "resources/public/js/ui-core.js.map"
52 | :externs ["cljs-externs/common.js"]
53 | :optimizations :advanced
54 | :cache-analysis true
55 | :infer-externs true
56 | :process-shim false
57 | :main "ui.core"}}]}
58 | :figwheel {:http-server-root "public"
59 | :css-dirs ["resources/public/css"]
60 | :ring-handler tools.figwheel-middleware/app
61 | :server-port 3449})
62 |
--------------------------------------------------------------------------------