clojurescriptcljsbuild

Multiple ClojureScript files on same page


I have a project that is using Jasmine to test the JavaScript. I am trying to switch to using ClojureScript for the front end. My project.clj is like

(defproject myproject "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.5.1"]
                 [org.clojure/clojurescript"0.0-1889"]
                 [org.clojure/google-closure-library-third-party "0.0-2029"]
                 [domina "1.0.0"]
                 [hiccups "0.2.0"]]
  :plugins [[lein-cljsbuild "0.3.3"]]
  :cljsbuild {
              :builds [{
                        :source-paths ["src/clojurescript"]
                        :compiler {
                                   :output-to "public/javascripts/main.js"
                                   :optimizations :whitespace
                                   :pretty-print true}}
                       {
                        :source-paths ["spec/clojurescript"]
                        :compiler {
                                   :output-to "spec/javascripts/mainSpec.js"
                                   :optimizations :whitespace
                                   :pretty-print true}}]})

So all the .cljs files in src/clojurescript get compiled to main.js and all the .cljs in spec/clojurescript get compiled to mainSpec.js. When I load the Jasmine page, both the .js files are loaded but the tests aren't run. In the console I get an Error: Namespace "goog.debug.Error" already declared. Both the .js files have the same ~30k lines of google closure code at the top which is causing the error. If I delete this code from mainSpec.js it runs fine. Is there any way to tell cljsbuild to leave this code off the spec file?


Solution

  • As Jared314 and Zubair pointed out, the problem you're encountering is caused by trying to include two clojurescript compilation outputs in the same page. Clojurescript/Google Closure expect to do a 'whole-world' compile, that is, the compiler expects that all of the code for the entire page is passed to the compiler so that it can optimise it, rename functions, and ultimately spit out a single javascript file. It's not designed to produce multiple output files that work together.

    The 'correct' way to solve your problem is to produce two outputs that are used in isolation: a main.js file for running your application, and a spec.js file that include all the code in main plus the code in spec for testing. You can do this by setting up your project something like this:

    :cljsbuild {
              :builds [{
                        :source-paths ["src/clojurescript"]
                        :compiler {:output-to "public/javascripts/main.js"}}
                       {
                        :source-paths ["src/clojurescript" "spec/clojurescript"]
                        :compiler {:output-to "spec/javascripts/spec.js"}}]})
    

    Your jasmine page should refer to spec.js but not main.js - referring to both is the cause of your error.