How to deploy a Vue.js app to Heroku

10.09.2016

This is the quickest way that I have found to deploy a Vue + webpack app that was generated by the vue-cli to Heroku. The idea is to have Heroku build the app and serve it with express in minimal time.

Step 1. Add these postinstall and start hooks to your package.json scripts section:

"postinstall": "npm run build",
"start": "node server.js"

Step 2. Create a server.js file in the root of your app:

var express = require('express')
var path = require('path')
var serveStatic = require('serve-static')

var app = express()
app.use(serveStatic(path.join(__dirname, 'dist')))

var port = process.env.PORT || 5000
app.listen(port)
console.log('server started ' + port)

Step 3. Configure Heroku to install dev dependencies:

This step is required to get the necessary packages installed to run and serve the build on Heroku, since all the required packages were placed into devDependencies when the app was generated.

$ heroku config:set NPM_CONFIG_PRODUCTION=false

The alternative to this step would be to move all the devDependencies into dependencies.

Sources

https://medium.com/@sagarjauhari/quick-n-dirty-way-to-deploying-vue-webpack-apps-on-heroku-4ab964ee536#.uer4mup5h
https://devcenter.heroku.com/articles/nodejs-support

7 Tips for Recent Coding Bootcamp Grads

05.24.2016

Not too long ago, I had a recent coding bootcamp grad message me for advice. I figured my response to him might help some other people out there in the same situation. Here was my response:

Hi S. Thanks for the message. Congrats on finishing the bootcamp. For someone starting out in programming, I would recommend a few things.

1. Keep working on interesting projects and finish what you start. Continue pushing to github. Projects must get progressively more challenging and impressive.

2. Build a portfolio website and post all of your projects there. Having a site makes it easier to sell your skills during interview.

3. Practice difficult programming problems. Do “code katas” on codewars.com, topcoder, project euler etc. This will help with those interview questions.

4. Take online courses. I recommend code school, pluralsight, and coursera. Then apply what you learn in projects.

5. Read a lot of programming books.

6. Watch screencasts. These are useful when you’re working on projects and need to figure out how to implement a specific feature.

7. Build your “brand” and online presence. Start a blog and write about programming stuff. Fill in linkedin with projects and clients. Get testimonials. Etc.

Hope this information helps. And good luck on the job application and job search.

Convert Exported Evernote HTML Files Into Text Files

06.03.2015

I’ve been using Evernote for a while, and I think it’s great. It makes it easy to flip through notes and has a super useful full text search feature. While they do have a way to import text files, they don’t have a way to export to text. Here is a ruby script I wrote to convert their exported HTML files into text:

require 'nokogiri'

my_notes_dir = File.expand_path(ARGV[0])

Dir.chdir(my_notes_dir)
Dir.chdir("..")
Dir.mkdir("evertextfiles") unless File.directory?("evertextfiles")
evertextfiles_dir = File.expand_path("evertextfiles")
Dir.chdir(my_notes_dir)
Dir.glob("*.html") do |filename|
  Dir.chdir(my_notes_dir)
  new_filename = filename.sub(".html", "") + ".txt"
  File.open(filename, "r") do |f|
    html = Nokogiri::HTML(IO.read filename)
    text = html.at('body').inner_text
    Dir.chdir(evertextfiles_dir)
    File.open(new_filename, "w") do |new_file|
      new_file.puts text
    end
  end
end

To run it:

ruby evertext.rb path/to/notes

Lessons Learned Building a Rails App With Wildcard Subdomains

05.11.2015

I recently launched my first software as a service web app called MicroSweepstakes, which allows you to build a simple sweepstakes website and have it hosted on a subdomain of microsweepstakes.com. This follows the same pattern as other do it yourself site builders like Squarespace, Weebly, WordPress, Wix, etc. There were a few key things I learned in the process.

Some DNS services support wildcard domains

