Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

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

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

winterbe opened this issue Feb 4, 2015 · 7 comments

Comments

@winterbe
Copy link

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
Copy link
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
Copy link
Author

winterbe commented Feb 4, 2015

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

@winterbe
Copy link
Author

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.

@sophiebits
Copy link
Collaborator

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.

@winterbe
Copy link
Author

Thanks for pointing that out.

@worldsayshi
Copy link

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
Copy link

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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants