Calling Node.js script from a Rails application using ExecJS

I have a Rails application that should run a node script. I believe that using the ExecJS gem is the cleanest way to run JavaScript from a Rails application. However, for now, ExecJS has been very frustrating to use.

Here is the script I need to run:

// Generated by CoffeeScript 1.7.1 (function() { var PDFDocument, doc, fs; fs = require("fs"); PDFDocument = require('pdfkit'); doc = new PDFDocument; doc.pipe(fs.createWriteStream('output.pdf')); doc.addPage().fontSize(25).text('Here is some vector graphics...', 100, 100); doc.save().moveTo(100, 150).lineTo(100, 250).lineTo(200, 250).fill("#FF3300"); doc.scale(0.6).translate(470, -380).path('M 250,75 L 323,301 131,161 369,161 177,301 z').fill('red', 'even-odd').restore(); doc.addPage().fillColor("blue").text('Here is a link!', 100, 100).underline(100, 100, 160, 27, { color: "#0000FF" }).link(100, 100, 160, 27, 'http://google.com/'); doc.end(); }).call(this) 

From my Rails console, I'm trying to do this:

 [2] pry(main)> file = File.open('test.js').read [3] pry(main)> ExecJS.eval(file) ExecJS::ProgramError: TypeError: undefined is not a function from /Users/matt/.rvm/gems/ruby-2.1.0/gems/execjs-2.0.2/lib/execjs/external_runtime.rb:68:in 'extract_result' 

Note that I can successfully run this script using 'node test.js', and I can also run the script using the backtick syntax suggested by Ruby:

 'node test.js' 

But it looks like a hack ...

+11
javascript ruby ruby-on-rails execjs
source share
4 answers

This is a mistake because require () is not supported by EvalJS. "require" is undefined, and undefined is not a function .;)

+3
source share

I'm not sure about the answer, but maybe you need to clarify the exec_js_runtime environment variable as node.

Something like ENV['EXECJS_RUNTIME'] = 'Node' You can try putting it in config / boot.rb or just define EXECJS_RUNTIME in your environment, something like export EXECJS_RUNTIME=Node

Hope this helps

+2
source share

ExecJS users use commonjs.rb https://github.com/cowboyd/commonjs.rb

Why can't I use CommonJS require () inside ExecJS?

ExecJS provides the lowest common denominator interface for any JavaScript runtime. Use ExecJS when it doesn't matter which JavaScript interpreter of your code starts. If you want to access the Node API, you should check out another library, such as commonjs.rb, designed to provide a consistent interface.

But this does not work in principle. require is completely messy - I had to run npm -g install pdfkit fs between env = and env.require in

 require 'v8' require 'commonjs' env = CommonJS::Environment.new(V8::Context.new, path: ::Rails.root ) env.require 'script' 

to search for a module for Oo to work, and if I tried to specify path in the node_modules folder, then for the gem it would be impossible to find a script (not to mention that #new and require are basically the only documentary methods - only afaik methods - and #new mistakenly documented: P)

Your options, as far as I can tell:

  • system(node ...) - you can use Cocaine to avoid some errors (pipe output, error handling, performance tuning ...) and run cleaner syntax - this is not as bad as it seems - this is how a clip performs post-processing of images ( imagemagick system package + cocaine ), so I think it is very stable and very doable
  • put it in web api and run a separate worker on the free heroku announcer, for example, to do this and similar material that you want to do with Node libs
  • use prawn :)
+2
source share

Get rid of ExecJS and everything that depends on ExecJS. I tried all the other suggestions, but that actually fixed it.

ES6 has been around since 2015. Any tool that is worth using already supports it. MICROSOFT EDGE supports it now. Jokes aside.

0
source share

All Articles