I first bought a domain on DreamHost, but quickly learned that DreamHost did not support wildcard domains. According to the forums, you can activate wildcard domains, but you will have to use their VPS services and then go through the process of contacting DreamHost support. I did initially try to work with support to get the wildcard domains set up and pointed to my Digital Ocean IP, but eventually gave up due to the hassle. I ended up purchasing another domain on DNSimple, and the process was fairly simple. The wildcard domain I need worked right off the bat. The annual expense for DNSimple ended up being $50+, after all of their service fees, WHOIS protection, and domain renewal, as opposed to DreamHosts’ $10.95/year. The lesson here is figure out if you need wildcard subdomains before purchasing your domain. Some providers support it. Some don’t.

Two types of SSL certificates

There are two types of SSL certificates you can purchase through DNSimple/Comodo. A single subdomain SSL certificate which runs for $20/year, and a wildcard subdomain SSL certificate which runs for $100/year. Without thinking it through carefully, I purchased the single subdomain SSL certificate assuming that I would need it only for the checkout page on my web app. By purchasing the single subdomain SSL certificate, I added another layer of complexity to my multiple subdomain app. Because some pages required SSL and some didn’t, I had to work the logic into my Rails app. I figured it would have been easier to just purchase the wildcard SSL certificate to make everything work within the https protocol instead of both http and https. So that is exactly what I did. I purchased the $100 SSL certificate. Then I realized that because my app supported custom domains, which allows users to point their domain to my app, the wildcard SSL certificate for microsweepstakes.com was essentially useless, since it wouldn’t even matter because of custom domains. Essentially, each custom domain would need its own SSL certificate for the entire site to run on https. I decided to go back to using the single subdomain SSL certificate only on the user dashboard, and then disable SSL on any custom domain parts of the app. The lesson learned here is to think more about how I’m going to structure the secure parts of my app before rushing into purchasing SSL certificates.

Working with subdomains locally

There are few strategies for working with subdomains locally. Pow and lvh.me. With Pow, you can run your app on a .dev top level domain locally, for example microsweepstakes.dev. With lvh.me, you can run your subdomain on lvh.me:3000. There a few things to consider. With lvh.me, byebug and/or pry works out of the box. You just run your server and see your log output which stops if there is a byebug/pry breakpoint. The only downside is that it requires an internet connection to work. Pow, on the other hand doesn’t require an internet connection. The downsides are that it is difficult to set up and byebug/pry does not work out of the box. You’ll have to connect to the byebug/pry through the command line, and it made the app slow when connected. I would work with lvh.me so long as I have an internet connection which is 99% of the time.

Rails route constraints

Rails has some useful features for dealing with subdomains. In your routes file, you can use lambdas to add constraints to your routes. Here is an example:

# microsite routes for custom domains
get '', to: 'microsite#home', constraints: lambda { |r| !(r.host =~ /microsweepstakes.com|microsweepstakes.dev|lvh.me/) }
get ':permalink', to: 'microsite#show', constraints: lambda { |r| !(r.host =~ /microsweepstakes.com|microsweepstakes.dev|lvh.me/) }
post 'create_entry', to: 'microsite#create_entry', constraints: lambda { |r| !(r.host =~ /microsweepstakes.com|microsweepstakes.dev|lvh.me/) }

# microsite routes for microsite domain
get '', to: 'microsite#home', constraints: lambda { |r| r.subdomain.present? && r.subdomain != 'www' }
get ':permalink', to: 'microsite#show', constraints: lambda { |r| r.subdomain.present? && r.subdomain != 'www' }
post 'create_entry', to: 'microsite#create_entry', constraints: lambda { |r| r.subdomain.present? && r.subdomain != 'www' }

The lambda places a condition for the route by accessing the request object, so you can route requests based on the subdomain and/or host name.

Conclusion

Working with dynamic subdomains and SSL certificates can get extremely complicated with many gotchas. Think carefully about your SSL needs before spending your money. Make sure your DNS provider supports wildcard domains before registering, if you need wildcard subdomains. Use lvh.me to work with subdomains. Use lambdas to place constraints on routes.

SSL Certificate, Nginx, Ruby on Rails

04.24.2015

Prerequisites. You have google apps set up and can already received e-mails from admin@yoursite.com.

Purchase an SSL certificate from DNSimple.

Follow instructions sent to admin@yoursite.com for domain control validation.

In production.rb, change the force_ssl option to true.

config.force_ssl = true

Download your certificates from DNSimple. It can take up to an hour before they appear.

Rsync your SSL certificates to your server.

$ rsync -av www_yoursite_com.pem deploy@yoursite.com:~/ssl/
$ rsync -av www_yoursite_com.key deploy@yoursite.com:~/ssl/

On the server, move the certs into /etc/nginx/ or wherever you want to put them.

$ sudo mv ~/ssl/www_yoursite_com.pem /etc/nginx/
$ sudo mv ~/ssl/www_yoursite_com.key /etc/nginx/

Edit your Nginx configuration found in /etc/nginx/sites-available.

The proxy_set_header X-Forwarded-Proto https; is necessary to prevent an infinite redirect loop.

upstream app {
  server unix:/tmp/unicorn.yoursite.sock fail_timeout=0;
}
server {
  listen 443;

  ssl on;
  ssl_certificate /etc/nginx/www_yoursite_com.pem;
  ssl_certificate_key /etc/nginx/www_yoursite_com.key;

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  server_name www.yoursite.com yoursite.com;
  root /var/www/yoursite/current/public;
  try_files $uri/index.html $uri @app;
  location @app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app;
  }
  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

Restart Nginx.

$ sudo /etc/init.d/nginx restart

Sources

http://stackoverflow.com/questions/14930452/too-many-redirects-error-while-trying-to-configure-rails-application-as-ssl-usin

http://seaneshbaugh.com/posts/configuring-nginx-and-unicorn-for-force_ssl

Ruby on Rails, Sending Email with sendmail on Ubuntu VPS

04.05.2015

config/environments/production.rb

config.action_mailer.delivery_method = :sendmail
config.action_mailer.default_url_options = { host: "yourdomain.com", port: 25}

Install sendmail

$ sudo apt-get install sendmail

Configure hosts file correctly:

$ nano /etc/hosts

And make sure the line looks like this:

127.0.0.1 localhost localhost.localdomain yourhostnamehere

Run hostname if you don’t know your hostname.

Reload /etc/hosts, so that the previous changes take effect

sudo /etc/init.d/networking restart that works but seems to be deprecated, better use:

$ /etc/init.d/networking stop
$ /etc/init.d/networking start

Run the sendmail config and answer ‘Y’ to everything:

$ sendmailconfig

Sources
https://holarails.wordpress.com/2013/11/17/configure-sendmail-in-ubuntu-12-04-and-make-it-fast/

http://collinhenderson.com/post/48046976172/a-fix-for-slow-sendmail-on-ubuntu

Ruby on Rails, Nginx, Unicorn, Postgresql, Capistrano

03.21.2015

This is a step-by-step guide for anyone who is trying to learn the basics of setting up Ruby on Rails, Nginx, Unicorn, and Postgresql to run on a VPS and use Capistrano to automate deployment. For this tutorial, we will use Digital Ocean as the VPS provider because it is cheap, fast, and simple to use.

Software versions used in this tutorial:

Ruby 2.1.3
Rails 4.2.0
Postgresql 9.3.6
Ubuntu 14.04 x64
Nginx 1.4.6
Unicorn 4.8.3
Capistrano 3.4.0

For reference, here is the git repo of this deploydemo app:

https://github.com/travisluong/deploydemo

Step 1: Preparation.

Spin up a Digital Ocean droplet with Ubuntu 14.04 x64.

