Building a small CMS with NextJS, pt2 – CodeWithSwiz

CodeWithSwiz is a twice-a-week live show. Like a podcast with video and fun hacking. Focused on experiments. Join live Wednesdays and Sundays

Play: YouTube video

Continuing our NextJS app where we left off on Sunday, in this episode we made good progress:

You can see it live at swiz-cms.vercel.app. I used it to publish this today 🤘

Slugs and article creation 🍝

This is a baby CMS and relies on humans to do the work. Means ~~you~~ I can start using this before it's finished and start saving time and effort.

You're the computer, the CMS is your script.

import slugify from "slugify"

export const CLICopyPasta = ({ title }) => {
  // creates the slug, hooray libraries
  const slug = slugify(title).toLowerCase()

  return (
    <pre>{`
cd ~/Documents/websites/swizec.com
mkdir src/pages/blog/${slug}
mkdir src/pages/blog/${slug}/img
touch src/pages/blog/${slug}/index.mdx
            `}</pre>
  )
}

Yep, simple component. Open source slugify makes our slug and we write the instructions. Once is better than always.

Copypasta instructions for article creation

You can find someone on Fiverrr or Upwork to do these steps for you. Costs $10/week compared to Contentful which is $400/mo.

🤔

Custom hook for social cards

A frustration I wanted to solve was adding social cards as hero images to article frontmatter. Fiddly manual process. Error prone as heck.

Hero link shows up in frontmatter

There's 2 ways you can do this:

  1. Hoist social card fetching out of <SocialCardImage> to top component and push state down through props
  2. Create a reusable hook that internally avoids double fetching

Following my Wormhole state management principle, reusable hook is the way to go.

// components/SocialCardImage
export function useSocialCardQuery(title) {
  return useQuery(["social-card", title], fetchSocialCard)
}

Doesn't look like much but therein lies magic. 🧙‍♂️

React Query dedupes API calls with the same name. Our hook ensures we use the same name and fetch function everywhere.

You can now pepper useSocialCardQuery anywhere in your app. It's always going to have the latest state and avoid refetching, if it knows the result.

Turn an old project into a library

This part proved tricky. We tried to extract the markdown machinery from techletter.app into a shared library.

techletter.app machinery in action

Extraction itself wasn't that hard:

Run microbundle and see it dies on image imports. It's meant for pure TypeScript and JavaScript projects.

We use images for loading gifs ...

Switch to parcel and packaging started working. A matter of changing config in package.json

"source": "src/index.js",
"scripts": {
    "dev": "microbundle watch",
    "build": "microbundle"
},

👇

"scripts": {
    "dev": "parcel src/index.js",
    "build": "parcel build src/index.js"
},

Yes no-config bundlers are that easy. Until you get into the weeds and try to be fancy that is.

Unfortunately it didn't work. global undefined whatever the heck that means 🤨

But I think I've got a solution, join me on Monday 6:30pm Pacific.

Favorite NextJS feature so far?

Initial quick setup was great and those error messages are divine. Beautifully designed, safe as heck, and fast.

An error message in NextJS

With client-side bugs you get a blurred-out view of your app behind the error. Useful, no, cool as heck, yeah!

And your browser almost always reconnects to the development server even after a restart.

I Love It Chefs Kiss GIF by Magic: The Gathering

Cheers,
~Swizec