Giter Site home page Giter Site logo

typesafehub / js-engine Goto Github PK

View Code? Open in Web Editor NEW

This project forked from huntc/js-engine

72.0 10.0 20.0 229 KB

A JavaScript Engine Library - provides an abstract of a means to execute JavaScript code where no browser is involved.

License: Other

Scala 98.99% JavaScript 1.01%

js-engine's Introduction

JavaScript Engine

Build Status

The JavaScript Engine library (jse) provides an Actor based abstraction so that JavaScript code can be executed in a browser-less fashion. In-jvm support is provided in the form of Trireme, a Node API for Rhino. Standalone Rhino is also supported with a RhinoShell environment. Native JavaScript performance is provided by using Common Node, node.js and PhantomJS (these latter 3 are required to be installed separately).

While multiple engines are provided, plugin authors are encouraged to target the Node API. Doing so means that the engine options generally come down to Trireme and Node, depending on whether in-JVM or native support is required. Trireme is therefore provided as a default as there should be no JS coding differences between Trireme and Node, and Trireme requires no manual installation.

Sample usage can be obtained by inspecting the js-engine-tester sub-project. There's a main class that illustrates essential interactions. Here is a snippet of it:

val engine = system.actorOf(Node.props(), "engine")
val f = new File(Main.getClass.getResource("test.js").toURI)
for (
  result <- (engine ? Engine.ExecuteJs(f, Seq("999"))).mapTo[JsExecutionResult]
) yield {
  println(new String(result.output.toArray, "UTF-8"))
  ...

An additional sbt-js-engine sub-project is provided that declares a base for sbt plugins that use the engine. This sub-project has a separate release cycle to jse itself and could be spun off into its own repo at a later point in time e.g. if/when Maven/Gradle support is required. The main point here is that the core JavaScript engine library is not related to sbt at all and should be usable from other build tools.

The library is entirely reactive and uses Akka.

© Typesafe Inc., 2013, 2014

js-engine's People

Contributors

benmccann avatar dwijnand avatar gmethvin avatar huntc avatar jroper avatar marcospereira avatar pvlugter avatar richdougherty avatar tgambet avatar yanns avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-engine's Issues

Library dependency

Hi,
could you add in your README the sbt libraryDependency instruction to depends on your library ?
Thanks

Nashorn support

I see that Rhino is an option. It'd also be nice to have Nashorn be an option since it's supposed to be so much more performant for those users on Java 8.

Stream Stdout/Stderr instead of buffering

Currently all logging is buffered inside a ByteString builder,
which let's long running tasks appear unresponsive (e.g. rjs
optimize).

I tried to get my head around the Engine class and implementing a simple
logging trait where other logging implementations, such as sbt.streams,
can easily be wrapped.

However I failed handling the ByteStrings and the context.become calls.
My Logger trait looks essentially like this

trait Logger {
    // var in trait?
    var outputBuilder = ByteString.newBuilder

    def info(msg: => String): Unit

    def infoRaw(bytes: => ByteString): Unit = {
      outputBuilder ++= bytes
      outputBuilder = outputBuilder.result.utf8String match {
        case content if !content.contains("\n") => outputBuilder ++= bytes
        case content =>
          val rest = content.split("\n") match {
            case Array(out, rest) => info(out); rest
          }
          ByteString.newBuilder ++= ByteString(rest, "UTF-8")
      }
    }
}

Rename JavaxEngine to just Javax?

None of the other engines have the word engine in the name, so perhaps we want to remove it from JavaxEngine to make them analagous?

Interface improvements: Reader instead of File and multiple scripts

I'm trying to port some code over to JS Engine and have run into trouble in a couple cases

One of the scripts I have is a String, but JS Engine only takes a File. Internally, JS Engine takes this File and turns it into a FileReader. It'd be nice if it just took a Reader to start because then I could pass it a FileReader, StringReader, InputStreamReader, etc. The only thing here that we'd have to account for is taking a File gives us a script name, so we'd also want to add a parameter for an optional script name.