Create a new repository on GitHub or Bitbucket. You’ll need this for Capistrano to pull from during deploys.

Step 2: Create a simple Rails app.

Create a new rails app. We will set the database to postgresql.

user@local $ rails new deploydemo -d postgresql

Commit and push app to git origin.

user@local $ cd deploydemo
user@local $ git init
user@local $ git add .
user@local $ git commit -m "initial commit"
user@local $ git remote add origin git@github.com:travisluong/deploydemo.git
user@local $ git push origin master

Run bundle to install dependencies.

user@local $ bundle

Create postgresql database for development.

user@local $ createdb deploydemo_development

Create a rails scaffold

user@local $ bin/rails g scaffold post title content:text
user@local $ bin/rake db:migrate

Set the root to the scaffold index in config/routes.rb.

root 'posts#index'

commit the changes.

user@local $ git add .
user@local $ git commit -m “scaffold"

Step 3: Install and configure Capistrano and Unicorn.

Add these gems to Gemfile.

gem 'unicorn'
group :development do
  gem 'capistrano-rails'
  gem 'capistrano-rvm'
  gem 'capistrano3-unicorn'
end

Run bundle.

user@local $ bundle

Install Capistrano. This will create some files.

user@local $ cap install

In config/deploy.rb, set the application, repo_url, deploy_to with your settings. You can uncomment linked_files, and linked_dirs. You might also want to set format to pretty and log level to info to get rid of some unimportant (failed) messages from Capistrano.

set :application, 'deploydemo'
set :repo_url, 'git@github.com:travisluong/deploydemo.git'
set :deploy_to, '/var/www/deploydemo'
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :format, :pretty
set :log_level, :info

Add require statements in Capfile. This will make it work with RVM and add extra rake tasks to Capistrano.

require 'capistrano/rails'
require 'capistrano/rvm'
require 'capistrano3/unicorn'

Add server to config/deploy/production.rb. You can find the server IP from your Digital Ocean dashboard. You’ll also want to set the unicorn_rack_env to production, since the gem uses “deployment” environment by default for some reason.

server '162.xxx.xxx.xx', user: 'deploy', roles: %w{app db web}
set :unicorn_rack_env, -> { "production" }

Commit changes.

user@local $ git add .
user@local $ git commit -m "capistrano"

Create a the unicorn configuration file in config/unicorn/production.rb.

working_directory '/var/www/deploydemo/current'
pid '/var/www/deploydemo/current/tmp/pids/unicorn.pid'
stderr_path '/var/www/deploydemo/log/unicorn.log'
stdout_path '/var/www/deploydemo/log/unicorn.log'
listen '/tmp/unicorn.deploydemo.sock'
worker_processes 2
timeout 30

before_fork do |server, worker|
  old_pid = "/var/www/microsweepstakes/current/tmp/pids/unicorn.pid.oldbin"
  if old_pid != server.pid
    begin
    sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
    Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

Here is what this file is doing:

  1. Set the working directory of the app.
  2. Set the unicorn pid file location. That contains the id of the unicorn process.
  3. The unicorn log files.
  4. The socket file that connects to Nginx.
  5. The number of workers each master process will spawn.
  6. The amount of time a request is given before Unicorn kills the process.
  7. A before fork that kills the old process when a new process is started, so we can achieve zero downtime deploys.

Commit changes and push to origin.

user@local $ git add .
user@local $ git commit -m "unicorn"
user@local $ git push origin master

Step 4: Create a deploy user on your VPS.

ssh in to remote server.

user@local $ ssh root@162.xxx.xxx.xx

Create a deploy user and give sudo privileges. You can leave all the fields blank, except for password.

root@remote $ adduser deploy
root@remote $ adduser deploy sudo

Switch to deploy user.

root@remote $ sudo su deploy

Step 5: Set up all of the SSH keys.

CD into home and make a .ssh directory.

