Search code examples
clojureclojurescript

How to compile clojurescript to nodejs?


Why cljsbuild does not compile gulpfile.js file properly?

Here is my project.clj config:

(defproject cljs-selfstudy "0.1.0-SNAPSHOT"
  :description "Where I want to learn about clojurescript"
  :url "http://example.com"

  :dependencies [[org.clojure/clojure "1.7.0-alpha2"]
                 [org.clojure/clojurescript "0.0-2322"]]

  :plugins [[lein-cljsbuild "1.0.4-SNAPSHOT"]]

  :source-paths ["src"]


  :cljsbuild {
              :builds [{:id "gulpjs"
                        :source-paths ["src/gulpjs"]
                        :compiler {
                                   :output-to "gulpfile.js"                                   
                                   :optimizations :none
                                   :pretty-print true}}]})

Here is my core.cljs

(ns gulpjs.core
  (:require [cljs.nodejs :as node]))

(def gulp (node/require "gulp"))

(def gulp-livereload (node/require "gulp-livereload"))

(def gulp-markdown (node/require "gulp-markdown"))

(def gulp-watch (node/require "gulp-watch"))

(.task gulp "markdown" 
       #(-> (.source gulp "../markdown-explained")
            (.pipe (gulp-markdown))
            (.pipe (.dest gulp "build/markdown-explained"))))

Here is command I used to compile

lein cljsbuild once gulpjs

Compiling ClojureScript.
Compiling "gulpfile.js" from ["src/gulpjs"]...
Successfully compiled "gulpfile.js" in 3.316 seconds.

But I have this strange output gulpfile.js, it doesn't look like node codes at all, why it is so wrong???

goog.addDependency("base.js", ['goog'], []);
goog.addDependency("../cljs/core.js", ['cljs.core'], ['goog.string', 'goog.object', 'goog.string.StringBuffer', 'goog.array']);
goog.addDependency("../cljs/nodejs.js", ['cljs.nodejs'], ['cljs.core']);
goog.addDependency("../gulpjs/core.js", ['gulpjs.core'], ['cljs.core', 'cljs.nodejs']);

Solution

  • Since you are targeting nodejs, first thing that you are missing in the compiler options is

    :target :nodejs
    

    Second, if you use :optimizations :none you are missing too the option output-dir:

    :output-dir "out"
    

    Here is a nice briefing on the compiler options and characteristics: http://slides.com/joakino/diving-into-clojurescript/#/5 (Go down in the slides)

    Then in your main file, you need to set a main function and it is nice to enable console prints:

    (ns cljs-gulp.core
      (:require [cljs.nodejs :as nodejs]))
    
    (nodejs/enable-util-print!)
    
    (defn -main [& args] ... )
    
    (set! *main-cli-fn* -main)
    

    Then, you can actually use any mode in nodejs, but the ones that work by default are simple and advanced. For none you need a wrapper file to make node be able to load closure dependencies, so create a file named index.js for example and put this in:

    require('./out/goog/bootstrap/nodejs')
    require('./cljs_gulp') // Name of the js ouput file
    require('./out/cljs_gulp/core') // Path to compiled core file
    cljs_gulp.core._main() // appname.namespace._mainfunction
    

    And after compiling you would node index.js instead of node cljs_gulp.js. And that works awesome, and you take advantage of the super fast recompilation times.

    This article explains it all pretty well, and it's recent: http://blog.lauripesonen.com/clojurescript-optimizations-on-node-huh/

    Here is the code: (my project name was generated as cljs_gulp, so change that to fit yours)

    project.clj

    (defproject cljs_gulp "0.1.0-SNAPSHOT"
      :description "Where I want to learn about clojurescript"
      :url "http://example.com"
    
      :dependencies [[org.clojure/clojure "1.7.0-alpha2"]
                     [org.clojure/clojurescript "0.0-2322"]]
    
      :plugins [[lein-cljsbuild "1.0.4-SNAPSHOT"]]
    
      :source-paths ["src"]
    
      :cljsbuild {
                  :builds [{:id "gulpjs"
                            :source-paths ["src/cljs_gulp/"]
                            :compiler {
                                       :target :nodejs
                                       :output-to "cljs_gulp.js"
                                       :output-dir "out"
                                       :optimizations :none
                                       :pretty-print true}}]})
    

    src/cljs_gulp/core.cljs

    (ns cljs-gulp.core
      (:require [cljs.nodejs :as nodejs]))
    
    (nodejs/enable-util-print!)
    
    (def gulp (nodejs/require "gulp"))
    
    (def gulp-livereload (nodejs/require "gulp-livereload"))
    
    (def gulp-markdown (nodejs/require "gulp-markdown"))
    
    (def gulp-watch (nodejs/require "gulp-watch"))
    
    (defn -main [& args]
      (.task gulp "markdown"
             #(-> (.source gulp "../markdown-explained")
                  (.pipe (gulp-markdown))
                  (.pipe (.dest gulp "build/markdown-explained")))))
    
    (set! *main-cli-fn* -main)
    

    There are a couple of cljs node templates that are very helpful for getting started on cljs and node, instead of the browser: