Next.js - MDXとシンタックスハイライト

1. MDX

MDX とは Markdown 内に jsx を記述できたり、コンポーネントを import できたりするので Markdown 形式 でより柔軟な対応ができます。よく利用するものなどをまとめておくと便利だと思います。ファイル形式は.mdではなく.mdxになります。

まず、Next.js で MDX を使用するために下記をインストールします。

npm install  @next/mdx @mdx-js/loader

次にnext.config.jsというファイルをpackage.jsonと同じ階層に作成して下記を記述すれば MDX を使用できるようになります。

const withMDX = require("@next/mdx")({
  extension: /\.mdx?$/,
})

module.exports = withMDX({
  pageExtensions: ["js", "jsx", "ts", "tsx", "md", "mdx"],
})

使用できるようになったか確認するために.mdxファイルを作成してその中に下記を記述して背景トマト色の<h3>が表示されれば ok です。

<div style={{ padding: "20px", backgroundColor: "tomato" }}>
  <h3>This is JSX</h3>
</div>

2. コードハイライト

コードハイライトする方法は色々あると思いますが、ここでは MDX でコードハイライト使用する方法です。MDX の公式サイトに書いてある方法をそのまま試しています。まずprism-react-rendererをインストールします。

npm install prism-react-renderer

次にcodeblock.jsというファイルをcomponentsフォルダ内に作成し、下記を記述します。import themeでコードハイライトのテーマを設定できるので、prism-react-renderer に入っているテーマから選びます。ここではgithubを選んでいます。

//codeblock.js
import Highlight, { defaultProps } from "prism-react-renderer"
import theme from "prism-react-renderer/themes/github" //テーマを選択

export default function Code({ children, className }) {
  const language = className.replace(/language-/, "")

  return (
    <Highlight
      {...defaultProps}
      code={children}
      language={language}
      theme={theme}
    >
      {({ className, style, tokens, getLineProps, getTokenProps }) => (
        <pre
          className={className}
          style={{ ...style, padding: "20px", overflow: "auto" }}
        >
          {tokens.map((line, i) => (
            <div key={i} {...getLineProps({ line, key: i })}>
              {line.map((token, key) => (
                <span key={key} {...getTokenProps({ token, key })} />
              ))}
            </div>
          ))}
        </pre>
      )}
    </Highlight>
  )
}

上記で作成したcodeblock.jsを反映させるために_app.jsに下記を記述すれば完了です。

//_app.js
import { MDXProvider } from "@mdx-js/react"
import CodeBlock from "../components/codeblock"

const components = {
  code: CodeBlock,
}

export default function App({ Component, pageProps }) {
  return (
    <MDXProvider components={components}>
      <Component {...pageProps} />
    </MDXProvider>
  )
}

Next.js | MDX
next.js/examples/with-mdx at canary · vercel/next.js · GitHub