Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Finish compile-file and compile-root. Add cljsc script for compiling …

…projects. Add sample project. Refs #28
  • Loading branch information...
commit c3f8e90d6e7921bf84676782f0fdb48d57b2779c 1 parent 724862f
Brenton Ashworth brentonashworth authored
28 bin/cljsc
View
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Compile all cljs files into a single JavaScript file. Takes one or
+# two arguments followed by any number of gclosure compiler arguments.
+# The first argument is the directory containing the cljs sources to
+# compile. It is required. An optional second argument specifies the
+# name of the output directory where js files will be created. core.js
+# and all closure library dependencies used by core.js are included by
+# default (see cljsc.clj).
+
+CLJSC_CP=''
+for next in lib/*: closure/compiler/*: src/clj: src/cljs; do
+ CLJSC_CP=$CLJSC_CP$CLOJURESCRIPT_HOME'/'$next
+done
+
+if test $# -eq 0
+then
+ echo "Usage: cljsc <root-dir>"
+ echo " cljsc <root-dir> <js-output-dir>"
+ echo " cljsc <root-dir> <js-output-dir> <gclosure-args>"
+else
+ java -server -Xmx2G -Xms2G -Xmn256m \
+ -cp $CLJSC_CP \
+ clojure.main $CLOJURESCRIPT_HOME/bin/cljsc.clj $CLOJURESCRIPT_HOME $*
+fi
+
+
+
11 bin/cljsc.clj
View
@@ -0,0 +1,11 @@
+; Copyright (c) Rich Hickey. All rights reserved.
+; The use and distribution terms for this software are covered by the
+; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+; which can be found in the file epl-v10.html at the root of this distribution.
+; By using this software in any fashion, you are agreeing to be bound by
+; the terms of this license.
+; You must not remove this notice, or any other, from this software.
+
+(require '[cljs.project-compiler :as comp])
+
+(apply comp/compile-project *command-line-args*)
2  samples/hello/.gitignore
View
@@ -0,0 +1,2 @@
+out/
+hello.js
14 samples/hello/README
View
@@ -0,0 +1,14 @@
+Simple ClojureScript Project Example.
+
+To run it...
+
+1) Make sure your clojurescript directory has the gclosure stuff in it and core.js.
+2) Add CLOJURESCRIPT_HOME environment variable.
+3) Add $CLOJURESCRIPT_HOME/bin to your PATH.
+3) Run
+
+ cljsc src > hello.js
+
+ in this directory.
+4) Open hello.html and enjoy!
+
13 samples/hello/hello.html
View
@@ -0,0 +1,13 @@
+<html>
+ <head>
+ <title>Hello ClojureScript</title>
+ <script type="text/javascript" src="hello.js"></script>
+ </head>
+ <body>
+ <h1>Hello ClojureScript!</h1>
+ <script>
+ alert(hello.core.greet("ClojureScript"));
+ alert("The sum of [1,2,3,4,5,6,7,8,9] is: " + hello.core.sum([1,2,3,4,5,6,7,8,9]));
+ </script>
+ </body>
+</html>
8 samples/hello/src/hello/core.cljs
View
@@ -0,0 +1,8 @@
+(ns hello.core
+ (:require [hello.foo.bar :as bar]))
+
+(defn greet [n]
+ (str "Hello " n))
+
+(defn sum [xs]
+ (bar/sum xs))
4 samples/hello/src/hello/foo/bar.cljs
View
@@ -0,0 +1,4 @@
+(ns hello.foo.bar)
+
+(defn sum [xs]
+ (reduce + 0 xs))
93 src/clj/cljs/compiler.clj
View
@@ -930,22 +930,47 @@ goog.require = function(rule){Packages.clojure.lang.RT[\"var\"](\"cljs.compiler\
(lazy-seq (cons form (forms-seq f rdr)))
(.close rdr))))
+(defn- rename-to-js
+ "Change the file extension from .cljs to .js. Takes a File or a
+ String. Always returns a String."
+ [file-str]
+ (clojure.string/replace file-str #".cljs$" ".js"))
+
(defn compile-file
- "Compiles src to a file of the same name, but
- with a .js extension, in the src file's directory.
+ "Compiles src to a file of the same name, but with a .js extension,
+ in the src file's directory.
+
+ With dest argument, write file to provided location. If the dest
+ argument is a file outside the source tree, missing parent
+ directories will be created.
+
+ Both src and dest may be either a String or a File.
- With dest argument, write file to provided location."
+ Returns a map containing the namespace and dependencies for this
+ file."
([src]
- (let [dest (clojure.string/replace src #".cljs$" ".js")]
+ (let [dest (rename-to-js src)]
(compile-file src dest)))
([src dest]
- (let [forms (forms-seq src)]
- (with-open [out ^java.io.Writer (io/make-writer (io/file dest) {})]
- (binding [*out* out
- *cljs-ns* 'cljs.user]
- (doseq [form forms]
- (let [env {:ns (@namespaces *cljs-ns*) :context :statement :locals {}}]
- (emit (analyze env form)))))))))
+ (let [src-file (io/file src)
+ dest-file (io/file dest)]
+ (do (when (not (:defs (get @namespaces 'cljs.core)))
+ (load-file (repl-env) "cljs/core.cljs"))
+ (.mkdirs (.getParentFile (.getCanonicalFile dest-file)))
+ (with-open [out ^java.io.Writer (io/make-writer dest-file {})]
+ (binding [*out* out
+ *cljs-ns* 'cljs.user]
+ (loop [forms (forms-seq src-file)
+ ns-name nil
+ deps nil]
+ (if (seq forms)
+ (let [env {:ns (@namespaces *cljs-ns*) :context :statement :locals {}}
+ ast (analyze env (first forms))]
+ (do (emit ast)
+ (if (= (:op ast) :ns)
+ (recur (rest forms) (:name ast) (:requires ast))
+ (recur (rest forms) ns-name deps))))
+ {:ns (or ns-name 'cljs.user) :requires (vals deps)}))))))))
(comment
;; flex compile-file
@@ -956,6 +981,52 @@ goog.require = function(rule){Packages.clojure.lang.RT[\"var\"](\"cljs.compiler\
(compile-file "/tmp/somescript.cljs")
(slurp "/tmp/somescript.js")))
+(defn- path-seq
+ [file-str]
+ (string/split file-str (re-pattern java.io.File/separator)))
+
+(defn to-path
+ [parts]
+ (apply str (interpose java.io.File/separator parts)))
+
+(defn to-target-file
+ "Given the source root directory, the output target directory and
+ file under the source root, produce the target file."
+ [^java.io.File dir ^String target ^java.io.File file]
+ (let [dir-path (path-seq (.getAbsolutePath dir))
+ file-path (path-seq (.getAbsolutePath file))
+ relative-path (drop (count dir-path) file-path)
+ parents (butlast relative-path)
+ parent-file (java.io.File. ^String (to-path (cons target parents)))]
+ (java.io.File. parent-file ^String (rename-to-js (last relative-path)))))
+
+(defn compile-root
+ "Looks recursively in src-dir for .cljs files and compiles them to
+ .js files. If target-dir is provided, output will go into this
+ directory mirroring the source directory structure. Returns a list
+ of maps containing information about each file which was compiled."
+ ([src-dir]
+ (compile-root src-dir "out"))
+ ([src-dir target-dir]
+ (let [src-dir-file (io/file src-dir)
+ cljs-files (filter #(.endsWith (.getName ^java.io.File %) ".cljs") (file-seq src-dir-file))]
+ (loop [cljs-files cljs-files
+ output-files []]
+ (if (seq cljs-files)
+ (let [cljs-file (first cljs-files)
+ output-file ^java.io.File (to-target-file src-dir-file target-dir cljs-file)
+ ns-info (compile-file cljs-file output-file)]
+ (recur (rest cljs-files) (conj output-files (assoc ns-info :file-name (.getPath output-file)))))
+ output-files)))))
+
+(comment
+ ;; compile-root
+ ;; If you have a standard project layout with all file in src
+ (compile-root "src")
+ ;; will produce a mirrored directory structure under "out" but all
+ ;; files will be compiled to js.
+ )
+
(comment
;;the new way - use the REPL!!
93 src/clj/cljs/project_compiler.clj
View
@@ -0,0 +1,93 @@
+; Copyright (c) Rich Hickey. All rights reserved.
+; The use and distribution terms for this software are covered by the
+; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+; which can be found in the file epl-v10.html at the root of this distribution.
+; By using this software in any fashion, you are agreeing to be bound by
+; the terms of this license.
+; You must not remove this notice, or any other, from this software.
+
+(set! *warn-on-reflection* true)
+
+(ns cljs.project-compiler
+ (:refer-clojure :exclude [munge load-file loaded-libs macroexpand-1])
+ (:require [cljs.compiler :as comp])
+ (:import java.io.File
+ com.google.javascript.jscomp.CommandLineRunner))
+
+(def default-output-dir "out")
+
+(def required-goog (map comp/to-path [["base"]
+ ["string" "string"]
+ ["useragent" "jscript"]
+ ["string" "stringbuffer"]
+ ["object" "object"]]))
+
+(defn cljs-home-relative
+ [^String cljs-home ^String path]
+ (if (.endsWith cljs-home File/separator)
+ (str cljs-home path)
+ (str cljs-home File/separator path)))
+
+(defn default-args
+ [cljs-home]
+ (concat
+ (mapcat #(vector "--js" (cljs-home-relative cljs-home (comp/to-path ["closure" "library" "closure" "goog" (str % ".js")])))
+ required-goog)
+ ["--js" (cljs-home-relative cljs-home "core.js")]))
+
+(defn- dfs-visit
+ [state ns-name]
+ (let [file (get state ns-name)]
+ (if (:visited file)
+ state
+ (let [state (assoc-in state [ns-name :visited] true)
+ deps (:requires file)
+ state (reduce dfs-visit state deps)]
+ (assoc state :order (conj (:order state) file))))))
+
+(defn sort-by-dep
+ "Perform a depth-first search of the dependency graph returning a
+ list of file names in dependency order."
+ [files]
+ (let [state (reduce #(assoc %1 (:ns %2) %2) {} files)]
+ (map :file-name (:order (reduce dfs-visit (assoc state :order []) (map :ns files))))))
+
+(defn- to-args
+ "Create a list of js args for gclosure compiler."
+ [file-info]
+ (map #(str "--js=" %) (sort-by-dep file-info)))
+
+(defn- non-gclosure-arg?
+ [^String arg]
+ (not (.startsWith arg "--")))
+
+(defn output-directory
+ "Get the output directory form a list of arguments. If it exists, it
+ will be the first argument and will not be preceded by --."
+ [args]
+ (if-let [first-arg (first args)]
+ (if (non-gclosure-arg? first-arg)
+ first-arg
+ default-output-dir)
+ default-output-dir))
+
+(defn compile-project
+ "Wraps gclosure compiler adding the initial step of compiling all
+ cljs files to JavaScript. The first and second arguments are the
+ ClojureScript home directory and the root directory which contains
+ all cljs source files to compile.
+
+ An optional third argument is the name of the directory where output
+ js files will be written. This argument defaults to 'out'.
+
+ Any additional arguments must be valid gclosure compiler arguments
+ and will be passed through.
+
+ CommandLineRunner/main finishes by calling System/exit which makes
+ this unusable from the repl."
+ [cs-home src-dir & args]
+ (let [out-dir (output-directory args)
+ compiled-info (comp/compile-root src-dir out-dir)]
+ (CommandLineRunner/main (into-array (concat (drop-while non-gclosure-arg? args)
+ (default-args cs-home)
+ (to-args compiled-info))))))
Please sign in to comment.
Something went wrong with that request. Please try again.