Deploy angularjs app with capistrano on the cloud

Recently in KMPIT we've been replacing backbonejs with angularjs as our main frontend javascript library of choice. Along with angular we decided to use yeoman in managing client apps.

In this article I will show you how we deploy our angularjs app on the cloud using capistrano 3.

Before

I assume that you already have a droplet with nginx, ruby and compass installed. If not - visit this link and after following the steps described there, you will be ready to go.

I also assume that you have nodejs with npm installed on your local machine.

Generating the app

To create a basic angular app on your development machine, first install yeoman along with angular generator (you may need to use sudo for that)

update npm (if you have old version of npm yeoman installer will throw errors)

sudo npm update npm -g  

and install yeoman

sudo npm install -g yo  
sudo npm install -g generator-angular  

Having this installed, create a dir for the new app and run the following commands to bootstrap a basic app:

mkdir deployapp && cd deployapp  
yo angular --coffee  

The generator will ask you some questions whether to use Sass or include twitter boostrap (my answer is YES for both of them). At last he will ask you which modules to include, if you are new to angular just use the default options.

Please notice that I used the --coffee option to create coffeescript files instead of raw javascript.

The generator will take some time. After that run grunt serve to check whether evertything is ok on local machine - it should open web browser and point it to localhost:9000. I also notice that on some machines when errors occurs with yeoman generator - npm cache clean usually helps.

Configuring capistrano

I will not cover a detailed configuration process of capistrano (you can check it at http://capistranorb.com/), although I will present a working solution. You can check it in my github repo.

Code and building

  • First, place the generated code under a version control system (git, svn, etc.).
  • Install capistrano: gem install capistrano (be sure that it is in 3.x version by checking gem list | grep capistrano)
  • capify project: cap install in your app directory.

We will set up capistrano to work like this:

  1. Update code on the remote machine
  2. Update bower components with node modules on the remote machine
  3. Build the app on the remote machine

Now lets modify the files generated by Capistrano. We’ll start with config/deploy.rb

In the configuration part of the file define the shared folders:

set :linked_dirs, %w{node_modules app/bower_components}  

Yeoman uses bower to manage dependencies. It operates similarly to bundler, so when in a rails app we always call bundle install during deploy, in angularjs we call bower install and npm install. The task for that looks:

namespace :deploy do  
....
  task :bower_and_npm_install do 
    on roles(:app), in: :sequence, wait: 5 do
      within release_path do 
        execute :npm, "install"
        execute :bower, "install"
      end
    end
  end
  after :published, :bower_and_npm_install
....
end  

Finally we build the app:

namespace :deploy do  
....
  task :build do 
    on roles(:app), in: :sequence, wait: 5 do 
      within release_path do 
        execute :grunt, "build"
      end
    end
  end
  after :bower_and_npm_install, :build
....
end  

In previous tasks we executed bower and grunt commands. Grunt also uses compass and ruby in the background (as we previously answered YES to sass). Those commands have to be in your PATH. Let’s add them! Again in deploy.rb:

set :default_env, {  
  path: ["/usr/local/rbenv/shims",
    "#{shared_path}/node_modules/bower/bin", 
    "#{shared_path}/node_modules/grunt-cli/bin",
    "/usr/local/rbenv/versions/#{fetch(:rbenv_ruby)}/bin",
    "$PATH"].join(":")
}

I use rbenv on remote machine so thats why those rbenv lines.

You only have to fill your repo data (top of deploy.rb) and change server settings in config/deploy/staging.rb

Finally have fun!!!

Before first deploy make sure that on remote machine you have installed the latest npm (sudo npm update -g npm)

Having everything configured, deploy your code to the cloud. In console:

cap staging deploy  

First time there will be errors because there are no node_modules. So you have to log in to remote machine and run npm install yo inside yourapppath/current (which was made during the first deploy). After that cap staging deploy will work.

More

Working with data depending on environment.

In every app there are some data that depend on the environment (an API endpoint for example). This variables we will place in a separate configuration file which could look like:

window.yourAppConfig = {  
  apiHost: "http://127.0.0.1:3000"
}

On local machine create config.js and place it in app/scripts/config.js. Then prevent this file to synchronize with your version control (in git its done by adding app/scripts/config.js in .gitignore

Then on the remote machine create the same file in shared/dist/scripts/config.js and add the following line to your capistrano configuration (deploy.rb):

`set :linked_files, %w{dist/scripts/config.js}`

And now after each deploy, capistrano will create a symlink from app/scripts/config.js

To add this file in your project place:

<script src="scripts/config.js"></script>  

in index.html

All in repo

I've created a repo with all that configuration which was tested on DigitalOcean and couple of other providers. And I also wrapped everything in a gem called capistrano-yeoman