-->

Rails/Passenger/Node.js: ExecJS “Could not find a

2020-08-12 17:56发布

问题:

I'm trying to use Node.js as the JavaScript runtime for my Rails application. I'm using the Phusion Passenger module with Nginx as my web server on Ubuntu 12.0.4. Every time I visit my Rails application I get an error page that appears to be generated from Passenger stating that ExecJS can't find a JavaScript runtime. I've seen numerous posts on here that either suggest that you install Node--which I have done via sudo apt-get install node--or suggest using therubyracer + execjs in your Gemfile. That latter solution does in fact work, but I would really prefer to use Node, especially since Heroku has stated that they discourage the use of therubyracer do to the fact that it uses a "very large amount of memory".

I ran into a tutorial which suggests that the user that my web server runs as may not have Node in it's path. I checked this out by running sudo -u www-data which node and it returns /usr/bin/node. The user www-data is the user that nginx runs as, and the user that owns all the files in my Rails application. I've also looked at /etc/environment, and I can see that /usr/bin is in the system-wide path. Running sudo -u www-data node -v also returns the Node version as expected, so it is executable.

When I run RAILS_ENV=production bundle exec rake assets:precompile I don't get any errors. When I load ExecJS into an interactive session with IRB I'm able to get it to return a valid runtime. I've also tried explicitly adding EXECJS_RUNTIME=Node as an environment variable, but then it just says "Node.js (V8) runtime is not available" instead. I've tried many things and I just can't get this to work!

Here's the error I get when I visit my Rails app. When I look at the Nginx log file I see pretty much the same thing.

Web application could not be started

Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
  /usr/lib/ruby/gems/2.1.0/gems/execjs-2.0.2/lib/execjs/runtimes.rb:51:in `autodetect'
  /usr/lib/ruby/gems/2.1.0/gems/execjs-2.0.2/lib/execjs.rb:5:in `<module:ExecJS>'
  /usr/lib/ruby/gems/2.1.0/gems/execjs-2.0.2/lib/execjs.rb:4:in `<top (required)>'
  /usr/lib/ruby/gems/2.1.0/gems/uglifier-2.5.0/lib/uglifier.rb:3:in `require'
  /usr/lib/ruby/gems/2.1.0/gems/uglifier-2.5.0/lib/uglifier.rb:3:in `<top (required)>'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:76:in `require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:76:in `block (2 levels) in require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:72:in `each'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:72:in `block in require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:61:in `each'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:61:in `require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler.rb:132:in `require'
  /srv/www/app/config/application.rb:7:in `<top (required)>'
  /srv/www/app/config/environment.rb:2:in `require'
  /srv/www/app/config/environment.rb:2:in `<top (required)>'
  config.ru:3:in `require'
  config.ru:3:in `block in <main>'
  /usr/lib/ruby/gems/2.1.0/gems/rack-1.5.2/lib/rack/builder.rb:55:in `instance_eval'
  /usr/lib/ruby/gems/2.1.0/gems/rack-1.5.2/lib/rack/builder.rb:55:in `initialize'
  config.ru:1:in `new'
  config.ru:1:in `<main>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:112:in `eval'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:112:in `preload_app'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:158:in `<module:App>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:29:in `<module:PhusionPassenger>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:28:in `<main>'

回答1:

I had this problem too. This is what fixed it for me. I added this to the top of my nginx.conf

env PATH;

http://wiki.nginx.org/CoreModule#env

As I zeroed in on this solution I also found this post which helped me start barking up the right tree: https://forums.freebsd.org/viewtopic.php?&t=35539 -- he edits the execjs code to give an absolute path to node. This worked and helped me find out how to give the path to passenger.



回答2:

So, I found the issue.

First, my installation of Node was not for all users. That said, it was installed and available for the user that Nginx was supposed to be run as. Still, you need to remember to have this in your nginx.conf:

user  ec2-user;
...

http {
    passenger_root /usr/local/rvm/gems/ruby-2.1.0/gems/passenger-4.0.42;
    passenger_ruby /usr/local/rvm/gems/ruby-2.1.0/wrappers/ruby;
    passenger_nodejs /usr/local/bin/node;
    passenger_default_user ec2-user;
...

Second, you also need to make the path to Node available for non-login shells, ie add it to /etc/bashrc and export.

Your environment may be different, but this is the gist.



回答3:

Spoke too soon in my above comment. Things were working fine on my Hello World Rails app (4.1, with the default Gemfile and config), I stopped the EC2 instance to snapshot it, then upon reboot, I ran into that Exec.js error despite node (~ 0.11) being installed at /usr/local/bin

However, I edited my `/etc/sudoers/ file from

Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin

to:

Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

I restarted the server and Apache and things were working as expected.