The second thing I've run into is that my code currently executes multiple scripts on the same engine. There's not a really good way to do that with JS Engine because a new engine is created for each script. I could probably just concatenate the scripts, but then it'd be harder to debug any errors because you'd get the line number for the concatenated script instead of the original file name and line number. Of course I'm doing this with the Javax engine. I don't know if there's a way to run multiple scripts in the same Node engine or not...

JavaScript exceptions are not caught by the Rhino engine

There is no test in RhinoSpec.scala that checks that JavaScripts exceptions are correctly caught, and as a matter of fact they are not.

Consider the following:

val system = ActorSystem()
val engine = system.actorOf(Rhino.props())
val f = new File(classOf[RhinoSpec].getResource("test-node.js").toURI)
implicit val timeout = Timeout(5000L, TimeUnit.MILLISECONDS)

val futureResult = (engine ? Engine.ExecuteJs(f, immutable.Seq("999"), timeout.duration)).mapTo[JsExecutionResult]
val result = Await.result(futureResult, timeout.duration)
new String(result.error.toArray, "UTF-8").trim must_!= ""

Since we are running a node.js script inside a Rhino engine we expect some exception to be caught, but the test fails. The exception is written on stdout (Error: Module "console" not found) but not in result.error.

String as script source in addition to File

Would you accept a pull request that makes it possible to use a string as source instead of a File?

NodeEnvironment already exposes this

public NodeScript createScript(String scriptName, String script, String[] args)

but it is not exposed in Engine:

case class ExecuteJs(
                        source: java.io.File,
                        args: immutable.Seq[String],
                        timeout: FiniteDuration,
                        timeoutExitValue: Int = Int.MinValue,
                        environment: Map[String, String] = Map.empty
                        )

timeout exception after update to 1.0.0 when using timeoutExitValue=0

After having update from 1.0.0-M1 to 1.0.0, I receive timeout exception when using js-engine.

The change:
yanns/play-react@aa1098d#diff-fdc3abdfd754eeb24090dbd90aeec2ceR12

Error:

[application-akka.actor.default-dispatcher-6] [akka://application/user/engine-196] Message [akka.actor.Terminated] from Actor[akka://application/user/engine-196/stderr#-264922344] to Actor[akka://application/user/engine-196#1741387420] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'

Combine Rhino and Javax engines?

Rhino is just one case of Javax, right?. If you use Javax and are on Java 7 then you get Rhino and if you're on Java 8 then you get Nashorn. It'd be nice to deprecate Rhino and just use Javax so that folks who are on Java 8 get Nashorn.

Does not detect Node.JS on Debian or AWS by default

We require node to be on the path. See https://github.com/typesafehub/js-engine/blob/master/src/main/scala/com/typesafe/jse/LocalEngine.scala#L69

Apparently Debian calls it nodejs because there's another package named node already. That means we should probably check for nodejs first and prefer it in case the user also has node installed.

I generally don't like installing the version of node that comes with the system package manager and typically prefer nvm

Workaround for these systems: Install nodejs-legacy, which adds symlink /usr/bin/node -> nodejs.

Executing a script in a Rhino engine is affected by previous executions

Running several subsequent script executions in one or several Rhino engines yields unexpected results. This issues doesn't show currently as there is only one test in RhinoSpec. A quick way to show the problem is to extend the current test in RhinoSpec.scala with the following:

val engine2 = system.actorOf(Rhino.props())
val f2 = new File(classOf[RhinoSpec].getResource("test-node.js").toURI)
val futureResult2 = (engine2 ? Engine.ExecuteJs(f2, immutable.Seq("888"), timeout.duration)).mapTo[JsExecutionResult]
val result2 = Await.result(futureResult2, timeout.duration)
new String(result2.output.toArray, "UTF-8").trim must_== ""

Although we expect test-node.js to fail when executed in a Rhino engine, and hence the output to be empty, the above test will fail with '888' does not equal ''. If you comment out the previous test that loads test-rhino.js the issue disappear. This is actually expected behavior considering that the current implementation of Rhino.scala uses the main Rhino shell through Main.eval, which "polutes" the scope with each invocation during the JVM lifetime.

This can be fixed by using the context.evaluateReader method of executing scripts instead of the main shell. Using this method will also simplify the code and remove the need for static initialization.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.