bhauman / lein-figwheel

Figwheel builds your ClojureScript code and hot loads it into the browser as you are coding!
Eclipse Public License 1.0
2.88k stars 209 forks source link

Figwheel + Electron problem #578

Open oskarkv opened 7 years ago

oskarkv commented 7 years ago

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.

pkpkpk commented 7 years ago

did you $npm install ws? also FYI we are waiting on the next cljs release for fw to work correctly with node

pkpkpk commented 7 years ago

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.

oskarkv commented 7 years ago

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...

pkpkpk commented 7 years ago

The fix we are waiting on should not affect fw connecting.

pkpkpk commented 7 years ago

Are there any errors in the devtools console?

oskarkv commented 7 years ago

@pkpkpk No.

oskarkv commented 7 years ago

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.

pkpkpk commented 7 years ago

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

oskarkv commented 7 years ago

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.

pkpkpk commented 7 years ago

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?

oskarkv commented 7 years ago

In the JavaScript console? global.figwheel is undefined.

oskarkv commented 7 years ago

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?

pkpkpk commented 7 years ago

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.

oskarkv commented 7 years ago

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!

pkpkpk commented 7 years ago

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

oskarkv commented 7 years ago

@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. :)