deploy@remote $ cd
deploy@remote $ mkdir .ssh

Copy your ssh key from local over to remote for password-less login.

user@local $ cat ~/.ssh/id_rsa.pub | ssh -p 22 deploy@162.xxx.xxx.xx 'cat >> ~/.ssh/authorized_keys'

Follow the instructions in the link below to add an ssh key to GitHub for your remote VPS. You need to do this so that Capistrano can pull the application from GitHub on deploys. The commands in this guide should be run on the VPS as your deploy user.

https://help.github.com/articles/generating-ssh-keys/

Step 6: Install packages and dependencies.

Run update.

deploy@remote $ sudo apt-get update

Install packages.

deploy@remote $ sudo apt-get install -y curl git-core build-essential zlib1g-dev libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libcurl4-openssl-dev libxml2-dev libxslt1-dev python-software-properties

Install node.js for JavaScript runtime.

deploy@remote $ sudo apt-get install -y nodejs

Install Postgresql. libpq-dev is needed for building the pg gem later.

deploy@remote $ sudo apt-get install -y postgresql postgresql-contrib libpq-dev

Install nginx. If you navigate to your IP in your browser, you should see an nginx welcome page.

deploy@remote $ sudo apt-get install -y nginx

Step 7: Set up the postgres user and create production database.

Create the production database.

deploy@remote $ sudo -u postgres createdb deploydemo_production

Set up password for “postgres” user.

deploy@remote $ sudo -u postgres psql
postgres=# \password postgres
postgres=# \q

Step 8: Install RVM, ruby, and bundler.

Add a line to your .gemrc to turn off document generation. Document generation takes way too long.

deploy@remote $ echo "gem: --no-document" >> ~/.gemrc

Install rvm and ruby.

deploy@remote $ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
deploy@remote $ \curl -sSL https://get.rvm.io | bash -s stable
deploy@remote $ source /home/deploy/.rvm/scripts/rvm
deploy@remote $ rvm install 2.1.3

Install bundler.

deploy@remote $ gem install bundler

Step 9: Create the directories and shared files needed for Capistrano deployment.

Make /var/www directory in remote.

deploy@remote $ sudo mkdir /var/www

Change the owner of /var/www to deploy.

deploy@remote $ sudo chown deploy /var/www

Make the shared config directory.

deploy@remote $ mkdir -p /var/www/deploydemo/shared/config

Make log directory for unicorn log.

deploy@remote $ mkdir -p /var/www/deploydemo/log

Create the shared database.yml file that will be shared between releases.

deploy@remote $ sudo vim /var/www/deploydemo/shared/config/database.yml
production:
  adapter: postgresql
  encoding: unicode
  pool: 5
  timeout: 5000
  database: deploydemo_production
  username: postgres
  password: password
  host: localhost

Run rake secret to generate a secret key. You will put that in the shared secrets.yml file.

user@local $ bin/rake secret

Create the shared secrets.yml file and put in the secret key you generated in the last step.

deploy@remote $ sudo vim /var/www/deploydemo/shared/config/secrets.yml
production:
  secret_key_base: 94d04182d80fe4ea1ec41b6839b019a02e8a3f8cfa0696ee3b5281d5512473c8483334b23f31bd7fcdf3914263d0719c819494613e3d6ffb1792a45b6277da66

Add the RAILS_ENV variable to .bashrc so Unicorn can load the right environment.

deploy@remote $ echo 'export RAILS_ENV=production' >> ~/.bashrc
deploy@remote $ source ~/.bashrc

Run cap production deploy:check to make sure all your files and directories are in place. Everything should be successful.

user@local $ cap production deploy:check

Step 10: Configure and restart Nginx.

Back up the default file. I put it in home directory for now.

deploy@remote $ sudo mv /etc/nginx/sites-available/default ~

Create a new nginx default file with these settings. Note that the socket is the same one specified in the Unicorn configuration.

