You Should Publish Your Next.js App to GitHub Pages

Written by msokola | Published 2024/02/20
Tech Story Tags: programming | next.js-to-github-pages | open-source-2048-game | 2048-game-source-code | 2048-source-code-github | 2048-source-code-github-pages | how-to-activate-github-pages | hackernoon-top-story

TLDRLearn how to can deploy Next.js apps to GitHub Pages and why it's a viable option for hosting your Open Source Software or your portfolios. You can publish your own project to GitHub Pages in less than 10 minutes.via the TL;DR App

Recently I revamped my open source version of 2048 Game and decided to migrate it to Next.js and React 18. The existing game was published to GitHub Pages without any custom domain. I was considering to deploy to Vercel but it would lose organic traffic from Google which was build up over the last 3 years. It means I needed to experiment with deployment to GitHub Pages and today I will share what i learnt.

If you want to see the end result of before reading the whole article, you canĀ check it here.

Quick Intro

I will be using two GitHub features – GitHub Actions and GitHub Pages. If you haven't heard of them, let me quickly explain:

GitHub ActionsĀ are like little workflows that can do tasks on your projects. It's like having a helper that automatically does things you tell it to do. You can use Actions to run tests, for quality checks, or to build your application. In my case, I used this workflows to automate deployment pipeline.

What areĀ GitHub Pages? Think of them like a web hosting option for developers and open source projects. You can use GitHub Pages to share your portfolios, host websites of your open-source projects, or just publish your pet projects like mine.

Now let's get started.

Step 1 – Activate GitHub Pages for Your Repository

To publish our Next.js application, I needed to activate GitHub Pages for the project’s repository. You can find in the Settings tab (1 in the image below), then selectĀ PagesĀ from the menu on the left-hand side (2), and find the dropdown menu that allows us to specify the deploymentĀ SourceĀ (3).

Now you will need to change the deploymentĀ SourceĀ toĀ GitHub Actions.

From now on, your project has a dedicated page. You only need to publish content there.

Step 2 – Configure the Next.js Build Process

Before deploying the Next.js app, it's important to change the build output. By default, Next.js uses Node.js to run the application, and this is incompatible with GitHub Pages.

GitHub Pages is designed to host static files, which means we can publish only HTML, CSS, JavaScript (and other static files) there. So we'll need to enable static page generation in Next.js.

To do so, you will change the output mode toĀ exportĀ insideĀ next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "export",  // <=== enables static exports
  reactStrictMode: true,
};

module.exports = nextConfig;

Now after runningĀ next build, Next.js will generate anĀ outĀ folder containing static assets for your app. In the next steps, we will take this directory and upload it to GitHub Pages.

Step 3 – Fix Missing Images

The Pages are published under a sub-path of a domain and takes the project name as a sub-path. Confusing? Let's take a sneak peak into a URL of my 2048 game as an example:

https://mateuszsokola.github.io/2048-in-react/

Github created a dedicated subdomain for my user calledĀ mateuszsokola (my username). But the project is published under the sub-path, which in my case isĀ /2048-in-react. Unfortunately, this will lead to issues with missing images and styles.

By default, Next.js maps all static assets the domain. This means that theĀ favicon.icoĀ file will be resolved toĀ mateuszsokola.github.io/favicon.icoĀ instead ofĀ mateuszsokola.github.io/2048-in-react/favicon.icon.

To fix this, we can set up a path prefix by addingĀ basePathĀ inside theĀ next.config.jsĀ file:

/** @type {import('next').NextConfig} */
const nextConfig = {
  basePath: "/2048-in-react", // <=== here it is
  output: "export",
  reactStrictMode: true,
};

module.exports = nextConfig;

In my case, it isĀ /2048-in-reactĀ since my project is calledĀ 2048-in-react.
Remember to include the (/) at beginning of the project directory.

Step 4 – Create Github Actions

Next.js is producing deployment artifacts that can be published to GitHub Pages. Now it's due time to set up Github Actions to publish them. I decided the deployment into two separate actions to promote reusability:

The setup-nodeĀ action will set up Node.js and instal all dependencies. Having a standalone action for the Node.js setup will allow me to reuse it for other pipelines. For example, I have pipelines that runĀ code linterĀ andĀ tests. Probably you want to have more than one action as well.

