Вызов Node.js script из приложения Rails с помощью ExecJS

У меня есть приложение Rails, которое должно запустить скрипт узла. Я полагаю, что использование драгоценного камня ExecJS - самый чистый способ запустить JavaScript из приложения Rails. Тем не менее, пока что ExecJS оказался очень разочаровывающим в использовании.

Вот скрипт, который мне нужно запустить:

// 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)

С моей консоли Rails я пытаюсь это сделать:

[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'

Обратите внимание, что я могу успешно запустить этот скрипт, используя 'node test.js', и я также могу запустить скрипт, используя синтаксис backtick, предлагаемый Ruby:

'node test.js'

Но это похоже на взлом...

Ответ 1

Это ошибка, потому что require() не поддерживается EvalJS. "require" - undefined, а undefined не является функцией.;)

Ответ 2

Я не уверен в ответе, но, возможно, вам нужно уточнить переменную среды exec_js_runtime как node.

Что-то вроде ENV['EXECJS_RUNTIME'] = 'Node' Вы можете попробовать поместить его в config/boot.rb или просто определить EXECJS_RUNTIME в своей среде, что-то вроде export EXECJS_RUNTIME=Node

Надеюсь, что это поможет

Ответ 3

Пользователи ExecJS используют commonjs.rb https://github.com/cowboyd/commonjs.rb

Почему я не могу использовать CommonJS require() внутри ExecJS?

ExecJS обеспечивает самый низкий общий интерфейс знаменателя для любого Время выполнения JavaScript. Используйте ExecJS, когда неважно, какой JavaScript интерпретатор вашего кода запускается. Если вы хотите получить доступ к API Node, вы должен проверить другую библиотеку, такую ​​как commonjs.rb, предназначенную для обеспечения согласованный интерфейс.

Но это не работает в принципе. require действует полностью беспорядочно - мне пришлось выполнить npm -g install pdfkit fs между env = и env.require в

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

для поиска модуля для работы Oo, и если бы я попытался указать path в папку node_modules, то для драгоценного камня было бы невозможно найти script (не говоря уже о том, что #new и require являются в основном единственными документальными методами - только методы afaik - и #new ошибочно документированы: P)

Ваши варианты, насколько я могу судить:

  • system(node ...) - вы можете использовать Cocaine, чтобы избежать некоторых ошибок (вывод трубопроводов, обработка ошибок, настройки производительности...) и запускать более чистый синтаксис - это не так плохо, как кажется - вот как скрепка выполняет постобработку изображений (imagemagick системный пакет + cocaine), поэтому я думаю, что это очень стабильно и очень выполнимо
  • выложите в веб-api и запустите отдельного рабочего на бесплатном дикторе heroku, например, чтобы сделать это и аналогичный материал, который вы хотите сделать с Node libs
  • использовать prawn:)

Ответ 4

Избавьтесь от ExecJS и всего, что зависит от ExecJS. Я попробовал все другие предложения, но это на самом деле исправило.

ES6 существует с 2015 года. Любой инструмент, который стоит использовать, уже поддерживает его. MICROSOFT EDGE поддерживает это сейчас. Шутки в сторону.