deploy@remote $ sudo vim /etc/nginx/sites-available/default
upstream app {
  server unix:/tmp/unicorn.deploydemo.sock fail_timeout=0;
}
server {
  listen 80;
  server_name localhost;
  root /var/www/deploydemo/current/public;
  try_files $uri/index.html $uri @app;
  location @app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app;
  }
  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

Restart nginx.

deploy@remote $ sudo service nginx restart

Step 11: Deploy the app.

Run cap production deploy. First time will take a while since it has to run bundle and install all dependencies.

user@local $ cap production deploy

Start the unicorn workers.

user@local $ cap production unicorn:start

You should see your simple CRUD app when you go to your IP in the browser.

Conclusion

I hope you have found this guide helpful. If you see any improvements that can be made to this guide or have any questions, feel free to contact me.

Notes

If you’re having issues with symlinks, deleting the “current” symlink and running deploy again might help.

If there’s an error, look at the Capistrano output. There’s usually some information that can help you debug the problem.

Use the cap -T command to see all Capistrano commands.

Use ps aux | grep unicorn to check unicorn processes. Capistrano has some commands to stop and restart unicorn workers, but use kill [pid] to kill the process manually if needed.

Sources

http://blog.mccartie.com/2014/08/28/digital-ocean.html

http://www.gotealeaf.com/blog/deploy-rails-apps-with-capistrano/

http://matteodepalo.github.io/blog/2013/03/07/how-i-migrated-from-heroku-to-digital-ocean-with-chef-and-capistrano/

https://www.digitalocean.com/community/tutorials/how-to-use-roles-and-manage-grant-permissions-in-postgresql-on-a-vps–2

http://voiceofchunk.com/2014/06/09/deploying-rails-apps-using-passenger-rbenv-postgresql-and-mina/

http://stackoverflow.com/questions/6282307/execjs-and-could-not-find-a-javascript-runtime

http://stackoverflow.com/questions/9987171/rails-3-2-fatal-peer-authentication-failed-for-user-pgerror

https://www.digitalocean.com/community/tutorials/how-to-use-mina-to-deploy-a-ruby-on-rails-application

https://www.infinum.co/the-capsized-eight/articles/faster-web-application-deployments-using-mina-instead-of-capistrano

https://coderwall.com/p/yz8cha/deploying-rails-app-using-nginx-unicorn-postgres-and-capistrano-to-digital-ocean

http://sirupsen.com/setting-up-unicorn-with-nginx/

http://theflyingdeveloper.com/server-setup-ubuntu-nginx-unicorn-capistrano-postgres/

http://www.cubicleapps.com/articles/ubuntu-rails-ready-with-nginx-unicorn

http://benjaminknofe.com/blog/2014/03/08/zero-downtime-deployment-with-unicorn-and-capistrano/

http://stackoverflow.com/questions/19716131/usr-bin-env-ruby-no-such-file-or-directory-using-capistrano-3-capistrano-rben

http://stackoverflow.com/questions/21692601/capistrano-3-process-failing

http://railscasts.com/episodes/335-deploying-to-a-vps

 

How to Set Up a Wildcard Subdomain on Heroku

03.16.2015

Recently, I needed to get subdomains to work on Heroku for a multitenant application. It might be slightly more expensive, but I highly recommend DNSimple over other services for a few reasons. DNSimple supports ALIAS records, which allows you to use the root domain. They also support wildcard subdomains. And things just work. No need to contact support to set up wildcard domains. DNSimple makes DNS simple. Outlined below is the general process for getting the DNS stuff set up.

Step 1: Learn how to work with subdomains in Rails.

Follow instructions in railscast http://railscasts.com/episodes/123-subdomains-revised.

Step 2: Deploy your heroku app.

Step 3: Add the subdomain.

heroku domains:add *.your-domain.com

Step 4: Sign up for DNSimple account.

Step 5: Register a domain

 Click add domain.

