              "\"); } else { console.warn(\"ClojureScript could not load :main, did you forget to specify :asset-path?\"); };</script>');\n")))))
 
 (defn output-modules
-  ([opts modules]
-    (doseq [{:keys [output-to closure-module]} modules]
-      (spit (io/file output-to) (.toSource ^JSModule closure-module)))))
+  "Given compiler options and a sequence of module name and module description
+   tuples output module sources to disk. Modules description must define
+   :output-to and supply :source entry with the JavaScript source to write
+   to disk."
+  [opts modules]
+  (doseq [[name {:keys [output-to source]}] modules]
+    (assert (not (nil? output-to))
+      (str "Module " name " does not define :output-to"))
+    (assert (not (nil? source))
+      (str "Module " name " did not supply :source"))
+    (spit (io/file output-to) source)))
 
 (defn ^String rel-output-path
   "Given an IJavaScript which is either in memory, in a jar file,

     :output-dir "samples/hello/out"
     :modules
     {:hello
      {:output-to "samples/hello/out/hello.js"}}})
  )

(defn watch

        sources (if (= :whitespace (:optimizations opts))
                  (cons "var CLOSURE_NO_DEPS = true;" sources)
                  sources)
        modules (build-modules sources opts)
        ^List inputs (map (comp :closure-module second) modules)
        ^Result result (.compileModules closure-compiler externs inputs compiler-options)]
    (if (.success result)
