lein-figwheel
lein-figwheel copied to clipboard
Figwheel + Electron problem
I've been trying to get Electron to work with Figwheel. This is probably not a bug with Figwheel, but I need help nonetheless.
My understanding is that Electron is like a Node.js environment, and :target :nodejs
is needed to get it working.
I have the following project.clj
:
(defproject typestack "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.671"]
[reagent "0.7.0"]]
:plugins [[lein-figwheel "0.5.10"]
[lein-cljsbuild "1.1.6"]]
:clean-targets [:target-path "out"]
:cljsbuild {:builds [{:id "dev"
:source-paths ["src"]
:figwheel true
:compiler {:main "typestack.core"
:target :nodejs
:optimizations :none
:source-map true }}]}
:figwheel {})
And small ClojureScript file (which is based on the Electron Quick Start example):
(ns typestack.core
(:require [cljs.nodejs :as nodejs]))
(def Electron (nodejs/require "electron"))
(def app (.-app Electron))
(def BrowserWindow (.-BrowserWindow Electron))
(def path (nodejs/require "path"))
(def url (nodejs/require "url"))
(def dirname (js* "__dirname"))
(def win (atom nil))
(defn create-window []
(reset! win (BrowserWindow. (clj->js {:width 800 :height 600})))
(.loadURL @win "file:///home/oskar/typestack/index.html")
(.openDevTools (.-webContents @win))
(.on app "closed" (fn [] (reset! win nil))))
(defn -main []
(.on app "ready" (fn [] (create-window)))
(.on app "window-all-closed"
(fn [] (.quit app)))
(.on app "activate"
(fn [] (create-window))))
(nodejs/enable-util-print!)
(.log js/console "App has started!")
(set! *main-cli-fn* -main)
When I start lein figwheel dev
it compiles my code then says:
Prompt will show when Figwheel connects to your application
If I start electron .
it says:
App has started!
Figwheel: trying to open cljs reload socket
But then nothing. And the REPL doesn't show up in the lein figwheel dev
console. I'm stuck and don't know what to do to get it working.
did you $npm install ws
? also FYI we are waiting on the next cljs release for fw to work correctly with node
Also if you start the runtime from a location other than your clojure project, you need to make sure that your compilation target output folder is where the runtime expects it to be.
Yes, I did install ws. I think I have the target output folder correctly set. The Electron app starts, it's just that figwheel does not connect properly.
also FYI we are waiting on the next cljs release for fw to work correctly with node
Oh? Ok...
The fix we are waiting on should not affect fw connecting.
Are there any errors in the devtools console?
@pkpkpk No.
By the way, I think I misspoke previously. The problem seems to be that a REPL server (right?) can't be opened in Electron, not that fw can't connect. I'm new to ClojureScript and messing about with REPLs.
I am not sure what you mean. Can you manually require ws from the javascript console?
It is possible there is another regression going on here besides the one already known. Give [org.clojure/clojurescript "1.9.293"]
a try. That was the last cljs version before all the npm changes, and is known to work with electron+fw
I am not sure what you mean.
That's OK. I'm not sure I know what I mean either. I'm new to ClojureScript and don't really know much about ClojureScript REPLs.
Can you manually require ws from the javascript console?
Yes. require('ws') => class WebSocket extends EventEmitter { ...
I tried CLJS 1.9.293 and the still the same problem.
So I just looked at my build and I don't use ws, so thats not the problem.
Does global.figwheel.client.utils.html_or_react_native_env_QMARK_()
should return true.
What does global.figwheel.client.socket.socket_atom.state.readyState
return?
In the JavaScript console? global.figwheel
is undefined.
I just noticed something.
In my code:
(defn -main []
(.on app "ready" (fn []
(println "hello") ;; <- this line
(create-window)))
(.on app "window-all-closed"
(fn [] (.quit app)))
(.on app "activate"
(fn [] (create-window))))
If I add the line (println "hello")
above (marked "<- this line") then it starts working. If I remove it it stops working.
Here is the output without and with the println
~/typestack » electron .
App has started!
Figwheel: trying to open cljs reload socket
------------------------------------------------------------
~/typestack » electron .
App has started!
Figwheel: trying to open cljs reload socket
hello
Figwheel: socket connection established
------------------------------------------------------------
And the lein figwheel
terminal doesn't show the REPL prompt until electron .
says "connection established". I'm sure, tested it like 10 times.
By the way, can I connect to the REPL with Emacs/CIDER somehow?
So its working then? phew. This looks familiar but the reason escapes me atm
Side note, you should consider moving all your electron startup boilerplate into a static .js file and then requiring your main cljs file inside the activation function or elsewhere. This will let you cycle builds without throwing away the runtime.
So its working then?
Yeah, but it seems frail. :)
Side note, you should consider moving all your electron startup boilerplate into a static .js file and then requiring your main cljs file inside the activation function or elsewhere. This will let you cycle builds without throwing away the runtime.
Thanks for the tip! I gotta learn more about Electron now.
Thanks for your time!
By the way, can I connect to the REPL with Emacs/CIDER somehow?
There's no reason why the standard docs wouldnt apply. Slack is the right place to ask about that if you need help
@pkpkpk By the way, I now realize that I don't understand exactly what you mean about moving the startup boilerplate into a static .js file. I hope it's OK to ask a few questions about that.
Why would the runtime (I assume you mean like, state?) get thrown away just because I reload the boilerplate? By boilerplate I assume you mean the callback that creates the initial window, etc., basically my code above. The window that was created doesn't get recreated just because I reload that file, right? And wouldn't it be the rest of the code that contains the interesting state anyway? And I will be reloading that.
And about requiring my main file inside the activation function: If I write my boilerplate in ClojureScript, and then copy the JS output to some other file to avoid reloading, can't I require the rest of the code in the ns
form?
As you can see, I'm a bit confused by the this whole thing, being new to Electron and somewhat new to ClojureScript too. :)