Next.jsでmdxを使ってみる
はじめに
mdxが気になっていた今日このごろ。
Next.js
と一緒に使ってブログとか作れたら面白そうと思ったので、
Next.jsでmdxを使えるところまで試してみる。
TL;DR.
mdxとは
MDX is an authorable format that lets you seamlessly use JSX in your markdown documents. You can import components, like interactive charts or notifications, and export metadata. This makes writing long-form content with components a blast.
(mdxのGithubから引用)
とのことなので、ざっくりいうとJSXが書けるmarkdown。
markdownだとやりにくい細かいレイアウトの調整とかやりやすそうである。
準備
必要なファイル、ライブラリの準備をする。
Next.js
ベースで進めるので、create-next-app
からスタート。
# デフォのままだとjsなので、ts対応したexampleから始める
$ npx create-next-app --example with-typescript mdx-sample
$ cd mdx-sample
# mdx追加
$ yarn add yarn add @next/mdx @mdx-js/loader
next.config.js修正
ページとしてmdx
を使えるように、next.config.js
を修正する。
↑の通りに進めるとおそらく無いので作るところから。
$ touch next.config.js
const withMDX = require('@next/mdx')({
extension: /\.mdx?$/
});
module.exports = withMDX({
pageExtensions: ['ts', 'tsx', 'md', 'mdx']
});
サンプルページ追加
早速mdxでページを作ってみる。
# pages配下にmdxファイルを追加
$ touch pages/hello.mdx
コードは下記の様にした。
# sample
ここから↓がjsx.
<article>
<h1>Hello World!</h1>
<div style={{backgroundColor: 'red', fontSize: '200%'}}>
sample text.
</div>
</article>
yarn dev
で起動後、localhost:3000/hello
で↓の様な画面が表示されればOK。
component読みこむ
header component作成
次にmdxで実際にcomponentを読み込んでみる。
まずはお試しのコンポーネントを作るところから。
import React from 'react';
import style from './Header.module.css';
interface Props {
heading: string,
color?: 'red' | 'blue'
}
export const HeaderComponent: React.FC<Props> = ({heading, color}) => {
if (!color) {
return <h1 className={style.header}>{heading}</h1>;
}
switch(color) {
case 'red':
return <h1 className={`${style.header} ${style['header--red']}`}>{heading}</h1>;
case 'blue':
return <h1 className={`${style.header} ${style['header--blue']}`}>{heading}</h1>;
}
}
.header {
font-size: 28px;
}
.header--red {
color: red;
}
.header--blue {
color: blue;
}
mdx修正
import {HeaderComponent} from '../components/header/Header.tsx';
# sample
ここから↓がjsx.
<article>
<HeaderComponent heading="Hello World!"/>
<div style={{backgroundColor: 'red', fontSize: '200%'}}>
sample text.
</div>
</article>
<article>
<HeaderComponent heading="Hello World!" color="red"/>
<div style={{backgroundColor: 'red', fontSize: '200%'}}>
red heading.
</div>
</article>
<article>
<HeaderComponent heading="Hello World!" color="blue"/>
<div style={{backgroundColor: 'red', fontSize: '200%'}}>
blue heading.
</div>
</article>
↓の画像のように変更されていればOK。
コードブロック作ってみる
mdのコードブロックでシンタックスハイライトが効かないっぽかったので自作する。
これは絶対うまいやり方がある気がするので一旦試してみるところまで……
ライブラリ追加
$ yarn add prism-react-renderer
コンポーネント作成
import React from 'react';
import Highlight, {defaultProps, Language} from 'prism-react-renderer';
export const CodeBlockComponent: React.FC<{ code: string, language: Language }> = ({code, language}) => {
return (
<Highlight {...defaultProps} code={code} language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={className} style={{...style, padding: '20px'}}>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({line, key: i})}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
};
mdx修正
import {HeaderComponent} from '../components/header/Header.tsx';
import {CodeBlockComponent} from '../components/codeblock/CodeBlock.tsx';
# sample
ここから↓がjsx.
<article>
<HeaderComponent heading="Hello World!"/>
<div style={{backgroundColor: 'red', fontSize: '200%'}}>
sample text.
</div>
</article>
<article>
<HeaderComponent heading="Hello World!" color="red"/>
<div style={{backgroundColor: 'red', fontSize: '200%'}}>
red heading.
</div>
</article>
<article>
<HeaderComponent heading="Hello World!" color="blue"/>
<div style={{backgroundColor: 'red', fontSize: '200%'}}>
blue heading.
</div>
</article>
<CodeBlockComponent
code={`
const hoge = 'hoge';
console.log(hoge);
`}
language="javascript"
/>
↓はハイライトされない
```js
const hoge = 'hoge';
console.log(hoge);
↓の様にコンポーネントに渡した方はちゃんとハイライトが効くようになる。
まとめ
今回はNext.jsでmdxを使うのを試してみた。
記事中にも書いたけど、絶対syntax highlightはより良いやり方があると思うので調べておきたい。