如何在Node.js上运行ClojureScripts Om?

我试图解决,如果我可以在Node.js上使用Om来生成HTML。 我已经能够在Node.js上运行ClojureScript ,显然React可以在Node.js上运行 。 根据基本指南,我创build了一个Leiningen项目

lein new figwheel om-tut -- --om 

修改project.clj文件启动如下

 (defproject om-tut "0.1.0-SNAPSHOT" :description "FIXME: write this!" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] [org.clojure/clojurescript "0.0-2850"] [figwheel "0.2.5-SNAPSHOT"] [org.clojure/core.async "0.1.346.0-17112a-alpha"] [sablono "0.3.4"] [org.omcljs/om "0.8.8"]] :plugins [[lein-cljsbuild "1.0.4"] [lein-figwheel "0.2.5-SNAPSHOT"] [lein-npm "0.4.0"]] :source-paths ["src"] :clean-targets ^{:protect false} ["resources/public/js/compiled" "out/server" "out/server/om_tut.js"] :cljsbuild { :builds [{:id "dev" :source-paths ["src" "dev_src"] :compiler {:output-to "resources/public/js/compiled/om_tut.js" :output-dir "resources/public/js/compiled/out" :optimizations :none :main om-tut.dev :asset-path "js/compiled/out" :source-map true :source-map-timestamp true :cache-analysis true }} {:id "min" :source-paths ["src"] :compiler {:output-to "resources/public/js/compiled/om_tut.js" :main om-tut.core :optimizations :advanced :pretty-print false}} {:id "server" :source-paths ["src"] :compiler { :main pow.core :output-to "out/server/om_tut.js" :output-dir "out/server" :optimizations :simple :target :nodejs :cache-analysis true :source-map "out/server/om_tut.js.map"}}]} 

并将core.cljs更改为

 (ns ^:figwheel-always om-tut.core (:require[om.core :as om :include-macros true] [om.dom :as dom :include-macros true])) (enable-console-print!) (println "Edits to this text should show up in your developer console.") ;; define your app data so that it doesn't get over-written on reload (defonce app-state (atom {:text "Hello world!"})) (defn render [data owner] (reify om/IRender (render [_] (dom/h1 nil (:text data))))) (om/root render app-state {:target (. js/document (getElementById "app"))}) (defn -main [] om.dom/render-to-str (render app-state nil)) (set! *main-cli-fn* -main) 

该项目使用以下命令成功编译

 lein cljsbuild once server 

但是当我尝试从Windows cmd shell运行这样的生成输出

 node out\server\om_tut.js 

我明白了

  ...\om-tut\out\server\om_tut.js:40237 om.dom.input = om.dom.wrap_form_element.call(null, React.DOM.input, "input"); ^ ReferenceError: React is not defined at Object.<anonymous> (...\om-tut\out\server\ om_tut.js:40237:52) at Module._compile (module.js:460:26) at Object.Module._extensions..js (module.js:478:10) at Module.load (module.js:355:32) at Function.Module._load (module.js:310:12) at Function.Module.runMain (module.js:501:10) at startup (node.js:129:16) at node.js:814:3 

我认为未定义的React对象应该来自… \ om-tut \ out \ react.inc.js文件,该文件存在并应该在生成的om_tut.js文件的第37532行加载

 cljs.core.load_file("react.inc.js"); 

任何关于什么可能出错的想法?

你需要添加一个前导码到project.clj ,例如:preamble ["include.js"] 。 前导符隐式引用相对于project.clj/resources目录。 来源: https : //github.com/Sparrho/supper/blob/master/project.clj

include.js您将提供对React的引用:

 var React = require("react"); 

来源: https : //github.com/Sparrho/supper/blob/master/resources/include.js

作为参考,这里是project.clj的构build块:

 {:id "server" :source-paths ["src"] :compiler {:main myapp.core-server :target :nodejs :output-to "deploy/index.js" :output-dir "out-server" :preamble ["include.js"] ;; Implicitly nested in /resources :optimizations :simple :language-in :ecmascript5 :language-out :ecmascript5}} 

我也读过:preamble可以直接引用react.min.js ,因为它已经捆绑在一个WebJar上,Om依赖于它。 来源: https : //groups.google.com/forum/#!topic/ clojurescript/ TL8Cv-jPkzM

您可以尝试以下内容的解决方法:preamble ["include.js"]

 module.exports = ''; 

但只有当你只有一些cljsjs/ packages(在这种情况下,它是cljsjs/reactcljsjs/react 。 例如包括cljsjs/jquery 2.1.4将无法正常工作。


由于React定义,出现问题:

 !function(e){ if ("object" == typeof exports && "undefined" != typeof module) { module.exports = e(); } else if ("function" == typeof define && define.amd) { define([],e); } else{ var t; t= "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this, t.React = e() } }(function(){/* React definition */}) 

环境在module.exports中没有window对象,但是它有modulemodule.exports 。 我们通过将module.exports重置为string来module.exports环境。

React = require('react')在安装了react模块的NpmJS环境中不起作用。


在我看来,正确的解决scheme不是将React代码包含在模块中,而是在依赖性react NpmJS环境下使用此模块。

在这种情况下, tyronep的答案是好的。 我们应该:

  1. 使用以下内容:preamble

     global.React = require('react') 
  2. 不要包含cljsjs/react依赖关系cljsjs/react

  3. 需要在NpmJS依赖关系中react

不幸的是,如果我们想使用om那么必须包含cljsjs/react (这是多余的包含)

你目前的问题是加载React模块,我相信你会解决你的configuration问题,但是你不能在Node上调用om.core/rootom.core/root将你的React组件挂载到一个DOM中,这个Node没有。 你想要的是定义你的组件,传递你的静态数据,然后调用React.renderToStringhttps://facebook.github.io/react/docs/top-level-api.html#react.rendertostring )。 Om使用render-to-str包装它。

 (def static-data {:text "Hello world!"}) (defn title-component [data owner] (reify om/IRender (render [_] (dom/h1 nil (:text data))))) (def component-html-as-string (dom/render-to-str (title-component static-data))) 

Om的大部分价值来自于他们的状态处理能力,你不需要服务器端渲染(这就是为什么我省略atom )。 如果你想要的是在ClojureScript中的React模板,我build议你看看Sablono ,它有一个静态html函数和一个比om.dom生成模板更好的语法。

另外,要在Node上开发,最好从mies-node开始