It had been a few years since I gave my personal website any love. When you code professionally, sometimes you have little left at the end of the day, or evening, to devote to personal projects. The last time I redid my site, I used Vue.js and Storyblok. After spending 5 years with Angular.js, it was time to give something else a try. I remember thinking how much better I liked Vue, it felt much more natural to be coding in an environment that gracefully coupled template HTML code with JS code. Then right when I finished the first pass, I took a new job and started learning React + Typescript and had no time for my site.
Three years later and I'm starting to manage my daily tasks efficiently and have some time for my own projects. I decided it was time to spruce up my site and add some content. I started looking through my Vue code and realized I hadn't committed much of it to memory and I thought it would be easier to redesign my site in React and use some more current tools and best practices I had gained. After a weekend, I had my new site deployed to Heroku with not much hassle and I was happy.
Then I started adding the new content I had planned and wanted to measure any traffic. And that's where I started going down a rabbit hole. In terms of SEO performance, I'd rank a vanilla create-react-app roughly a D+. I think this probably holds true for many JS heavy SPA-style websites, when Google's webcrawler comes a knockin', there's nobody home. Sure you can create a sitemap and submit pages to Google Search Console, but if you're site pulls content from an API and renders it in the browser asynchronously, your pages are practically invisible to web crawlers until they get in the render queue which takes considerably longer to process given the amount of web content out there.
Other issues, like page titles and meta tags are not considered in a create-react-app project, you'll need to develop your own method for handling these if your want them to be unique and SEO-friendly. There are methods described where you dynamically populate the
document.title after your content is fetched, but I have my doubts that a web crawler would read the updated tag instead of the whatever it was on the initial page load.
While I was reading up on solutions to fix these problems, I remembered reading about Next.js and vaguely recalling that it offered several unique ways to deploy a React-based site, one option is deploying a completely static HTML site. This peaked my interest because I knew a static site with all of its content ready on initial paint would be much more SEO-friendly.
I didn't think too hard about my next steps, they just sort of fell into my lap. I began with looking at the start learning section. The tutorial started walking me through building a new Next.js project, and within minutes I had something up and running in my dev environment. There wasn't too much unfamiliar here if you're coming from a React background.
The main thing that stuck with me is Next.js has routing built-in. And the way routing works is drastically different than what you're probably used to. Instead of defining routes in a file, the routes are created automatically based on your file hierarchy. Essentially anything you add to the pages folder in a Next.js app, the route will be created automatically. In my example below, I have posts, projects, and services which correspond to my main navigation. It even has a very simple way to create dynamic routes, say you wanted
/posts/:id, you would simply create a file under your posts folder and name it
[id].jsx. That is pretty cool.
Built-in Head Component
When I saw they had a built-in <Head /> component, it started to click that Next.js was built with SEO in mind. The Head component allows you to specify
<head /> tags that should appear on your pages. You may use the component on pages, and if you require a custom title that comes from your api, you can pass that into your head component using a new Next.js convention called
getStaticProps which allows you to do cool things like pass in server-based or api data that needs to be available before your page is rendered.
Built-in Image Component
On my old site, I spent a bit of effort dealing with lazy loading images to improve page performance. Since I use pretty large images for my portfolio section, I wanted to make sure these pages would be usable for people on mobile devices. For this I used a custom React library called react-lazy-load-image-component. This worked pretty well but it was an afterthought and I am really happy to see a site building platform that treats this as a first-class citizen. Next.js Image components handle lazy-loading automatically. They even come with a built-in
placeholder property that can add a blur effect while the high-res image is downloading. It also requires you to define a height and width which ensures minimal layout shift when your image finishes downloading.Other responsive features are baked in, like on-demand image resizing, even for images stored on remote servers. That is pretty amazing.
Typescript and Eslint Build-in
These are features that typically take a bit of fiddling with new/existing projects to get it right. However, Next.js has these already part of it's core. You can start a new project with built-in TS support by simply typing in your console
npx create-next-app@latest --ts or if you have an existing project, type
touch tsconfig.json and Next.js will automatically configure typescript to work inside your project.
Flexible Data Fetching
With Next.js, you can deploy a site that serves up pages at request time, or serves pre-rendered pages at build time, all under the same app. This gives you lots of flexibility and optimizes site performance.
Speaking of performance, here's a snapshot of my sites performance after the Next.js redesign taken with Chrome's Lighthouse performance analyzer.
This is a significant improvement over my previous create-react-app version which scored roughly an 80% performance score before tinkering. I was eventually able to raise it to upper 90s, but that was after adding the react-lazy-load-image-component and other mods.
I did hit a slight snag though. After deploying my new site to Heroku and dealing with some DNS issues, I tested my new site and started to notice the images were downloading slower than what I saw in my development environment. Even worse, I saw my app crash while attempting to fetch these images. I tried many changes including passing in a PORT config variable, but kept seeing my app crash which was unacceptable.
While I wasn't able to resolve my issue on Heroku, I was able to fix it, and enjoy some massive load time improvements by hosting my new site on Vercel, the makers of Next.js. I was actually really pleasantly surprised by their onboarding experience, which got my new site deployed in minutes, and unlike Heroku, they offer free SSL with free accounts. Vercel specializes in Next.js app hosting and its likely you will see a performance boost if you choose to try them.
Overall I'm really happy with what Next.js brings to the table. For those comfortable with React, it's a no-brainer to give it a try. I think the hardest concept to grasp was the
getStaticPaths features, but once you understand how these work, you will start to understand what makes Next.js the future of Web coding.