tips / nextjs

Migrating from GatsbyJS to Next.js

August 29, 2022

As part of my learning process, I decided to migrate from Gatsby to Next.js, a JavaScript framework based on React.js.

While I came across several articles stating that Gatsby performs better in terms of performance, I had three main reasons for choosing to migrate:

  • Frequent deployment errors on Netlify during updates.
  • GatsbyJS offers many convenient plugins, but it also has issues with dependency vulnerabilities.
  • I wanted to build the website using Next.js and TypeScript.

About Next.js

Next.js is a JavaScript framework based on React, which provides an excellent developer experience with all the necessary features for production, including hybrid static and server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No configuration is needed.

Next.js gives you the best developer experience with all the features you need for production: hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed.

環境について

Before After
Framework GatsbyJS Next.js
Language React TypeScript
Hosting Service Netlify Vercel

Migration Process

The required migration tasks may vary depending on the site's configuration, but I started by following the steps provided in the "Migrating from Gatsby" page on the Next.js official website.

In addition to the steps mentioned in that page, the specific tasks I needed to perform for my site were as follows:

  • Maintain the permanent links and directory structure of each article.
  • Handle image loading within articles.
  • Apply syntax highlighting to Markdown in articles.
  • Display a table of contents.
  • Create category and tag listing pages.
  • Configure Google Analytics, Google AdSense, and other settings.
  • Switch from Netlify to Vercel.

Since I didn't use a CMS, I loaded the data of each article by reading markdown files within the src directory. When creating the site with Gatsby, I followed certain rules for file management, referring to other sites. These rules were:

  • To manage the files of each article in chronological order, I named the files as "date-slug.md"
  • I only used the slug for the permanent link
  • If an article contained images, I created a folder named "date-slug" and placed an index.md file inside it
  • Pages like "about" and "policy" were also managed using Markdown
src
├──contents
│   ├── pagegs
│   │   ├── about.md
│   │   └── policy.md
│   │
│   ├── posts
│   │   ├── blog
│   │   │    └── 日付-スラッグ.md
│   │   └── tips
│   │   │    ├── 日付-スラッグ.md
│   │   │    └── 日付-スラッグ
│   │   │          ├── index.md
│   │   │          └── image.jpg

To maintain this structure after transitioning to Next.js, I needed to make modifications in the section equivalent to getPostBySlug under the "Data Fetching" topic, as mentioned in the "Migrating from Gatsby" guide.

Image Loading in Articles

In Next.js, static files are managed in the public folder.

For my site, I stored the images within the same folder as the corresponding markdown files. This allowed me to load the images in articles using a simple path:

![](./image.jpg)

As I was exploring different methods, including using the next-optimized-images library and loaders, I tried several approaches but couldn't get them to work properly. So, I'm not sure if this is the correct solution, but in the end, I was able to load images within articles without modifying the paths using the following method:

  1. Install the copy-webpack-plugin

  2. Copy the image files from the articles to the .next/static/media/ folder, where the static files are placed after the build, using the next.config.js file:

/** next.config.js */
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  webpack: (config) => {
    config.plugins.push(
      new CopyWebpackPlugin({
        patterns: [
          {
            from: './src/contents/posts/**/**/*', // Specify the source files to copy
            to: './static/media/img/[path][name][ext]', // Specify the destination folder
            globOptions: {
              ignore: ['./**/*.md'], // Exclude markdown files from articles
            }
          },
        ]
      })
    )
    return config
  }
}

Regarding the usage and customization of the Webpack plugin, the Next.js official website provides an explanation in the "Custom Webpack Config" section of the "Custom Webpack Config" documentation. However, please note that they mention the following:

Note: changes to webpack config are not covered by semver so proceed at your own risk

Therefore, please use this approach at your own discretion.

Applying Syntax Highlighting to Markdown in Articles

Since I was using the gatsby-remark-prismjs plugin in Gatsby, I decided to use the same Prism.js library in Next.js as well.

The process of applying it to markdown files may vary depending on how the files are transformed, but here is a general outline of the steps:

markdown への適用は、 markdown ファイルの変換方法によって変わりますが、おおまかな導入の流れとしては次の手順になります。

  1. Instead of the plugins used in Gatsby, install prismjs and babel-plugin-prismjs:
npm install prismjs babel-plugin-prismjs
  1. In the _app.tsx file, import the prism.css file and the CSS file for the desired theme:
/** _app.tsx */
import '@(path)/prism.css'
import '@(path)/prism-tomorrow.css'
  1. Apply Prism.js to the markdown in the article component.

  2. In the Babel configuration file, .babelrc, specify the languages and options to be used:

/** .babelrc */
{
  "plugins": [
    "@emotion/babel-plugin",
    [
      "prismjs",
      {
        "languages": [
          "javascript", 
          "typescript",
          "jsx",
          "css",
          "markup",
          "json",
        ],
        "plugins": ["show-language"], // // Display language labels
        "css": true
      }
    ]
  ]
}

By following these steps, you should be able to apply syntax highlighting to markdown content in Next.js using Prism.js.

Displaying Table of Contents

In Gatsby, I used the gatsby-transformer-remark plugin to retrieve and display the table of contents using GraphQL.

For the migration to Next.js, I opted to use the npm package marked, which is used for converting markdown, to retrieve and display the table of contents.

How to Create a Markdown Blog with Next.js

Switching from Netlify to Vercel

As part of the transition to Next.js, I found it more convenient to switch the hosting service from Netlify to Vercel, which is the company behind Next.js.

Since my deployment was already integrated with a GitHub repository for Netlify, migrating to Vercel was a straightforward process.

In addition to changing the deployment target, I had to update the domain settings for my site since I have a custom domain. Here are the steps I followed:

  1. Remove the custom domain registration in Netlify.
  2. Register the custom domain in Vercel after deploying the site.
  3. Modify the name server settings in the domain registrar's management interface.

Main Packages Added

  • next
  • gray-matter : Parses front-matter in markdown files
  • marked : Converts markdown to HTML
  • prismjs : Provides syntax highlighting

Conclusion

Here are the results measured using Lighthouse before and after the migration. As I read in the articles beforehand, the performance metrics have decreased compared to Gatsby, but I intend to work on improving them going forward. (The slight increase in the Accessibility score is due to some changes in background and text color contrast and not directly related to the migration to Next.js.)

移行前

移行後

Reference

Tags

web-developerjavascriptreact