reagent-project / reagent-template

A Leiningen template for projects using Reagent.
MIT License
395 stars 55 forks source link

Deploying to Heroku gives 'ClojureScript has not been compiled!' #124

Open boyentenbi opened 7 years ago

boyentenbi commented 7 years ago

I've created an app using this template (great stuff btw) and am now trying to deploy using Heroku as per the README instructions.

In the project directory I run

lein do clean, uberjar
git init
git add .
git commit -m "init"
heroku create
git push heroku master

After the last command, the remote deploys the app and verifies it. One of the messages during deployment is: Compiling "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/prod/cljs"] which seems to be correct.

However, the app gives the message 'ClojureScript has not been compiled!' which I am familiar with from local development. Locally this just means I haven't run lein figwheel yet, but I'm not sure what I ought to do since this is the deployed version.

Any help is appreciated, cheers!

yogthos commented 7 years ago

Looking in the console log, I see the following error:

Uncaught TypeError: (intermediate value)(intermediate value)(intermediate value).qg is not a function

It's usually an indication that some external Js function got munged during advanced compilation. You probably just have to add externs for any Js libraries you're using.

yogthos commented 7 years ago

Just to give more detail on what's happening. The compiler will minify the Js code it produces, so if it sees something like someFunction, then it will create a shortened name from it such as qg.

The compiler is able to track all the names it converts in ClojureScript code and core JavaScript functions. However, when you use code from a library, the compiler won't know about it. This is where externs come in. The externs tell the compiler what symbols need to be guarded against renaming, so they're not munged during compilation.

In most cases you can just supply the library as its own extern. For example, if you have your libraries under resources/public/js, then you just add them in the compiler options as follows:

{:source-paths ["src/cljs"]
     :compiler
                   {:output-to     "target/cljsbuild/public/js/app.js"
                    :output-dir    "target/uberjar"
                    :externs       ["react/externs/react.js"]
                                   ["public/js/mylib.js"] ;; <-- your js library
                    :optimizations :advanced
                    :pretty-print  false}}
ekhall commented 7 years ago

This "reloading" seems to still occur for me when deployed to heroku despite adding all my javascript files. (By the way, is each extern it's own vector? Seems un-clojurelike to me. Would have expected a single vector with all strings / filenames as elements)

Could this be because I'm including javascript from a web resource (via Reagent)

 (include-js "https://code.jquery.com/jquery-2.2.3.min.js")
yogthos commented 7 years ago

Sorry, the externs is a typo. It should be a single vector:

["react/externs/react.js"
 "public/js/mylib.js"]

You would need the resources to be available on the classpath/filesystem during the compilation step. So, if you're including the resource from a CDN, you would need a local copy to compile the externs.

ekhall commented 7 years ago

You're a rockstar @yogthos - thank you. I'm still getting the "compiling" thing on heroku with the reagent lein template and all local js and things setup as above but I'll keep digging.

Ps - whatever's minimizing jquery (Google Closure?) gives a mess of errors when optimizing jquery :)

yogthos commented 7 years ago

Sorry to hear you're still having problems. One more thing to look at might be cljsjs repository. If the libraries you're using are packaged there, then they will have externs packaged with them. There's also more externs info on here.

The compiler shouldn't be doing anything to jQuery itself. What happens when externs are generated is that it tries to infer the function signatures from the library. That can give a lot of warnings. You can suppress these by adding the following to your cljsbuild:

:closure-warnings {:externs-validation :off}
alehatsman commented 7 years ago

@ekhall @yogthos So what status this issues have? Have you resolved it?