ブログを作ってみました
2023/1/9
概要
Next.js, react-markdown, react-syntax-highlighter, tailwindCSS, Figmaらを使って簡単な機能があるブログを作ってみました。 Vercelを使って公開しています。
- DBは使わずマークダウンで記事を書くとhtmlに反映
- 記事にtagをつけてtag一覧を生成
- 記事のイメージをS3などの外部Storageは使わない(githubでマークダウンファイルを作って記事を直接書くと、イメージもアップロードしてURLが生成されるので)
- 記事のサムネイルだけはpublic配下におく
機能一覧
最小限の機能を入れています。
- マークダウン記事 → HTML表示
- 記事内のcode blockに色付き
- imageはimgタグを利用することでsize調節できるようにする
- 目次表示
- ロゴのアニメーション
- サイドメニュー表示
- profileページ作成
- tag機能追加
- レスポンシブ
- SEO(meta tag, lighthouse, image lazy-load, robot.txt)
今後追加したいもの
- dark mode
- 共有機能
- 検索機能
- 記事の公開非公開機能
- コメント機能
- thumbnailジェネレータ
- E2Eテスト
実装方法
マークダウン記事 → HTML表示
最初はremark-htmlとdangerouslySetInnerHTML使ってマークダウンをhtml化しましたが、react-markdownに変えました。 react-markdownの方が色んなプラグインをつけやすいし、全体的に簡単に書けたからです。
<ReactMarkdown rehypePlugins={[rehypeRaw]} components={CodeBlock} remarkPlugins={[gfm]} className="prose prose-stone mt-5 max-w-4xl m-auto" > {post.content} </ReactMarkdown>
rehype Pluginsで使いたいプラグインをnpm installして、rehypePlugins
propsに追加します。
markdownの中でもHtmlタグが使えるように rehype-raw
を追加しました。
Tailwind CSS
CSSはTailwindCSSを使いました。 巣のCSSのように自由にデザインができるけど、簡単に統一したデザインができるし、個人的に使い慣れているからです。
マークダウンのスタイリング
マークダウンをhtmlにする時に、TailwindCSSのtypography-pluginを利用すると簡単にデザインが適応されます。 @tailwindcss/typographyをインストールしてmarkdownを囲んでいるクラスにproseとつけるだけです。
<article class="prose prose-xl"> {{ markdown }} </article>
上記の ReactMarkdown
のclass名にも同じくつけています。
レスポンシブ
tailwind.config.js
ファイルに画面サイズを定義して置いて、
theme: { screens: { tablet: "640px", laptop: "1024px", desktop: "1280px", }, }
classで tablet:grid
のように利用します。以下の例は記事リストのカード配置のclassです。
<div className="flex flex-col justify-center space-y-8 tablet:grid tablet:grid-cols-2 tablet:gap-2 tablet:space-y-0 desktop:grid-cols-3">
記事内のcode blockのスタイリング
react-syntax-highlighter
を利用しました。
react-markdownでコードをシンタックスハイライトさせるフログを参考にしました。
まずはcodeblockを整形するコンポーネントを作ります。
CodeBlock.tsximport { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { a11yDark } from "react-syntax-highlighter/dist/cjs/styles/prism"; import { CodeComponent } from "react-markdown/lib/ast-to-react"; const customCode: CodeComponent = ({ inline, className, children }) => { const style = a11yDark; const match = /language-(\w+)(:?.+)?/.exec(className || ""); const lang = match && match[1] ? match[1] : ""; const name = match && match[2] ? match[2].slice(1) : ""; return !inline && match ? ( <> {name && <span className="bg-stone-200 py-1 px-2 text-xs">{name}</span>} <SyntaxHighlighter style={style} language={lang} PreTag="div" className="md-codeblock" > {String(children).replace(/\n$/, "")} </SyntaxHighlighter> </> ) : ( <code className="rounded-md bg-stone-200 text-red-600">{children}</code> ); }; export const CodeBlock = { code: customCode, };
色んな highlighter styleの指定が可能です。私は a11yDark
を選びました。
prism-themes
ReactMarkdown propsの components
に作ったCodeBlockを追加するだけでOK
<ReactMarkdown rehypePlugins={[rehypeRaw]} components={CodeBlock} remarkPlugins={[gfm]} className="prose prose-stone mt-5 max-w-4xl m-auto" > {post.content} </ReactMarkdown>
目次を作る
二つ方法がありましたが、後者の方のrehype-toc
を利用しました。
remark-tocを利用
最初は remark-tocを使って目次を作る方法です。導入はとても簡単でremark-toc
とrehype-slug
をinstallし、
ReactMarkdownのremarkPlugins
とrehypePlugins
にそれぞれ追加するだけです。
remark-toc
はhtmlからtocを作ってくれるもので、rehype-slug
はh1, h2のような見出しタグにidを付与して目次のリンクから各項目に飛べるようにしてくれます。
$ npm install remark-toc $ npm install rehype-slug
<ReactMarkdown rehypePlugins={[rehypeRaw, rehypeSlug]} components={CodeBlock} remarkPlugins={[gfm, [remarkToc, { maxDepth: 2, heading: "目次" }]]} remarkPlugins={[gfm]} className="prose prose-stone mt-5 max-w-4xl m-auto"> {post.content} </ReactMarkdown>
以下のように、マークダウンの中に「目次」と書いてあるところの下に作られます。(装飾は自分のでデザインに引っ張られているだけ。)
rehype-tocを利用
rehype-toc
とrehype-slug
を使って目次を作る方法です。
同じくnpmでinstallし、今回は両方ともrehypePlugins
に追加します。
rehype-toc
より多くのオプションが指定できました。tocOptions
として別途optionを作りました。
cssClasses
オプションを使ってclass名をつけると、それを付与したtocが作られます。
これで目次のデザインも自由にできます。
const tocOptions = { headings: "h2", cssClasses: { toc: "prose-toc", list: "prose", listItem: "prose-toc-list-item", link: "prose-toc-link", }, }; <ReactMarkdown rehypePlugins={[rehypeRaw, rehypeSlug, [rehypeToc, tocOptions]]} // rehypeTocとそのoptionを渡す components={CodeBlock} remarkPlugins={[gfm]} className="prose prose-stone mt-5 max-w-4xl m-auto" > {post.content} </ReactMarkdown>
作られる目次の中身
<nav className="prose-toc"> <ol className="prose prose-1"> <li className="prose-toc-list-item prose-toc-list-item-h2"><a className="prose-toc-link prose-toc-link-h2" href="#概要">概要</a></li> <li className="prose-toc-list-item prose-toc-list-item-h2"><a className="prose-toc-link prose-toc-link-h2" href="#state-of-css-2022">State of CSS 2022</a> </li> <li className="prose-toc-list-item prose-toc-list-item-h2"><a className="prose-toc-link prose-toc-link-h2" href="#まとめ">まとめ</a></li> </ol>
post.contentの一番上に自動で目次が作られます。
lighthouse / SEO
Chrome ブラウザの lighthouse
を回して引っかかったものを追加しました。
meta tag、robot.txt, imageのlazyloadなど色々指摘してくれたので修正しました。
最後
ブログでもなんでもいいと思いますが、自分のWebpageを持っていると自由に遊べるテーマパークができたようで楽しいです。 もっと整ったらソースコードも公開して見ようと思います。