logo

ブログを作ってみました

2023/1/9

概要

Next.js, react-markdown, react-syntax-highlighter, tailwindCSS, Figmaらを使って簡単な機能があるブログを作ってみました。 Vercelを使って公開しています。

Blogはこちら

  • 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 を追加しました。

rehypePlugins

rehype-raw

Tailwind CSS

CSSはTailwindCSSを使いました。 巣のCSSのように自由にデザインができるけど、簡単に統一したデザインができるし、個人的に使い慣れているからです。

マークダウンのスタイリング

md md2

マークダウンを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">

Responsive Design

記事内のcode blockのスタイリング

highlight highlight2

react-syntax-highlighter を利用しました。 react-markdownでコードをシンタックスハイライトさせるフログを参考にしました。

まずはcodeblockを整形するコンポーネントを作ります。

CodeBlock.tsx
import { 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>

react-markdownから利用する方法

目次を作る

二つ方法がありましたが、後者の方のrehype-tocを利用しました。

remark-tocを利用

最初は remark-tocを使って目次を作る方法です。導入はとても簡単でremark-tocrehype-slugをinstallし、 ReactMarkdownのremarkPluginsrehypePluginsにそれぞれ追加するだけです。 remark-tocはhtmlからtocを作ってくれるもので、rehype-slugはh1, h2のような見出しタグにidを付与して目次のリンクから各項目に飛べるようにしてくれます。

remark-toc

rehype-slug

$ 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>

以下のように、マークダウンの中に「目次」と書いてあるところの下に作られます。(装飾は自分のでデザインに引っ張られているだけ。)

toc1

rehype-tocを利用

rehype-tocrehype-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の一番上に自動で目次が作られます。

toc2

lighthouse / SEO

Chrome ブラウザの lighthouse を回して引っかかったものを追加しました。 meta tag、robot.txt, imageのlazyloadなど色々指摘してくれたので修正しました。

lighthouse lighthouse2

最後

ブログでもなんでもいいと思いますが、自分のWebpageを持っていると自由に遊べるテーマパークができたようで楽しいです。 もっと整ったらソースコードも公開して見ようと思います。

blog作成に参考したURL