Resolving modules using require.js and Java/Rhino
require.js works well with rhino. Recently, I used it in a project.
- You have to make sure to use r.js (not require.js) , modified version of require.js for rhino.
- You have to extend
ScritableObject
class to implementload
andprint
function. When you callrequire(["a"])
, the load function in this class will be called, you can tweak this function to load the js file from any location. In the below example, I load fromclasspath
. - You have to define the property
arguments
in the sharedscope as shown below in the sample code - Optionally, you can configure the sub path using
require.config
, to specify the subdirectory inside classpath where js files are located.
JsRuntimeSupport
public class JsRuntimeSupport extends ScriptableObject {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(JsRuntimeSupport.class);
private static final boolean silent = false;
@Override
public String getClassName() {
return "test";
}
public static void print(Context cx, Scriptable thisObj, Object[] args,
Function funObj) {
if (silent)
return;
for (int i = 0; i < args.length; i++)
logger.info(Context.toString(args[i]));
}
public static void load(Context cx, Scriptable thisObj, Object[] args,
Function funObj) throws FileNotFoundException, IOException {
JsRuntimeSupport shell = (JsRuntimeSupport) getTopLevelScope(thisObj);
for (int i = 0; i < args.length; i++) {
logger.info("Loading file " + Context.toString(args[i]));
shell.processSource(cx, Context.toString(args[i]));
}
}
private void processSource(Context cx, String filename)
throws FileNotFoundException, IOException {
cx.evaluateReader(this, new InputStreamReader(getInputStream(filename)), filename, 1, null);
}
private InputStream getInputStream(String file) throws IOException {
return new ClassPathResource(file).getInputStream();
}
}
Sample Code
public class RJsDemo {
@Test
public void simpleRhinoTest() throws FileNotFoundException, IOException {
Context cx = Context.enter();
final JsRuntimeSupport browserSupport = new JsRuntimeSupport();
final ScriptableObject sharedScope = cx.initStandardObjects(browserSupport, true);
String[] names = { "print", "load" };
sharedScope.defineFunctionProperties(names, sharedScope.getClass(), ScriptableObject.DONTENUM);
Scriptable argsObj = cx.newArray(sharedScope, new Object[] {});
sharedScope.defineProperty("arguments", argsObj, ScriptableObject.DONTENUM);
cx.evaluateReader(sharedScope, new FileReader("./r.js"), "require", 1, null);
cx.evaluateReader(sharedScope, new FileReader("./loader.js"), "loader", 1, null);
Context.exit();
}
}
loader.js
require.config({
baseUrl: "js/app"
});
require (["a", "b"], function(a, b) {
print('modules loaded');
});
js/app
directory should be in your classpath.
Admin
Updated on June 04, 2022Comments
-
Admin almost 2 years
I'm trying to get require.js to load modules on the server-side with Java 6 and Rhino.
I'm able to load require.js itself just fine. Rhino can see the
require()
function. I can tell because Rhino complains that it can't find the function when I changerequire()
to something else likerequireffdkj()
.But when I try to require even a simple JS, like
hello.js
var hello = 'hello';
using either of the following:
require('hello'); require('./hello');
it doesn't work. I get
Caused by: javax.script.ScriptException: sun.org.mozilla.javascript.internal.JavaScriptException: [object Error] (<Unknown source>#31) in <Unknown source> at line number 31 at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:153) at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:167) at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
I have my
hello.js
at the top of the Java classpath. That's where I haverequire.js
as well. I tried movinghello.js
everywhere I could think it might possibly go, including the root of my hard drive, the root of my user directory, the directory from which I'm running my Java app, etc. Nothing works.I looked at the CommonJS spec (http://wiki.commonjs.org/wiki/Modules/1.0) and it says that top-level IDs (like
hello
) are resolved from the "conceptual module name space root", whereas relative IDs (like./hello
) are resolved against the calling module. I'm not sure where either of those baselines is, and I suspect that's the issue.Any suggestions? Can I even use require.js from Rhino?
EDIT: Thinking that I need to set the environment up as per Pointy's suggestion in the comment below, I tried evaluating
r.js
as well. (I tried evaluating after evaluatingrequire.js
, and then again beforerequire.js
.) In either case I get an error:Caused by: javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "arguments" is not defined. (<Unknown source>#19) in <Unknown source> at line number 19 at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:153) at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:167) at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
"arguments" appears to be a variable in
r.js
. I think it's for command line arguments, so I don't thinkr.js
is the right path for what I'm trying to do. Not sure though.