Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connecting to ClojureScript bREPL: clojure.browser.repl/connect throws TypeError in compiled JavaScript

I'm trying to connect to a ClojureScript browser REPL, and I'm having trouble with clojure.browser.repl/connect. My compiled JavaScript throws a TypeError trying to call appendChild on a null object in the block of Google Closure code at the top. I'm following the instructions in ClojureScript: Up and Running (Chapter 9, p.78, available in the preview), and wondering if the tooling for this has changed since it was published.

I'm using Leiningen 2.0.0, Java 1.6.0_37, OS X 10.7.5, plus the dependencies in my project.clj:

(defproject brepl-hello "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [org.clojure/clojurescript "0.0-1552"]
                 [compojure "1.1.5"]
                 [ring/ring-jetty-adapter "1.1.8"]]
  :plugins [[lein-cljsbuild "0.3.0"]]
  :source-paths ["src/clj"]
  :cljsbuild {:builds [{
                :source-paths ["src/cljs"]
                :compiler {
                 :output-to "resources/public/brepl-hello.js"
                 :optimizations :whitespace 
                 :pretty-print true}}]})

Here's the only ClojureScript source file, src/cljs/brepl_hello/brepl-hello.cljs:

(ns brepl-hello
  (:require [clojure.browser.repl :as repl]))

(repl/connect "http://localhost:9000/repl")

This compiles to the file resources/public/brepl-hello.js, which I've inserted into index.html in the same directory:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <script type="text/javascript" src="brepl-hello.js"></script>
    </head>
    <body>
    </body>
</html>

I've been serving this on port 3000 with Ring/Jetty from the REPL or Python SimpleHTTPServer. When I open this page in Chrome, the dev console shows Uncaught TypeError: Cannot call method 'appendChild' of null, with a traceback to this if/else block in the Google Closure code at the top of the complied js file, where parentElm (passed in to the containing function as a parameter) is null.

if(goog.userAgent.GECKO || goog.userAgent.WEBKIT) {
    window.setTimeout(goog.bind(function() {
      parentElm.appendChild(iframeElm);
      iframeElm.src = peerUri.toString();
      goog.net.xpc.logger.info("peer iframe created (" + iframeId + ")")
    }, this), 1)
  }else {
    iframeElm.src = peerUri.toString();
    parentElm.appendChild(iframeElm);
    goog.net.xpc.logger.info("peer iframe created (" + iframeId + ")")
  }

This seems to be a problem with clojure.browser.repl/connect. Swapping out this line in the ClojureScript source for something like:

(ns brepl-hello
  (:require [clojure.browser.repl :as repl]))

(.write js/document "Hello World!")

Will compile and run in the browser just fine. I suspect something is misconfigured in my build settings or directory structure, or I'm making a noob mistake somewhere in all this. What's changed since the time the instructions I'm following were published? I found a couple references to this problem in the #clojure irc logs, but no solution.

Finally, here's an abbreviated directory tree for reference:

├── out
│   ├── cljs
│   │   ├── core.cljs
│   │   └── core.js
│   ├── clojure
│   │   └── browser
│   │       ├── event.cljs
│   │       ├── event.js
│   │       ├── net.cljs
│   │       ├── net.js
│   │       ├── repl.cljs
│   │       └── repl.js
│   └── goog
│       └── [...] 
├── pom.xml
├── project.clj
├── resources
│   └── public
│       ├── brepl-hello.js
│       └── index.html
├── src
│   ├── clj
│   │   └── brepl_hello
│   │       └── core.clj
│   └── cljs
│       └── brepl_hello
│           └── brepl-hello.cljs
└─── target
     ├── brepl-hello-0.1.0-SNAPSHOT.jar
     ├── classes
     ├── cljsbuild-compiler-0
     │   ├── brepl_hello
     │   │   └── brepl-hello.js
     │   ├── cljs
     │   │   ├── core.cljs
     │   │   └── core.js
     │   └── clojure
     │       └── browser
     │           ├── event.cljs
     │           ├── event.js
     │           ├── net.cljs
     │           ├── net.js
     │           ├── repl.cljs
     │           └── repl.js
     └── stale
         └── extract-native.dependencies
like image 779
ecmendenhall Avatar asked Jan 27 '13 20:01

ecmendenhall


2 Answers

Well, its open source and looking at the code it seems that document.body is null at the time the repl hidden iframe is being added to it (the connect call leads to this point).

You should do this connect call on dom ready or body on load and it should work fine.

like image 65
Ankur Avatar answered Oct 21 '22 19:10

Ankur


Take a look at:

https://github.com/magomimmo/modern-cljs/blob/master/doc/tutorial-02.md

or, for a better brepl experience, here

https://github.com/magomimmo/modern-cljs/blob/master/doc/tutorial-18.md

like image 2
Magomimmo Avatar answered Oct 21 '22 21:10

Magomimmo