Make sure “register or transfer this domain” is checked, otherwise you might end up adding a domain that isn’t even registered and wonder why things aren’t working.

Register the domain if it is available.

Step 6: Add Heroku service in DNSimple.

Click services and add heroku service.

Enter your heroku app.

Click on your domain.

Click on DNS.

Click Manage records.

Add a CNAME record for *.your-domain.com pointing to your-app.herokuapp.com.

Ruby on Rails Dynamic Forms

03.15.2015

I needed to create a dynamic form where users can add additional fields to save additional properties onto a model. I followed the instructions on this RailsCast: http://railscasts.com/episodes/403-dynamic-forms

Everything worked fine except for one thing. I was on Rails 4 and I needed to add all of the nested attributes to the parameter white list. You also have to add the id and _destroy as permitted parameters for the remove link to work.

Example:

def product_params
  params.require(:product).permit(:name, fields_attributes: [:name, :field_type, :required, :id, :_destroy])
end

Code School JavaScript Best Practices Notes

03.13.2015

The Sword of Syntax

Ternary Conditionals

The ternary conditional provides a shortcut over lengthier condition

Logical Assignment I: OR Assignment

The OR operator takes the leftmost “truthy” value, and if none exists, the last “falsy” value.

Logical Assignment II: AND Assignment

The && operator takes the rightmost “truthy” value or the first “falsy” value.

Switch Blocks & Fall-Through

JavaScript has an alternate way of taking action based on actual values, not just Booleans.
‘Break’ will allow us to leave the entire block of code that contains it, in this case, the switch.
Fall-through will tighten up our code if we stack similar cases before their appropriate action.
The ‘default’ case can help us watch for unavailable regiment values and alert the armorer.
A carefully organized switch block can add LEAST common properties first and MOST common, last.

The Pendant of Performance

Loop Optimization

We can use “cached values” to curtail lengthy, repetitive access to the same data.
For better organization, we can place our new control variable inside the first loop parameter.
Stick with for-loops instead of for-in loops when your goal is only to reach every index.

Script Execution

Scripts encountered high in the <head> or <body> tags of an HTML page can have adverse effects.
Scripts that are not essential to immediate loading of the page should be moved as low as possible.
With external files, the HTML5 async attribute will allow the rest of the page to load before the script runs.

Short Performance Tips

Give all common methods that a “class” of objects will use to the constructor’s prototype.
Each new addition to the DOM causes document “reflow”, which can really hinder user experience.
Fragments are invisible containers that hold multiple DOM elements without being a node itself.
Every var keyword adds a look-up for the JavaScript parser that can be avoided with comma extensions.
Anticipate variable needs to avoid the processor burden of creating a new var over and over.
For concatenations over an array’s contents, use the join() method inherited from the Array prototype.

Measuring Performance I: console.time

This timing feature can help determine the code that creates the best experience.
Since timers are created by the label you provide, creative stacking can produce layers of time data.

Measuring Performance II: Speed Averaging

We’ll use our Date object approach to calculate a more accurate performance over many code repetitions.

The Crystal of Caution

Careful Comparisons

The triple-equals comparator compares both type AND contents.
A === ensures comparison reliability in environments where data may have multiple or unknown types.
The instanceof operator helps identify objects. Use this operator to ensure you’re examining precisely the type of object that your code expects.
An object is an “instance” of all of the prototypes from which it inherits properties.

Exception Handling

A syntax error will not make it past the interpreter. It will be marked as invalid Javascript and reported in the JS console.
“run-time error” is the sort we want to catch and control.
Like other languages, Javascript offers a method for identifying and recovering from errors.
JavaScript can throw multiple useful error types that allow a catch block to “handle” errors more gracefully.
Use conditionals and the throw keyword to craft the right exception scenario based on your expectations.
Try-blocks nested within catch-blocks can organize an option sequence, should our first choice not work out.

