The words Under construction in black text on a yellow background with diagonal black stipes surrounding it
I'm in the process of moving my site. It's still a work in progress. Please excuse the mess and broken links.

2021 - Next.js Build Notes

TODO: Pull subtitle into page object

These notes start from the point when I moved off mdx-bundler and onto next-mdx-remote. I started from scratch.

Initial setup

code_start_default_section code_end_default_section

I build the `Img.js` file with a script before I publish that grabs all the images in the `_images` directory and makes an entry for each one. That way, all I need to do is drop in an image with a valid name and then use it in the `

I'd prefer to keep the images in sub-directories by year but that's more than I want to tackle at the moment. Getting the images in place in generally was the key. I can optimize later if that becomes necessary.

Something that's cool about this is that it will let me customize image calls further if I want since there's a layer of abstraction between the content and the `

It's a bit of a hack, but it works.

TODO: Figure out if this impacts the performance of the site as the number of images goes up since they are all being imported.

Debugging Stuff

I'm moving stuff around right now. All this below is helping me figure out where to put stuff

        -- title

2021 - Next.js Build Notes

-- p

These notes start from the point when I moved off mdx-bundler and onto next-mdx-remote. I started from scratch.

-- p

Initial setup

-- code/

mkdir alanwsmith.com
cd alanwsmith.com
npx create-next-app .
npm i next-mdx-remote gray-matter
npm i @netlify/plugin-nextjs

-- /code

-- p

That got everything ready to go based off the work done on https://next-mdx-remote-blog-example.netlify.app/

-- p

Moved all components into their own files since next-mdx-remote doesn't work with them inside of files.

-- p

The data has to be added directly in the component as well, like this:

-- code/
-- jsx

<Checklist data={`
Start Monster Cat Audio
Set Monster Cat Audio to Shuffle
Mute headphones
Switch OBS to main scene and check that music and vocals are working
`} />

-- /code

-- p

Installed Tailwind from these instructions: via: https://tailwindcss.com/docs/guides/nextjs

-- p

Starting with

-- code/

npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

-- /code

-- p

Then ran this

-- code/

npx tailwindcss init -p

-- /code

-- p

which created `tailwind.config.js` and `postcss.config.js`

-- p

The next step was to put this in `tailwind.config.js`

-- code/

purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],

-- /code

-- p

Then replaced the contents of ./styles/global.css with:

-- code/
-- css

@tailwind base;
@tailwind components;
@tailwind utilities;

-- /code

-- p

That gets the basic framework in place.

-- p

Setup to use a basic LayoutMain file that has tailwind in it:

-- p

file: ./components/LayoutMain.js

-- code/
-- javascript

export default function LayoutMain(props) {
  return (
    <>
      <div className="bg-gray-800 min-h-screen">
        <main className="pb-16 mx-auto container pt-4 px-6 max-w-screen-md">
          {props.content}
        </main>
      </div>
    </>
  )
}

-- /code

-- p

Then updated the index.js and [slug].js file to use it with:

-- p

file: ./pages/index.js

-- code/
-- javascript

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import Link from 'next/link'
import LayoutMain from '../components/LayoutMain'

export default function HomePage({ posts }) {
  return (
    <>
      <LayoutMain
        content={
          <>
            <h1>This is the home page</h1>
            <p>Stuff broke... I fix</p>
            <ul>
              {posts.map((post) => (
                <li key={post.slug}>
                  <Link href={`/posts/${post.slug}`}>
                    <a>{post.title}</a>
                  </Link>
                </li>
              ))}
            </ul>
          </>
        }
      />
    </>
  )
}

export async function getStaticProps({ params }) {
  const contentDir = path.join(process.cwd(), '_posts')

  const posts = fs
    .readdirSync(contentDir)
    .filter((filePath) => /\.mdx?$/.test(filePath))
    .map((filePath) => {
      const slug = filePath.replace(/\.mdx$/, '')
      const { content, data } = matter(
        fs.readFileSync(path.join(contentDir, filePath))
      )
      return {
        title: data.title,
        slug: slug,
      }
    })

  return {
    props: {
      posts: posts,
    },
  }
}

-- /code

-- p

file: ./pages/posts/[slug].js

-- code/
-- javascript

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'
import Link from 'next/link'

const CONTENT_DIR = path.join(process.cwd(), '_posts')

import LayoutMain from '../../components/LayoutMain'
import Checklist from '../../components/Checklist'
import ReadOnlyChecklist from '../../components/ReadOnlyChecklist'
import YouTubeVideo from '../../components/YouTubeVideo'
import VimeoVideo from '../../components/VimeoVideo'

