Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    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

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

    • added title slugification
    • copypasta instructions to create an article
    • extracted social card API into a custom hook
    • added hero to frontmatter
    • aaaalmost extracted my custom Markdown machinery out of techletter.app

    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 (
    cd ~/Documents/websites/swizec.com
    mkdir src/pages/blog/${slug}
    mkdir src/pages/blog/${slug}/img
    touch src/pages/blog/${slug}/index.mdx

    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
    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:

    • create new project
    • yarn init to create package.json
    • add microbundle for packaging
    • copy files from old project
    • fix relative paths in imports
    • add index.js file that re-exports the public interface

    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
    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.


    Published on September 3rd, 2020 in CodeWithSwiz, Livecoding, Technical

    Did you enjoy this article?

    Continue reading about Building a small CMS with NextJS, pt2 โ€“ CodeWithSwiz

    Semantically similar articles hand-picked by GPT-4

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help ๐Ÿ‘‰ swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers ๐Ÿ‘‰ ServerlessHandbook.dev

    Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are โค๏ธ

    Created by Swizec with โค๏ธ