Testing, building, and deploying your NuxtJS site for free with GitHub Actions and Heroku

This post is also available in: Español (Spanish)

You have made a new rockstar website, blog or personal portfolio using NuxtJS? This post will show you how can you publish it for free using Heroku.

Remember whilst hosting the application is free, you still will have to buy a domain from any registrar if you want to have something like myapp.com. Heroku provides a subdomain like example-app.herokuapp.com for free.

In this post we will be covering how to deploy a Javascript application using the NuxtJS framework, these steps can be used in any modern Javascript framework. It is possible that will not work out-of-the-box, and you should adjust some config.

First steps

Our NuxtJS application

I assume you already have your NuxtJS running nicely in your local development machine, for this example, we will create a new one using the create-nuxt-app in npx.

$ yarn create nuxt-app example-app-for-deploy-in-heroku

We will be using Jest as our testing framework, but you can use the one with which you feel most comfortable.

GitHub Repository / Account

You should have your code in a repository, does not matter if it is public or private.

It will be enough having a Free account from GitHub, with this kind of account, we will have 2.000 minutes for running our actions (test).

Create your Heroku account and app

Like in GitHub, it will be enough with having a free account, but it has some limitations like:

  • Our app will start on the first request and it will sleep after 30 mins of inactivity.
  • If you need to use a custom domain, it will not have SSL.
  • You only have up to 1.000 dyno hours per month

If any of those limits bothers you, you can use the $7 Hobby plan, your app will be always running with custom domain and SSL.

In this post we will use Free version, so create new account and create your first Heroku app

We need to set up some environment variables to make it to work in Heroku, so go to the Settings, click on Reveal Config Vars and set HOST to 0.0.0.0. This tells the app to listen in any IP Address, as Heroku will be responsible of giving a private IP address to our host.

Prepare your code for Heroku

Heroku will rely on your package.json file to choose the best environment for your application, so we need to make a few changes:

PORT environment variable.

In Heroku you are not able to choose the port where your application should listen (Heroku will route traffic from both 80 & 443 ports to this internal port). So, check you are not overriding the PORT environment variable anywhere. You can test this using the command:

$ PORT=3333 yarn dev

If you see something like this, everything will work seamlessly:

ℹ Listening on: <http://localhost:3333/>

NodeJS Engine version

You should tell Heroku which version of NodeJS should run, this can be done using the package.json file:

{
  ...
  "engines": {
    "node": "12.x"
  },
  "dependencies": {
    ...
  },
  ...
}

Also, you can define the required versions for yarn or npm.

Building the NuxtJS application

As Heroku will pull our source code from GitHub, it should be built before running yarn start.

To do this, Heroku has some hooks that can be set in the package.json file. By default, it will use the build command, but if you need something different for deploy, Heroku will use the heroku-postbuild command instead.

Create the production branch

We should not deploy our code from the main branch in our repository, so we will create a new branch called production. Only when this branch receives a commit the deploy will be started.

Connecting Github & Heroku

Focus again on the Heroku page we left in the previous section and choose GitHub as Deployment Method.

Once connected, choose your repo, the production branch, and enable automatic deploys.

Now, click on the Deploy Branch button to make our first deploy.

You can check the deployment log in the Overview tab, on the Latest activity section. Once you see the Build succeeded message, your app will be up and running, click on the Open app button and… tada!

Running tests before going live

You do not want to publish an updated version of your site if it does not pass the test suite 🙄. This is extremely easy to avoid using GitHub Actions.

The first step is going back again in the Deploy section, and make sure the Wait for CI to pass before deploy is checked. This changes the automatic deployment behaviour and waits until GitHub marks the commit as valid after running the associated actions.

Now, we will setup an action to allow GitHub run our test suite, so create a new file in the .github/workflows directory. We will call it ci.yml.

We will not dive deeper in how GitHub Actions work, as it would cover hundreds of posts, but we will explain what each block does:

name: ci
on:
  push:
    branches:
      - production

This block only sets name for this action and tells GitHub to run this action on each push to production. You can use also on each pull_request if you want.

jobs:
  ci:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        node: [12] 

Here we set up which environment we will be using, in our case an Ubuntu Linux distro, and the node version 12, same as in our package.json.

steps:
      - name: Checkout
        uses: actions/checkout@master

This action gets the source code from the commit (Note the @master is the version for the action, not our master branch).

steps:
...

      - name: Setup node env
        uses: actions/setup-node@v2.1.2
        with:
          node-version: ${{ matrix.node }}

      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        run: echo "::set-output name=dir::$(yarn cache dir)"

      - name: Cache node_modules
        uses: actions/cache@v2
        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-

These three steps set prepares the node environment and sets a cache directory for yarn. This will speed up our process in the following deploys, as we will not need to download again all the required dependencies.

steps:
...

      - name: Install dependencies
        run: yarn

      - name: Run tests
        run: yarn test

As a last step, we will install our dependencies and run our test suite.

If any process fails, the action will stop and no deploy will be made. So, upload this file to your repository and make your first merge to production. In this case, the Actions tab will show the result:

If everything went OK, Heroku will start building your app, in case something fails, you will receive an alert from Github and deployment will not be placed.

You have here the example NuxtJS demo repository.

Hope this helps you to show the world your shiny precious job 🥰.