# Deploying to Heroku
This project could be deployed in a number of ways, but for this excercise I decided to stick with Heroku, since it makes deploying Node apps very easy and free.
You can do the following steps using the Heroku dashboard, but since you will need the Heroku CLI to push the production files to the cloud, you might as well get started in the terminal.
# Getting started
Create an account on Heroku
Download and install the Heroku CLI
Log-in with your credentials:
$ heroku login
- Create a new application:
$ heroku apps:create --region eu
If you're in the US or elsewhere, you can view a full list of available regions here. Locations marked Private Spaces are only available for Heroku Enterprise accounts.
Open your local
.env
file and replace the name of the app inHEROKU_APP=your-app-name
Add the free Sandboxed version of the mLab add-on by replacing
your-app-name
with the name of your app in the following command:
$ heroku addons:create mongolab --app your-app-name
- Get the
MONGODB_URI
:
$ heroku config
- Copy the
MONGODB_URI
to your local.env
file and you should be good to go.
# Pushing to Heroku
Start the deployment:
$ npm run deploy:heroku
This will automatically build the current project and deploy the compiled files using a simplified version of package.json
located in the dist
folder. The process should abort if there are any errors or something is missing from the .env
file.
You might get prompted for your login information again as it uses a temporary Git repository to push the content to Heroku.
The entire process should take about 45 seconds to complete.
# Deployment process explained
There were several different approaches I could have taken to deploy this project to Heroku:
- Push the entire project to Heroku and let it do all the work
This turned out to be too slow and frankly made less sense at every push when I tried to make it work.
- Create a release using GitHub releases and instruct Heroku to fetch the files from there
This felt a bit too official and would have involved spending more time learning how the releases API works to automate the process.
- Create a tarball, figure out a place to host it and instruct Heroku to fetch the compiled project from there
Again, a lot of work and the need to have extra hosting for the tar files.
- Create a separate branch in the same Git repository as this project and create a new commit with only the static files included
Switching back and forth between a master branch and a deployment branch didn't seem very logical.
- Create a temporary Git on the local machine and push the compiled files from there
A bit hacky, but it turned out to be the easiest choice by far
At first I would have been perfectly happy pushing the entire project to Heroku without the production files included hoping that Heroku would be able to build them on-the-fly using the versions specified in the package.json
file and serve the generated files after the build process was complete. This had some unforseen obstacles such as not working and being extremely slow, but more importantly it exposed the whole process to a variety of side-effects that were out of my control.
The whole point in deploying a production-ready application is to have it tested, built and re-tested before pushing it somewhere where it can do its magic. Having Heroku do all the hard work seemed pointless, since it had already been done and tested. All that was needed was to figure out a way to push the compiled files to the remote server.
As I was going through the documentation for VuePress, I came over their long list of deployment methods and created my own script that did more or less the same. What VuePress does is to nuke the dist
folder entirely, regenerate it and have a script create a temporary Git repository inside it which pushes the built files to a remote Git repository where they get served as static files on the web.
Here's what I came up with:
#!/usr/bin/env bash
# Color definitions
blue=`tput setaf 12`
bold=`tput bold`
cyan=`tput setaf 6`
dim=`tput dim`
normal=`tput sgr0`
white=`tput setaf 8`
# Abort on errors
set -e
echo "Deploying to ${bold}Heroku${normal}..."
# Export .env variables
export `cat .env | xargs`
# Make sure the HEROKU_APP variable exists in the .env file
# or else the script won't know where to deploy the files
if [ ! $HEROKU_APP ]; then
echo
echo "${bold}Aborting. ${blue}HEROKU_APP${normal} missing."
echo
echo "Add the following to the ${cyan}.env${normal} file located in the root folder of this project:"
echo "${bold}HEROKU_APP=your-app-name${normal}"
echo
echo "Replace ${cyan}your-app-name${normal} with the name of your Heroku application."
echo
echo "${dim}${white}For more information, see the documentation:"
echo "${normal}https://phoenix2k.github.io/vue-microblog-ts/deployment/${normal}"
echo
exit
else
echo
echo "Application detected: ${bold}${HEROKU_APP}${normal}"
echo
echo "Proceed with deployment?"
select yn in "Yes" "No"; do
case $yn in
Yes ) break;;
No ) exit;;
esac
done
fi
# Make the client and server ready for production
npm run build
# Navigate the dist directory where the production files are located
cd dist
# Generate a package-lock.json file with the dependencies
# specified in the second package.json file meant for Heroku
npm install
# Remove the temporary Git repository if it was left behind
# from a previous deployment process
if [ -d ./.git ]; then
rm -rf .git
fi
# Create a temporary Git repository for deployment
git init
echo
git add -A
git commit -m 'Deploy production files to Heroku'
echo
heroku git:remote -a $HEROKU_APP
echo
git push -f heroku master
# Remove the temporary Git repository to avoid interferance
# with the main .git repository located in the root
rm -rf .git
cd -
Hopefully this example will have given you ideas on how to push your own files to production. If you've figured out an even easier way to do this or see something wrong with this process, please drop me a line in the issues section here on GitHub.
Big thanks to the VuePress team for pointing me in the right direction!