Swizec Teller - a geek with a hatswizec.com

    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.


    Did you enjoy this article?

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

    Learned something new?
    Want to become an expert?

    Here's how it works πŸ‘‡

    Leave your email and I'll send you thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

    Join Swizec's Newsletter

    And get thoughtful letters πŸ’Œ on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.

    "Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. πŸ‘Œ"

    ~ Ashish Kumar

    Join over 14,000 engineers just like you already improving their careers with my letters, workshops, courses, and talks. ✌️

    Have a burning question that you think I can answer?Β I don't have all of the answers, but I have some! Hit me up on twitter or book a 30min ama for in-depth help.

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

    Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.

    Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first πŸ’° on the side with ServerlessReact.Dev

    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 bySwizecwith ❀️