diff --git a/project.clj b/project.clj index fa013cd..79afacb 100644 --- a/project.clj +++ b/project.clj @@ -2,13 +2,13 @@ :description "CLJSFiddle" :url "http://cljsfiddle.net" :dependencies [[org.clojure/clojure "1.6.0"] - [org.clojure/clojurescript "0.0-2227"] + [org.clojure/clojurescript "0.0-2850"] [org.clojure/tools.reader "0.8.4"] [org.clojure/core.match "0.2.1"] - [org.clojure/core.async "0.1.303.0-886421-alpha"] + [org.clojure/core.async "0.1.346.0-17112a-alpha"] [org.clojure/core.logic "0.8.7"] [org.clojure/tools.macro "0.1.5"] - [com.datomic/datomic-free "0.9.4815"] + [com.datomic/datomic-free "0.9.5130"] [ring/ring-jetty-adapter "1.3.0"] [ring/ring-devel "1.3.0"] [fogus/ring-edn "0.2.0"] @@ -21,16 +21,19 @@ [environ "0.5.0"] [com.taoensso/timbre "3.2.1"] [hylla "0.2.0"] - [domina "1.0.2"] - [prismatic/dommy "0.1.2"] + [domina "1.0.3"] + [prismatic/dommy "1.0.0"] + [org.omcljs/om "0.8.8"] + [reagent "0.5.0-alpha3"] + [quiescent "0.1.4"] [hiccups "0.3.0"] - [cljs-ajax "0.2.4"] - [om "0.6.4"] - [quiescent "0.1.3"] - [reagent "0.4.2"]] + [cljs-ajax "0.3.10"] + [rum "0.2.5"] + [datascript "0.9.0"] +] :source-paths ["src/clj" "src/cljs"] :plugins [[lein-ring "0.8.10"] - [lein-cljsbuild "1.0.3"]] + [lein-cljsbuild "1.0.4"]] ; :main cljsfiddle.handler ; :uberjar-name "cljsfiddle-standalone.jar" :min-lein-version "2.0.0" @@ -43,7 +46,7 @@ :source-paths ["src/cljs"] :compiler {:output-to "resources/public/js/app.js" :output-dir "resources/public/js/out-dev" - :source-map true + :source-map "resources/public/js/app.js.map" :optimizations :simple :pretty-print true}} :prod { diff --git a/src/clj/cljsfiddle/closure.clj b/src/clj/cljsfiddle/closure.clj index da3d76f..840767c 100644 --- a/src/clj/cljsfiddle/closure.clj +++ b/src/clj/cljsfiddle/closure.clj @@ -8,6 +8,7 @@ [cljsfiddle.db.src :as src] [cljs.closure :as cljs] [cljs.env :as cljs-env] + [cljsfiddle.compiler :refer [compiler-env]] [taoensso.timbre :as log] [clojure.pprint :refer [pprint]] [datomic.api :as d] @@ -17,7 +18,7 @@ [java.util.logging Level] [java.io StringReader BufferedReader] [com.google.javascript.jscomp.Compiler] - [com.google.javascript.jscomp JSSourceFile + [com.google.javascript.jscomp SourceFile CompilerOptions CompilationLevel ClosureCodingConvention])) @@ -31,11 +32,7 @@ :body (pr-str edn-data)}) (defn compile-cljs* [cljs-src-str] - (let [cljs-src (read-all cljs-src-str) - js-src (cljs-env/with-compiler-env - (cljs-env/default-compiler-env) - (cljs/-compile cljs-src {}))] - js-src)) + (:js-src (cljsfiddle.db.util/cljs-object-from-src cljs-src-str))) (defn js-errors [error] {:description (.description error) @@ -53,8 +50,8 @@ (.setOptionsForCompilationLevel level compiler-options) compiler-options) compiler (com.google.javascript.jscomp.Compiler.) - src (JSSourceFile/fromCode name src) - externs (JSSourceFile/fromCode "externs" "") + src (SourceFile/fromCode name src) + externs (SourceFile/fromCode "externs" "") result (.compile compiler externs src options)] (if (.success result) (merge {:status :success @@ -81,7 +78,11 @@ tdb (:db-after (d/with db (:tx cljs-tx))) deps (db/dependency-files tdb (:ns cljs-obj)) js-src-obj (closure-compile (:js-src cljs-obj)) - js-src-obj (assoc js-src-obj :dependencies deps :status :ok)] + js-src-obj (assoc js-src-obj + :dependencies deps + :deps-src (:deps-src cljs-obj) + :status :ok)] + (edn-response js-src-obj)) (catch clojure.lang.ExceptionInfo e (edn-response diff --git a/src/clj/cljsfiddle/compiler.clj b/src/clj/cljsfiddle/compiler.clj new file mode 100644 index 0000000..005568a --- /dev/null +++ b/src/clj/cljsfiddle/compiler.clj @@ -0,0 +1,17 @@ +(ns cljsfiddle.compiler + (:require [cljs.closure :as closure] + [cljs.js-deps :as deps] + [cljs.env :as cljs-env] + [cljs.compiler :as compiler])) + + +(let [ups-deps (closure/get-upstream-deps) + opts {:ups-libs (:libs ups-deps) + :ups-foreign-libs (:foreign-libs ups-deps) + :ups-externs (:externs ups-deps)} + + env (cljs-env/default-compiler-env opts)] + + (swap! env assoc :js-dependency-index (deps/js-dependency-index opts)) + + (def compiler-env env)) diff --git a/src/clj/cljsfiddle/db/util.clj b/src/clj/cljsfiddle/db/util.clj index d35be02..d449e8c 100644 --- a/src/clj/cljsfiddle/db/util.clj +++ b/src/clj/cljsfiddle/db/util.clj @@ -3,10 +3,13 @@ [clojure.java.io :as io] [clojure.tools.reader :as reader] [datomic.api :as d] + [cljs.analyzer :as ana] [cljs.env :as cljs-env] [cljs.closure :as closure] [cljs.js-deps :as cljs-deps] + [cljsfiddle.compiler :refer [compiler-env]] [cljs.tagged-literals :as tags] + [taoensso.timbre :as log] [environ.core :refer (env)]) (:import [clojure.lang LineNumberingPushbackReader] [java.io StringReader BufferedReader] @@ -37,14 +40,38 @@ line-seq cljs-deps/parse-js-ns)) +(comment + (defn log-time [prev txt] + (let [cur (System/nanoTime) + diff (- cur prev) + ms (-> diff + (/ 1000000) int)] + (log/trace (format "%dms | %s" ms txt)) + cur))) + (defn cljs-object-from-src [cljs-src-str] - (let [cljs-src (read-all cljs-src-str) - js-src (cljs-env/with-compiler-env - (cljs-env/default-compiler-env) - (closure/-compile cljs-src {})) ;; TODO perf. + (let [parsed-ns (ana/parse-ns + (-> cljs-src-str + StringReader. + BufferedReader.)) + cljs-src (binding [*ns* (-> parsed-ns :ns)] + (read-all cljs-src-str)) + + [deps-src js-src] + (cljs-env/with-compiler-env compiler-env + (let [opts {} + + compiled (closure/-compile cljs-src opts) + js-sources (closure/add-dependencies opts compiled) + fdeps-str (closure/foreign-deps-str + opts + (filter closure/foreign-source? js-sources))] + + [fdeps-str compiled])) {:keys [provides requires]} (parse-js-ns js-src)] {:src cljs-src-str :js-src js-src + :deps-src deps-src :sha (sha cljs-src-str) :ns (first provides) :requires (set requires)})) diff --git a/src/clj/cljsfiddle/import.clj b/src/clj/cljsfiddle/import.clj index a389051..2c3f9d8 100644 --- a/src/clj/cljsfiddle/import.clj +++ b/src/clj/cljsfiddle/import.clj @@ -21,9 +21,15 @@ (let [uri (or uri (env :datomic-uri) "datomic:free://localhost:4334/cljsfiddle")] + (prn "creating db") (d/create-database uri) + (prn "ok") (let [conn (d/connect uri)] - @(d/transact conn schema)))) + (prn "creating schema") + @(d/transact conn schema) + (prn "ok") + (System/exit 0) + ))) ;; Import js and cljs from the classpath into datomic. @@ -74,8 +80,11 @@ ;; TODO: Figure out if schema is installed. (defn -main [uri] (let [conn (d/connect uri) - files (find-files #{"cljs/" "clojure/" "goog/" "domina" "hiccups" - "dommy" "om" "quiescent" "reagent"} + files (find-files #{"cljs/" "clojure/" "goog/" "domina" "hiccups" + "cljsjs" + "react" "om" "quiescent" "reagent" + "rum" "sablono" "datascript" + "dommy"} (filter #(.endsWith % ".jar") (-> "java.class.path" System/getProperty @@ -86,12 +95,13 @@ cljs-objects (map cljs-object-from-file cljs-files)] (println "transacting cljs") (doseq [cljs cljs-objects] + (pr "Considering " (:file cljs) "... ") + (flush) (let [cljs-tx (:tx (src/cljs-tx (d/db conn) cljs))] - (print "Considering " (:file cljs) "... ") (if-not (empty? cljs-tx) (do @(d/transact conn cljs-tx) - (println "transacted.")) - (println "skipped.") + (prn "transacted.")) + (prn "skipped.") ))) (println "done.") (println "transacting js") @@ -116,7 +126,8 @@ (println "Running storage GC") (d/gc-storage conn (Date.)) - (println "Done."))) + (println "Done.")) + (System/exit 0)) ;; (-main (env :datomic-uri)) diff --git a/src/clj/cljsfiddle/views.clj b/src/clj/cljsfiddle/views.clj index c508360..8ccd7e6 100644 --- a/src/clj/cljsfiddle/views.clj +++ b/src/clj/cljsfiddle/views.clj @@ -1,7 +1,7 @@ (ns cljsfiddle.views (:require [hiccup.util :refer (escape-html)] [environ.core :refer (env)] - [cljsfiddle.closure :refer [compile-cljs*]])) + [cljsfiddle.db.util :refer [cljs-object-from-src]])) (def google-analytics-script "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ @@ -113,6 +113,11 @@ [:a {:href "http://cljsfiddle.net"} "cljsfiddle.net"] " © 2013 Jonas Enlund"]]])) (defn html-view [ns fiddle deps] + (let [cljs-obj (-> fiddle + :cljsfiddle/cljs + :cljsfiddle.src/blob + :cljsfiddle.blob/text + cljs-object-from-src)] [:html [:head [:title ns] @@ -128,14 +133,10 @@ :cljsfiddle.blob/text) [:script "CLOSURE_NO_DEPS=true;"] [:script "COMPILED=true;"] + [:script (:deps-src cljs-obj)] (for [dep deps] [:script {:src (str "/jscache/" (env :cljsfiddle-version) "/" dep)}]) - [:script - (-> fiddle - :cljsfiddle/cljs - :cljsfiddle.src/blob - :cljsfiddle.blob/text - compile-cljs*)]]]) + [:script (:js-src cljs-obj)]]])) (defn about-view [user] (base (navbar user) diff --git a/src/cljs/cljsfiddle/core.cljs b/src/cljs/cljsfiddle/core.cljs index 1be4cef..adba001 100644 --- a/src/cljs/cljsfiddle/core.cljs +++ b/src/cljs/cljsfiddle/core.cljs @@ -1,4 +1,5 @@ (ns cljsfiddle.core + (:require-macros [hiccups.core :as hiccups]) (:require [clojure.string :as s] [cljs.reader :as reader] [domina :as dom] @@ -21,14 +22,15 @@ [:script {:src (str "/jscache/" version "/" (s/replace dep ".cljs" ".js"))}])] (apply str (map render-html (concat html ds))))) -(defn make-srcdoc [html css js deps version] - (render-html +(defn make-srcdoc [html css js deps-src deps version] + (hiccups/html [:html [:head [:style css]] [:body [:script "window.onerror = function(msg, url, line) { parent.postMessage('{:type :runtime-error}', '*'); return false;};"] html + [:script (or deps-src "")] (make-deps deps version) [:script "cljs.core.set_print_fn_BANG_.call(null,function(s){var s = s.replace(/\"/g, \""\"); parent.postMessage('{:type :runtime-print :to-print \"' + s + '\"}', '*');});"] [:script js] @@ -99,7 +101,7 @@ ">" ">"})]) (defn output-html [msg] - (render-html (output-hiccup msg))) + (hiccups/html (output-hiccup msg))) (defn output-fn [] (let [out (dom/by-id "output")] @@ -156,6 +158,7 @@ (dom/add-class! run-btn "disabled") (http/POST "/compiler/compile" {:params {:src (.getValue cljs-editor)} + :format :edn :handler (fn [res] (dom/remove-class! run-btn "disabled") (condp = (:status res) @@ -163,6 +166,7 @@ (let [srcdoc (make-srcdoc (.getValue html-editor) (.getValue css-editor) (:js-src res) + (:deps-src res) (:dependencies res) version)] (.setAttribute result-frame "srcdoc" srcdoc)) @@ -174,6 +178,7 @@ {:params {:cljs (.getValue cljs-editor) :html (.getValue html-editor) :css (.getValue css-editor)} + :format :edn :handler (fn [res] (dom/remove-class! save-btn "disabled") (if (= (:status res) :success)