21
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

LivesenseAdvent Calendar 2020

Day 16

Next.jsでMDXを使ってみる

Last updated at Posted at 2020-12-15

目次

  1. MDXとは?
  2. Next.jsで使ってみる
  3. MDXのシンタックスをいろいろ試してみる
  4. 所感
  5. 余談

MDXとは?

  • 公式サイト: https://mdxjs.com/
  • markdownとjsx両方を同時に書ける
  • markdownはjsxをimportできる
  • MDXはruntimeを持たない、ビルドで解決される

といった特徴があるようです。

# Hello, *world*!

Below is an example of JSX embedded in Markdown. <br /> **Try and change
the background color!**

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

(MDXは流石にシンタックスハイライトされない...)

ドキュメントやブログを書く際に便利ですね。

Next.jsでMDXを使ったブログを作ってみる

https://mdxjs.com/getting-started/next 公式の通りに設定を入れると、あとはpages以下に好きなようにmdxファイルを作成するだけです。next devしましょう。

markdownが吐き出すタグを変更する

MDXの中に書いたmarkdownの構文はjsxに変換されますが、どのコンポーネントに変換するかを設定することができます。
https://mdxjs.com/getting-started/#mdxprovider
公式サイトにある通り、MDXProviderを使います。今回はNext.jsなので_app.jsに書いてしまいます。
例として、markdownのcode blockにシンタックスハイライトを効かせます。
https://mdxjs.com/guides/syntax-highlighting
(最近でたnext/imageなんかをここで使うと良さそうですね)

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

const mdComponents = {
  code: CodeBlock
}

const MyApp = ({ Component, pageProps }) => {
  return (
    <MDXProvider components={mdComponents}>
      <Component { ...pageProps } />
    </MDXProvider>
  )
}

export default MyApp

これでMDXに書いたcode blockはシンタックスハイライトが効くはずですね。
スクリーンショット 2020-12-15 3.22.01.png

Layoutを定義してみる

MDXだと、特定のページにレイアウトを適用するのが非常に簡単です。
今回は例として、タイトルタグを設定するレイアウトを作成します。

components/layout/BaseLayout.jsx
import Head from "next/head"

export const BaseLayout = ({ meta, children }) => (
  <>
    <Head>
      <title>{meta.title}</title>
    </Head>
    { children }
  </>
)

mdxでLayoutを適用します。

.mdx
import { BaseLayout } from "../components/layouts/BaseLayout"

export const meta = {
  title: "ホーム"
}

# レイアウトを適用したいMDX

export default ({ children }) => (
  <BaseLayout meta={meta}>
    {children}
  </BaseLayout>
)

MDX内でdefault exportすることができて、childrenにはこのMDXのJSXが渡ってきます。

MDXのシンタックスをいろいろ試してみる

index.mdx
import { Counter } from "../components/Counter"
import AboutContent, { meta as aboutMeta } from "./about.mdx"

# サンプルです

<div>
  { ["hoge", "fuga"].map(word => (
    <p>{word}</p>
  )) }
  # これはh1にならない
</div>

<!-- コメントアウト -->

<div>
  {/* コメントアウト */}
</div>

(qiitaのmarkdownとバッティングするのでいったん回避)
\```tsx
// コードブロックが書ける
type Props = { name: string }
export const Component: FC<Props> = ({ name }) => <>{name}</>
\```

- exportのない変数宣言はできない

export const hoge = "hoge"

- 文章とexportの間に空行がない場合は文章として扱われる
- constであればちゃんとMDX内でも再定義できない
export const hoge = "hoge"

<!--
export あああ
これはexport構文と解釈されてエラーとなる
-->

もちろんコンポーネントも使える
<Counter />

別のMDXをimportすることもできる(jsxなら当たり前ではある)
<AboutContent />
<div>
  title: { aboutMeta.title }
</div>

定義済みの変数があったりする
import MDXContent from "./about.mdx" // MDXContentはjsxで宣言される関数名ぽい
about.mdx
export const meta = {
  title: "about"
}

# aboutページです

vercelに↑のmdxをデプロイしたので、興味がある方は実際にどう表示されているか確認してみてください。
https://ikea-dless-mdx-sample.vercel.app/

所感

Next.js + MDXはドキュメントやブログでは結構使えるんじゃないかなと思っています。実際はfsでゴニョゴニョする部分があったり、検索機能を入れようと思うと一筋縄ではいかなさそうだったりすると思いますが...
gatsbyjsとの比較はしていないので、どちらが良いかはわかりませんが、vercelも込みで考えるとこの辺のエコシステムはNext.js強いよなーと思います。

余談

https://storybook.js.org/docs/react/writing-docs/mdx
以前、試験的に導入したのですが、storybookもMDXに対応していて、これが結構コンポーネントのドキュメントを書くのには向いている気がしています。仕様と実際のコンポーネントが同時に確認できて、非常に良いです。
加えて、MDXでもstoryshotsでドキュメント化したコンポーネントは漏れなくsnapshotテスト対象にできたりします。

button-story-default-docs-code.png

参考

21
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?