export default function Post({ source, frontmatter }) {
  return (
    <>
      <div>
        <Link href="/">
          <a>Home Page</a>
        </Link>
      </div>
      <LayoutMain
        content={
          <>
            <h1>{frontmatter.title}</h1>
            <MDXRemote
              {...source}
              components={{
                Checklist,
                ReadOnlyChecklist,
                YouTubeVideo,
                VimeoVideo,
              }}
            />
          </>
        }
      />
    </>
  )
}

export async function getStaticProps({ params }) {
  const { content, data } = matter(
    fs.readFileSync(path.join(CONTENT_DIR, `${params.slug}.mdx`))
  )
  const mdxSource = await serialize(content)
  return { props: { source: mdxSource, frontmatter: data } }
}

export async function getStaticPaths() {
  const paths = fs
    .readdirSync(CONTENT_DIR)
    .filter((path) => /\.mdx?$/.test(path))
    .map((fileName) => fileName.replace(/\.mdx$/, ''))
    .map((slug) => ({ params: { slug: slug } }))
  return {
    paths: paths,
    fallback: false,
  }
}

-- /code

-- p

Installed prismjs with:

-- code/

npm i prismjs

-- /code

-- p

Added `import 'prismjs/themes/prism-tomorrow.css'` to _app.js so it looks like this:

-- code/
-- javascript

import '../styles/globals.css'
import 'prismjs/themes/prism-tomorrow.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

-- /code

-- p

And then updated ./components/LayoutMain.js so it looks like this:

-- code/
-- javascript

const prism = require('prismjs')
import { useEffect } from 'react'

export default function LayoutMain(props) {
  useEffect(() => {
    prism.highlightAll()
  }, [])

  return (
    <>
      <div className="bg-gray-800 min-h-screen">
        <main className="pb-16 mx-auto container pt-4 px-6 max-w-screen-md">
          {props.content}
        </main>
      </div>
    </>
  )
}

-- /code

-- p

That gets the syntax highlighting in place so that code fences like:

-- code/
-- javascript

const someThing = 'An example'

-- /code

-- p

Render as:

-- code/
-- javascript

const someThing = 'An example'

-- /code

-- p

Added in favicons and header stuff and nav. see the github for details.

-- p

Using next/image requires importing the images directly to get the benefits of local functionality. Unfortunately next-mdx-remote doesn't handle that. So, I ended up created a `components/Img.js` file with:

-- code/
-- javascript

import Image from 'next/image'

import black_widow_20051026_230734a1 from '../_images/black_widow_20051026_230734a1.jpg'

const imgMap = {
  black_widow_20051026_230734a1: black_widow_20051026_230734a1,
}

export default function Img({ src, alt = 'image alt text unavailable' }) {
  return <Image src={imgMap[src]} alt={alt} />
}

-- /code

-- p

That gets included in the `[slug].js` file with the other components (via: `import Img from '../../components/Img'`) and passed to `MDXRemote` like this:

-- code/
-- javascript

<MDXRemote
  {...source}
  components={{
    Checklist,
    Img,
    ReadOnlyChecklist,
    YouTubeVideo,
    VimeoVideo,
  }}
/>

-- /code

-- p

Then, for every image that's going to be called I create an import like:

-- code/
-- javascript

import black_widow_20051026_230734a1 from '../_images/black_widow_20051026_230734a1.jpg'

-- /code

-- p

and a reference in a mapping object so I can access it like this:

-- code/
-- javascript

const imgMap = {
  black_widow_20051026_230734a1: black_widow_20051026_230734a1,
  // other images here
}

-- /code

-- p

I make sure the image filenames work as variable names so I can keep the same name in place across the board.

-- p

Then, to use the image, I call it like this in the MDX source files:

-- code/
-- html

<Img
    src="black_widow_20051026_230734a1"
    alt="A dead black widow spider showing the red hour-glass shape on the belly"
/>

-- /code

-- p

I build the `Img.js` file with a script before I publish that grabs all the images in the `_images` directory and makes an entry for each one. That way, all I need to do is drop in an image with a valid name and then use it in the `<Img>` tag. The rest of the work is automated.

-- p

I'd prefer to keep the images in sub-directories by year but that's more than I want to tackle at the moment. Getting the images in place in generally was the key. I can optimize later if that becomes necessary.

-- p

Something that's cool about this is that it will let me customize image calls further if I want since there's a layer of abstraction between the content and the `<Image>` call. For example, instead of just sending a style tag I could send an attribute that adds extra divs and puts in captions, etc... In fact, now that I think about it, that's exactly what I'm going to do.

-- p

It's a bit of a hack, but it works.

-- p

TODO: Figure out if this impacts the performance of the site as the number of images goes up since they are all being imported.


-- categories
-- Miscellaneous

-- metadata
-- date: 2021-11-22 14:39:38
-- id: 21htjsja
-- status: scratch
-- type: post
-- SCRUBBED_NEO: false
-- site: aws