React doesn't eval on Java 8 Nashorn JavaScript Engine #3037

Closed
winterbe opened this Issue Feb 4, 2015 · 7 comments

Projects

None yet

5 participants

@winterbe
winterbe commented Feb 4, 2015

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.

@brigand
Contributor
brigand commented Feb 4, 2015

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.

@winterbe winterbe referenced this issue in ForbesLindesay/umd Feb 4, 2015
Closed

Add support for Java 8 Nashorn Engine #22

@winterbe
winterbe commented Feb 4, 2015

Thanks for the hint. I've filed another issue.

@winterbe
winterbe commented Feb 9, 2015

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;

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.

@spicyj
Member
spicyj commented Feb 26, 2015

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.

@spicyj spicyj closed this Feb 26, 2015
@winterbe

Thanks for pointing that out.

@worldsayshi

Also, don't forget console.error = print;. This took me a while to figure out. Hope it helps someone.

sdeleuze/spring-react-isomorphic#3

@david-mark

The root of this issue is fixed in this pull request:

#8341

Suggested workarounds are just dodging the real problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment