Nashorn is the new JavaScript Engine shipped with Java 8. Nashorn compiles JavaScript to Java Bytecode, so it runs natively on the JVM.
Unfortunately React doesn't evaluate properly on Nashorn due to the fact that Nashorn doesn't support any kind of module system like AMD out of the box.
This code creates a new nashorn engine and evaluates React on the JVM:
ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn");
nashorn.eval("load('https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js')");
Running the above code results in the following error:
Caused by: https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js:4 TypeError: Cannot set property "React" of undefined
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:58)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:214)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:186)
at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:173)
at jdk.nashorn.internal.runtime.Undefined.lookupTypeError(Undefined.java:128)
at jdk.nashorn.internal.runtime.Undefined.lookup(Undefined.java:119)
at jdk.nashorn.internal.runtime.linker.NashornLinker.getGuardedInvocation(NashornLinker.java:98)
at jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker.getGuardedInvocation(CompositeTypeBasedGuardingDynamicLinker.java:176)
at jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
at jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:144)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:232)
at jdk.nashorn.internal.scripts.Script$react.L:4(https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js:4)
at jdk.nashorn.internal.scripts.Script$react.runScript(https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js:4)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:535)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:209)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:378)
at jdk.nashorn.internal.runtime.Context.evaluateSource(Context.java:983)
at jdk.nashorn.internal.runtime.Context.load(Context.java:680)
at jdk.nashorn.internal.objects.Global.load(Global.java:877)
at jdk.nashorn.internal.scripts.Script$\^eval\_.runScript(<eval>:1)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:535)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:209)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:378)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:568)
... 34 more
Simple workaround is to create a variable window referencing the the global context this:
ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn");
nashorn.eval("var window = this;"); // workaround
nashorn.eval("load('https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js')");
BTW: Here's a fully working isomorphic java example of your CommentBox tutorial:
https://github.com/winterbe/spring-react-example
The CommentBox is initially rendered on the server with Nashorn.
The root of this issue is in the build tool: browserify's dependency browser-pack's dependency umd. In template.js it only checks for window, global, or self. You can send a PR there to fall back to this as a last resort.
For now, I'd recommend using var global = this; instead, because typeof window !== 'undefined' is often used to determine a if a script is being run in the browser.
Thanks for the hint. I've filed another issue.
FYI: The issue is fixed in UMD.
In the meanwhile I've found another incompatibility between React and Nashorn: There's no console available in Nashorn. Instead Nashorn defines a global function print. I'm using this simple workaround to get my React example working on the JVM:
var global = this;
var console = {};
console.debug = print;
console.warn = print;
console.log = print;
Dunno if this fixes all possible issues but that's what I found out so far.
In the docs we do say that we require a console polyfill for browsers(/engines) that don't support it:
http://facebook.github.io/react/docs/working-with-the-browser.html#browser-support-and-polyfills
Doesn't sound like there's anything else we need to do here so I'm closing this.
Thanks for pointing that out.
Also, don't forget console.error = print;. This took me a while to figure out. Hope it helps someone.
https://github.com/sdeleuze/spring-react-isomorphic/issues/3
The root of this issue is fixed in this pull request:
https://github.com/facebook/react/pull/8341
Suggested workarounds are just dodging the real problem.
Most helpful comment
FYI: The issue is fixed in UMD.
In the meanwhile I've found another incompatibility between React and Nashorn: There's no
consoleavailable in Nashorn. Instead Nashorn defines a global functionprint. I'm using this simple workaround to get my React example working on the JVM:https://github.com/winterbe/spring-react-example/blob/master/src/main/resources/static/nashorn-polyfill.js
Dunno if this fixes all possible issues but that's what I found out so far.