Stuff that (Sometimes) Sucks

JavaScript’s ‘with’ keyword is somewhat unreliable and often expensive, so it is generally avoided in practice.
The with keyword takes the entire encapsulated environment of the parameter object and use it to build a new “local” scope within its bracketed block … which is kind of processing-expensive.
Nested objects are frequent in JavaScript, and ‘with’ attempts to help coders avoid typing deep access repeatedly.
As before, caching values saves the day by letting us avoid a bunch of typing, as well as being quite clear in indication.
JavaScript’s ‘eval’ keyword may not be evil, but it can affect legibility, an ability to debug, and performance.
Eval might be useful for dynamic code or uncontrollable data, but it’s still treating the string as a program to expensively compile.
Eval is most often misused for just this kind of mapping numbers to objects, but an array is much more efficient.
Chill, bro. Using eval to parse JSON data is often regarded as vulnerable and unsafe, because eval evaluates any script.
JSON.parse, or a parser library that recognizes JSON, helps to avoid both the security and performance issues posed by eval.
Just because we CAN leave curly braces off of single-statement blocks of code, doesn’t mean we should.
Requiring bracket analysis in order to ensure the proper scoping of necessary additional code will ensure your unpopularity.
In the example of conditional blocks, leaving off brackets may produce valid JavaScript and undesired executions!
For better organization, legibility, and error prevention, brackets are a two-character sacrifice that you should be making.

Number Nonsense

JavaScript uses binary floating point values to handle all of its decimal based operations.
First, the toFixed() method will allow you to select the exact amount of decimal places to display.
If dealing with percentages of money, for example, toFixed() can handle hundredths rounding for you.
A combination of toFixed() and parseFloat() will let us use values of exact length in other math operations.
Instead of looking for a floating point number, parseInt() seeks the first available integer at the front of a string.
Since parseInt() will accept octal, hexadecimal, and decimal values, caution is necessary.
When a browser version or user input is not reliable, make sure to let parseInt() what number system you expect.
Using NaN to check if values are actually JS Numbers seems like a good idea, but it will try to kill you.
If unsure about data type, but highly reliant on a Number, use typeof AND isNaN() as a best practice.
If numerical data may show up as a string, parse data before your type check and add additional checks.

The Mail of Modularity

Namespacing Basics

JavaScript files can often create conflicting global elements, overwriting existing, important data.
Though not native to JS, the namespace concept can limit global impact and provide data protection.
Using a mini-environment as a data “container”, we add a layer of protection around important data.
Namespaces reduce global “footprint” while also keeping data grouped around their intended functionality.
Nesting namespaces provide further organization and protection, as well as help keep variable names intuitive.
Our sensitive data is private by closure, and our public properties are accessible through the namespace.

Anonymous Closures

Javascript’s closure feature will allow us to “privatize” properties.
As a first visual step, we’ll wrap the entire set of properties in an anonymous immediately invoked function expression (IIFE).
Now we’ll make desired private properties into local executable code.
Here’s the money: to make some properties public, return an object.
All of the function’s local variables are “bound down” within the scope of the returned namespace object.

Global Imports

Standard global use in a module pattern causes two problems.
#1: When non-local variables are referenced in a module, the entire length of the scope chain is checked.
#2: Lengthy namespaces mean that global variables have unclear scope, leading to code that is tough to manage.
For clearer, faster globals in modules, use imports.
While devs may still need to review code, importing globals creates faster local variables that are (more) clear in source.
Imports are closed up as local variables.
An imported global variable becomes another piece of data, boxed up in the module’s closure.

Augmentation

Modules often need to have additions to their existing properties.
Augmentation provides extra properties for existing modules.
Augmented properties will have access a new private state, if used, but not to the other file’s closed data.
Best practice: group file contents around needed data.
Any cross-file private state build won’t have the level of privacy of a single closure, and often leads to hard-to-manage code.