disquisition.net

Photo by Nathan Anderson / Unsplash

↜ Blog

Building My Blog With Next.js

June 13th, 2017

I re­cently de­cided to build a blog. In 2017, it is eas­ier than ever to get a blog on­line, but in­stead of us­ing one of the many shake and bake so­lu­tions I chose to have a lit­tle fun and build out a React-based site.

Next.js is one of the best so­lu­tions avail­able right now for React development. It is one of a hand­ful of op­tions for those who, like me, don’t want to spend too much time fid­dling with con­fig­u­ra­tion and build process setup.

Initial Setup

Start with this package.json:

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}

Save the fol­low­ing as /pages/index.js:

export default () => (
  <div>
    <h1>Welcome to Next.js</h1>
    <p>See how easy that was?</p>
  </div>
);

Now run npm i --save next react react-dom && npm run dev. That’s it.

Advanced Setup

Okay, I lied a lit­tle bit when I said “that’s it.” Next.js only has one ma­jor draw­back: it does­n’t play nice with dy­namic URLs out of the box (i.e., /blog/:slug, where :slug is a dy­namic URL seg­ment cor­re­spond­ing to a spe­cific blog post). Given that this is an ex­tremely com­mon use case, it feels like an over­sight but luck­ily there is a fairly clean workaround: next-routes. You can even find an ex­am­ple im­ple­men­ta­tion in the Next.js GitHub repos­i­tory here.

The ba­sic idea is that next-routes wraps the built-in Next.js router and Link com­po­nent such that dy­namic URL seg­ments are treated as query pa­ra­me­ters in­ter­nally. In prac­tice, this is rea­son­ably in­tu­itive… but I still wish I didn’t need a third party pack­age for this.

Writing Posts

I could have called it a day af­ter set­ting up rout­ing. At that point, all you re­ally need to do is save your blog posts as HTML in a sep­a­rate di­rec­tory and then when a reader hits /blog/my-first-post you just load the HTML for my-first-post.html and dis­play it us­ing the dangerouslySetInnerHTML API.

I wanted the sim­plic­ity of a file-based com­po­si­tion mech­a­nism—af­ter all, why else would I be us­ing Next.js?—but HTML does­n’t make for the best writ­ing ex­pe­ri­ence. The ob­vi­ous choice was Markdown. I ended up de­cid­ing against sim­ply com­pil­ing to HTML, but rather to us­ing the ex­cel­lent unified package—combined with rehype-parse—to com­pile to an AST. The AST is what gets sent to the client, where it is ren­dered as a tree of React components.

The rea­son for this ap­proach is more than just avoid­ing the dangerouslySetInnerHTML API. Rendering the whole tree al­lows me to sub­sti­tute my own com­po­nents for, e.g., plain <a></a> tags. This al­lows me to write posts as Markdown while main­tain­ing very fine-grained con­trol over how those posts are loaded and dis­played.

What about Create React App?

I looked briefly at us­ing Create React App to build this site, but de­cided against it. CRA is a fan­tas­tic tool but on the the site ↔ app con­tin­uum, it leans much fur­ther to­ward “app” territory than Next.js. Here are some points to con­sider if you’re de­cid­ing be­tween Next.js and Create React App:

  • Routing: Next.js has built-in, file-based rout­ing, whereas Create React App has no rout­ing built in but can eas­ily be paired with react-router. This may seem like a small dif­fer­ence, but it’s worth tak­ing a look at the more ad­vanced ex­am­ples in the react-router docs—if you see some­thing you think you need, you may be bet­ter off with CRA. If not, Next.js’s sim­pler, built-in rout­ing will be fine.
  • Hot Code Reloading: Next.js hot re­loads code changes au­to­mat­i­cally while run­ning in dev mode. If you haven’t ex­pe­ri­enced hot re­load­ing be­fore, do your­self a fa­vor and cre­ate a sim­ple Next.js app just to see it in ac­tion. It’s in­cred­i­ble. Create React App cur­rently does not of­fer a hot re­load­ing so­lu­tion.
  • Server Side Rendering: Next.js is server side ren­dered (SSR) by de­fault, while Create React App does not cur­rently of­fer an SSR so­lu­tion. If you’re build­ing an app, SSR may not be your top pri­or­ity, but if you’re build­ing a blog or other site with strict SEO re­quire­ments, Next.js may be the safer bet.
  • Head: Next.js has built-in ways of man­ag­ing your head, via the cus­tom Head com­po­nent. Create React App has great rec­om­men­da­tions about how to add com­pa­ra­ble func­tion­al­ity, but noth­ing as easy and straight­for­ward as Next.js.
  • Ejecting: Create React App pro­vides an eject script which will boot you from the cu­rated CRA en­vi­ron­ment. This can be valu­able if you want to use CRA as a way to kick­start de­vel­op­ment and then later re­al­ize you re­quire com­plete con­trol over your build process. With Next.js, you are more or less locked in.

For me, hot load­ing and SSR out­weighed lock-in and wran­gling its ex­tremely sim­ple rout­ing. I con­sid­ered do­ing a sep­a­rate blog post de­voted to com­par­ing Next.js and Create React App, but hon­estly they are dif­fer­ent enough that most of the time it should be very easy to choose one or the other.

What’s next?

Right now, when I need to pub­lish a post I’m just re­de­ploy­ing the site with now. now makes this a very easy so­lu­tion, how­ever, I re­ally should­n’t have to re­de­ploy just to add a new post, right? (I know we live in a post-Jekyll world, but it still feels wrong.)

The so­lu­tion I’m look­ing at now is cre­at­ing a sim­ple Dropbox web­hook. This should al­low me to save my posts in a folder on my per­sonal Dropbox ac­count and have them au­to­mat­i­cally picked up by the blog.