How to migrate a user/organization GitHub Page made in ReactJS to NextJS
Tags: react, nextjs, github, webdev
Published: 2021-01-23 18:54:58

Hey, there!
You might find several guides out there that show how to **migrate a website made in ReactJS to NextJS** or how to **deploy NextJS to GitHub Pages**, however you'll rarely find the following specific scenario:

- Migrate **ReactJS to NextJS**
- The page is deployed on **GitHub Pages**
- More specifically, it's a [user/organization page](https://docs.github.com/en/github/working-with-github-pages/about-github-pages#types-of-github-pages-sites)
- The page deployment is made using **TravisCI**

# 📚 Motivation

The motivation for this is that I'm learning NextJS and wanted to migrate an organization page hosted GitHub Pages.

{% github tarrafahc/tarrafahc.github.io no-readme %}

# ⌛ Before

This is the repository before the migration, a pretty simple React project with some components, a few routes and a NavBar:

![original project](https://dev-to-uploads.s3.amazonaws.com/i/g9j3qma0dv1u8fsul46n.png)
_In case you're wondering, the lovely sidebar with folders is the [Octotree](https://addons.mozilla.org/en-US/firefox/addon/octotree/) extension_
Here's a link to the repository by the time it was still a pure React project
https://github.com/tarrafahc/tarrafahc.github.io/tree/df834b8af66dd6983577016e82d66b20d5c57a43

# ☀️ Starting

So what I first did was to create a new NextJS app with `npx create-react-app` and to copy its `package.json`'s `scripts` and `dependencies` from its to mine.   
I've also copied its `pages`, `public` and `styles` folders, since the folder structure is a bit different.

# 🏠 Structure

I started by copying files inside `src/components/pages` to the root `pages` folder and changing some of their content, like removing `import React from 'react'` and adapting the [Link](https://nextjs.org/docs/api-reference/next/link) component usage.

```jsx
/* Link with ReactJS */
import { Link } from 'react-router-dom'

//...
const Home = () => {
  return (
    <p>Find more about us {<Link to="/about">here</Link>}</p>
  )
}
//...

/* Link with NextJS */
import Link from 'next/link'

//...
const Home = () => {
  return (
    <p>Find more about us {<Link href="/about"><a>here</a></Link>}</p>
  )
}
//...
```

I also had to move the component folder from `src/components` to `components` in the root directory, because... well... that's how it works with NextJS

By the way, if you're importing SVG files as React components like me, this link will be pretty useful

{% medium https://medium.com/frontend-digest/how-to-import-svgs-into-nextjs-8ec6100e613f %}

# 💅 Styles

NextJS uses some kind of [CSS Modules](https://nextjs.org/docs/basic-features/built-in-css-support) that can be imported and used in components like objects, however this project was so simple that I had all my CSS on `src/index.css`.
To use it as a global css file in NextJS, we just copy its content to `styles/globals.css`

# 🛠️ The boostraped NavBar problem

Ok, so I have a `NavBar` component that should be shown on all pages, but `App.js` is now gone. Where should I put it?

It seems there are two approaches:
- Using a Layout component [(example project)](https://github.com/vercel/next.js/tree/canary/examples/layout-component)
- Using it on [_app.js](https://nextjs.org/docs/advanced-features/custom-app)

I've chosen the second because it looked better than importing a `Layout` component in every page.
If you know which advantages we might have by choosing the Layout approach, please let me know in the comments (I really want to know the difference)

{% gist https://gist.github.com/Markkop/d04dbced4c6d197b7884871aaf0cfc75 %}

I'm not very proud of it, but by the time I made this React project, I've imported [bootstrap](https://getbootstrap.com/docs/5.0/getting-started/introduction/) libraries using `<script>` and `<link>` tags in `public/index.html` so my `NavBar` could use some of their class names to make it responsive on mobile.

In NextJS we don't have `index.html` anymore, so I've found out that this kind of code should belong to a `_document.js` file similar to `_app.js`
Here's where you can know more about [_document.js](https://nextjs.org/docs/advanced-features/custom-document)

 {% gist https://gist.github.com/Markkop/63736981090320159978e6a24931c7b6 %} 

I'm surely should refactor this someday.

# 🚀 Deploy

Okay, so far I've shown some content that you can find anywhere on the internet. But now comes the part where this guide shines.

Since we're using [TravisCI](https://travis-ci.org/) to deploy to **GitHub Pages** and not the **NextJS** own deployment method, we have to `next export` our project.

Simply add the follow command to the `scripts` object on `package.json`
```json
scripts: {
  "export": "next build && next export"
}
```
Then change `.travis.yml` to run `npm run export` and make sure to modify `deploy`'s section to `local_dir: out`, because that's the folder where our content will be.
There's a file example right below if this wasn't clear.

If you've done everything right, you'll find out that the CSS and other pages except the index are not loading.

![_next not found](https://dev-to-uploads.s3.amazonaws.com/i/zyt7ibupangb9b1flb1h.png)

That's exactly what @jameswallis reported on its own guide:

{% link https://dev.to/jameswallis/deploying-a-next-js-app-to-github-pages-24pn %}

However, since he was deploying a project page, the fix was adding some base paths in the `next.config.js`:

```js
module.exports = {
    basePath: '/wallisconsultancy',
    assetPrefix: '/wallisconsultancy/',
}
```

Which does not really work for us because we don't have this base path for user and organization [GitHub Pages](https://docs.github.com/en/github/working-with-github-pages/about-github-pages#types-of-github-pages-sites).

The trick here is to add an empty `.nojekyll` file to our output folder to let [GitHub actually copy files](https://github.blog/2009-12-29-bypassing-jekyll-on-github-pages/) that starts with underscore to their final GitHub Page. 
In this case, we want the `_next` folder being copied correctly.
You can add an `&& touch out/.nojekyll` at the end of the `export`command or add an extra line in `.travis.yml` script.
Here's how is mine:

```yml
language: node_js
node_js:
  - 'stable'
cache:
  directories:
    - node_modules
script:
  - npm run export
  - touch out/.nojekyll
deploy:
  provider: pages
  skip_cleanup: true
  github_token: $GITHUB_TOKEN
  keep_history: true
  local_dir: out
  target_branch: master
  fqdn: tarrafa.net
  on:
    branch: dev
```

# 🍀 Bonus

At this point you already know that the `target_branch` for user and organization pages must be `master` that contains the build/exported code.

But if you're using a Custom Domain name, like me, you'll need a CNAME file in the output folder so you don't have to configure the repository every time a deployment is made.

Don't know what I'm talking about?
Check the following post:
{% link https://dev.to/heymarkkop/how-to-set-up-a-custom-domain-on-github-pages-hc7 %}

Here's what I've found out, you don't have to use `&& cp CNAME build/CNAME` in the `package.json` export command to copy the CNAME file with your domain name.
You can simply add `fqdn: my.domain` in the TravisCI yml like the example above.
A minor change, but way cleaner!

# 🏁 Conclusion

After migration:
![after](https://dev-to-uploads.s3.amazonaws.com/i/wvzqiymbfsktoerxcnm9.png)

{% github tarrafahc/tarrafahc.github.io no-readme %}

I hope this guide helps people looking to learn more about NextJS and its comparison to a pure ReactJS project, specially when it's being deployed to a user/organization GitHub Page.
Thanks for your attention!
If possible, let me know your thoughts on the comments below :D