The publishĀ action will build Next.js artifacts and publish them to GitHub Pages each time we merge code into theĀ main branch.

Let me begin by explaining theĀ setup-nodeĀ action. Here is the code:

# File: .github/workflows/setup-node/action.yml
name: setup-node
description: "Setup Node.js āš™ļø - Cache dependencies ⚔ - Install dependencies šŸ”§"
runs:
  using: "composite"
  steps:
    - name: Setup Node.js āš™ļø
      uses: actions/setup-node@v4
      with:
        node-version: 20

    - name: Cache dependencies ⚔
      id: cache_dependencies
      uses: actions/cache@v3
      with:
        path: node_modules
        key: node-modules-${{ hashFiles('package-lock.json') }}

    - name: Install dependencies šŸ”§
      shell: bash
      if: steps.cache_dependencies.outputs.cache-hit != 'true'
      run: npm ci

Important: Create this file in the Ā .github/workflows/setup-nodeĀ directory in your project. Make sure to call it action.yml.

What does this snippet do?

  1. It creates aĀ compositeĀ action. TheĀ compositeĀ action allows you to bundle multiple workflow steps into a single action. If it isn’t clear you will understand it once we get into the second action.

  2. It creates a new build environment using Node.js 20 and installs project dependencies.

These are the most important parts of theĀ setup-nodeĀ action. Now, let's move on to theĀ publish action:

# File: .github/workflows/publish.yml
name: publish-to-github-pages
on:
  push:
    branches:
      - main

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout šŸ›Žļø
        uses: actions/checkout@v4

      - name: Setup Node.js āš™ļø - Cache dependencies ⚔ - Install dependencies šŸ”§
        uses: ./.github/workflows/setup-node

      - name: Setup Pages āš™ļø
        uses: actions/configure-pages@v4
        with:
          static_site_generator: next

      - name: Build with Next.js šŸ—ļø
        run: npx next build

      - name: Upload artifact šŸ“”
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./out

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    runs-on: ubuntu-latest
    needs: build

    steps:
      - name: Publish to GitHub Pages šŸš€
        id: deployment
        uses: actions/deploy-pages@v4

Create this file in theĀ .github/workflowsĀ directory in your project. You can name the file as you like – I called mineĀ publish.yml.

What it does?

  1. This action is triggered each time the new code is pushed or merged into theĀ mainĀ branch.

  2. It uses theĀ setup-nodeĀ action to set up the environment. The composite action I created in the previous action. Now you know how to include your composite actions in other actions.

  3. The action has two stages: in the first stage, Next.js app is being built. In the second stage, the artifacts from the first stage are uploaded to GitHub Pages.

These are the most important aspects of the deployment pipeline. I skipped the permissions and concurrency setup since they remain unchanged for all GitHub Pages deployments.

Now, action is ready to use.

Commit and Push

After committing and pushing your changes to theĀ mainĀ branch, GitHub will automatically spin up the deployment to GitHub Pages.

To inspect the process, navigate to theĀ ActionsĀ tab (1 in the image below), and select theĀ publish-to-github-pagesĀ action from the menu on the left hand side (2).Ā You will see a all your deployments on the screen (they are calledĀ workflows).

Now select the first one of those workflows, and you will see a two-stage deployment. In theĀ deployĀ stage, you can find a link to your website on GitHub Pages.

Conclusion

Github Pages isn't sufficient for hosting websites with millions of views. But it's an perfect choice to host your portfolio or a website for your open-source project.

There are many free options to host our websites such as Vercel, but I wanted to show you an alternative. GitHub Pages is built for developers and I think every developer should be familiar with it.

If this article helped you, please share it on your social media.

And where do you deploy your application? Is it always Vercel?

Learn React 18 & Next.js

You don’t feel strong with React or Next.js? Join my online course on Udemy! I will help you to get started with React by creating a fully-functional 2048 Game. I believe creating games makes learning more fun, and you'll have something cool to show your friends.

šŸ‘‡šŸ‘‡šŸ‘‡šŸ‘‡

šŸ§‘ā€šŸŽ“ Join React 18 and Next.js course on Udemy – 80% OFF only this week.


Written by msokola | yippee ki-yay
Published by HackerNoon on 2024/02/20