Deploy Rails 5.1 / Webpacker app with Capistrano

The error tells you pretty much what's wrong. Neither Yarn or Node can be found on the server. Your installation might be incorrect.

Follow instructions to install both here:

https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions

and here:

https://yarnpkg.com/lang/en/docs/install/#linux-tab

Then make sure you can call:

yarn
node

On the server. If not, you might need to add paths to executables into your PATH variable


I prefer to compile assets locally and then copy to the production servers with rsync:

# lib/capistrano/tasks/precompile.rake
namespace :assets do
  desc 'Precompile assets locally and then rsync to web servers'
  task :precompile do
    run_locally do
      with rails_env: stage_of_env do
        execute :bundle, 'exec rake assets:precompile'
      end
    end

    on roles(:web), in: :parallel do |server|
      run_locally do
        execute :rsync,
          "-a --delete ./public/packs/ #{fetch(:user)}@#{server.hostname}:#{shared_path}/public/packs/"
        execute :rsync,
          "-a --delete ./public/assets/ #{fetch(:user)}@#{server.hostname}:#{shared_path}/public/assets/"
      end
    end

    run_locally do
      execute :rm, '-rf public/assets'
      execute :rm, '-rf public/packs'
    end
  end
end

# config/deploy.rb
after 'deploy:updated', 'assets:precompile'

In your Capfile you need to include all the capistrano tasks:

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob('lib/capistrano/tasks/**/*.rake').each { |r| import r }

This eliminates the need to install node and yarn on the production servers.

Of course you need node and yarn installed locally


What worked for me was making sure NVM was included in the PATH. By default, in a bash terminal, NVM adds its environment variables to the end of ~/.bashrc, but much of that file is not usually executed in a non-interactive terminal (which Capistrano runs in). I found this comment helpful:

Put your NVM source script in your .bashrc which is still evaluated even during an non-interactive SSH session. Just make sure you place the declarations at the top, before the case statement:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac