エンジニアなら自分でブログを作れ!③Markdownのカスタマイズ編
初めに
この記事は「エンジニアなら自分でブログを作れ!」の第三弾です。
第一弾や第二弾を読んでいなくても問題ありませんが、特に第一弾では無料の自作ブログを作成するために必要な導入について解説しているので良ければご覧ください。
第一弾↓
第二弾↓
この記事はNext.jsの
blog-starter
(公式のデモページ)
について、デフォルトではとてもリッチとは言い難いMarkdownの出力をzennと同様のものにする方法を解説します。
デフォルトのmarkdown出力
blog-starterにおけるMarkdownからHTMLの出力は lib/markdownToHtml.ts
に実装されています。
export default async function markdownToHtml(markdown: string) {
const result = await remark().use(html).process(markdown)
return result.toString()
}
これはremarkというライブラリを経由して単純にHTMLにする実装のみが含まれています。
remarkについては以下が詳しいです。
また、CSSも components/markdown-styles.module.css
で定義された最小限しかありません。
.markdown {
@apply text-lg leading-relaxed;
}
.markdown p,
.markdown ul,
.markdown ol,
.markdown blockquote {
@apply my-6;
}
.markdown h2 {
@apply text-3xl mt-12 mb-4 leading-snug;
}
.markdown h3 {
@apply text-2xl mt-8 mb-4 leading-snug;
}
しかし、最近のブログサービスはもっとリッチなコンテンツを入れられてCSSも綺麗ですよね。ここは是非ともカスタマイズしたいです。
zenn-editor
この記事が投稿されているZennで使われている変換機構やCSSは、Github上でMITライセンスで公開されています。とてもありがたいことです。
これを使っていきましょう。
組み込み
インストール
まずは必要なパッケージをインストールしましょう。
過去の記事に従っていればDockerで環境構築されているはずなので、まずは立ち上げましょう。
$ docker-compose up -d
次に、以下のコマンドでコンテナ内でyarnコマンドを使ってインストールしましょう。
$ docker-compose exec app yarn add zenn-markdown-html@0.1.106 zenn-markdown-css@0.1.106 zenn-embed-elements@0.1.106
zenn-markdown-html
その名の通りZennで使われているMarkdownをHTMLに変換するパッケージです。
使い方は非常にシンプルで、lib/markdownToHtml.ts
の変換部分を置き換えるだけです。
- import { remark } from 'remark'
- import html from 'remark-html'
+ import m2h from "zenn-markdown-html";
export default async function markdownToHtml(markdown: string) {
- const result = await remark().use(html).process(markdown)
- return result.toString()
+ return m2h(markdown)
}
これでhtmlへの変換がリッチになり、ZennのMarkdown記法も変換できるようになったはずです。
zenn-content-css
Zennで使われているCSSです。こちらも組み込んでいきましょう。
まず pages/_app.tsx
でCSSをインポートします。
import { AppProps } from 'next/app'
import '../styles/index.css'
+ import 'zenn-content-css'
export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
このCSSはzncというクラスがついている要素の配下で機能します。ですので components/post-body.tsx
を以下のように変更しましょう。
const PostBody = ({content}: Props) => {
return (
- <div className="max-w-2xl mx-auto">
+ <div className="max-w-2xl mx-auto znc">
<div
className={markdownStyles['markdown']}
dangerouslySetInnerHTML={{__html: content}}
/>
</div>
)
}
これでCSSの組み込みも完了です!
zenn-embed-elements
次にZennの埋め込みコンテンツへの対応もやっていきます。
pages/posts/[slug].tsx
を編集します。
import { useRouter } from 'next/router'
import ErrorPage from 'next/error'
import Container from '../../components/container'
import PostBody from '../../components/post-body'
import Header from '../../components/header'
import PostHeader from '../../components/post-header'
import Layout from '../../components/layout'
import { getPostBySlug, getAllPosts } from '../../lib/api'
import PostTitle from '../../components/post-title'
import Head from 'next/head'
import { CMS_NAME } from '../../lib/constants'
import markdownToHtml from '../../lib/markdownToHtml'
import type PostType from '../../interfaces/post'
+ import {useEffect} from "react";
+ import initTwitterScriptInner from "zenn-embed-elements/lib/init-twitter-script-inner";
type Props = {
post: PostType
morePosts: PostType[]
preview?: boolean
}
export default function Post({ post, morePosts, preview }: Props) {
const router = useRouter()
if (!router.isFallback && !post?.slug) {
return <ErrorPage statusCode={404} />
}
+ useEffect(() => {
+ import('zenn-embed-elements');
+ }, []);
return (
<Layout preview={preview}>
+ <script
+ dangerouslySetInnerHTML={{
+ __html: initTwitterScriptInner
+ }}
+ />
<Container>
<Header />
{router.isFallback ? (
<PostTitle>Loading…</PostTitle>
) : (
<>
<article className="mb-32">
<Head>
<title>
{post.title} | Next.js Blog Example with {CMS_NAME}
</title>
<meta property="og:image" content={post.ogImage.url} />
</Head>
<PostHeader
title={post.title}
coverImage={post.coverImage}
date={post.date}
author={post.author}
/>
<PostBody content={post.content} />
</article>
</>
)}
</Container>
</Layout>
)
}
これで埋め込みコンテンツに対応できました!
確認
ブログの投稿をいじって色々試してみましょう。_posts/hello-world.md
の本文にZenn公式が出しているMarkdownの使い方の記事をそのまま入れてみます。
長いので差分はここには貼りません。Github上で確認してください。
(zenn-docsのライセンスは書かれていませんでしたが引用の範囲で利用しているつもりです。まずかったら教えてください。)
最新版では無いからかごく一部使えないものもありますが、問題ない範囲だと思います。
以下のスクリーンショットはZennのものではなく、ローカルで立ち上げたブログのものです。
まとめ
この記事では自作ブログにZennのMarkdownとCSSを導入するやり方を解説しました。
次回もブログをカスタマイズしていく方法について解説したいと思っていますので、是非よろしくお願いします。
最後に、私の投稿はZenn以外の投稿もまとめて以下ブログで取得できますので、良ければ見てみてください。
追記
次回
Discussion
素敵な投稿をありがとうございます。
必要なパッケージをインストールするコマンドのCSSのパッケージ名が
zenn-markdown-css となっていますが、zenn-content-css
ではないかと思いましたので、コメントさせていただきます。
気づかずすみません。
コメントありがとうございます。
おそらくzennのライブラリに変更があり、手順が一部陳腐化しているようです。
詳しくはzenn-editorのリポジトリを参照してください。