Next.jsでコードブロックにシンタックスハイライトで色を付ける
編集対象ファイルの全コード
シンタックスハイライトを付ける上で変更するのは、root/pages/blog/[id].tsxファイルのみです。最初に、このファイルの例を貼っています。
import { client } from "../../libs/client"; import type { Article } from '../../types/article'; import styles from '../../styles/Home.module.css' import Head from 'next/head' import cheerio from 'cheerio'; import hljs from 'highlight.js'; import 'highlight.js/styles/night-owl.css'; import {endpoint} from '../index' type props = { article: Article, highlightedBody:string, tableOfContents:content[] }; type content = { text: string; id: string; name: string; } export default function BlogId({article, highlightedBody, tableOfContents}:props) { return ( <div className={styles.container}> <Head> <title>{article.title}</title> <meta name="description" content={article.description} /> <link rel="icon" href="/favicon.ico" /> </Head> <main className={styles.postmain}> <h1 className={styles.title}>{article.title}</h1> <div className={styles.toc}> <h4>目次</h4> <ul id="lists"> {tableOfContents.map(content => { if (content.name == "h2"){ return <li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li> }else if (content.name=="h3"){ return <ul><li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li></ul> }else if (content.name=="h4"){ return <ul><ul><li id={content.name} key={content.id}> <a href={"#" + content.id}>{content.text}</a> </li></ul></ul> } })} </ul> </div> <div className={styles.post} dangerouslySetInnerHTML={{__html: highlightedBody}}/> </main> </div> ); } // パス指定 export const getStaticPaths = async () => { const data = await client.get({ endpoint: endpoint }); const articles: Article[] = data.contents; const paths = articles.map((content) => `/`+endpoint+`/${content.id}`); return { paths, fallback: false }; }; // データをテンプレートに受け渡す export const getStaticProps = async (context: any) => { const id = context.params.id; const res:Article = await client.get({ endpoint: endpoint, contentId: id }); // autoでシンタックスハイライトを付ける const $ = cheerio.load(res.body) $('pre code').each((_, elm) => { const result = hljs.highlightAuto($(elm).text()) $(elm).html(result.value) $(elm).addClass('hljs') }) const headings = $('h2, h3, h4').toArray() const toc:content[] = headings.map((data) => { return { //@ts-ignore text: String(data.children[0].data), id: data.attribs.id, name: data.name, } }) return { props: { article:res, highlightedBody:$.html(), tableOfContents:toc }, } };
各処理の紹介
ハイライト付HTMLの作成
getStaticProps内で、ハイライトされたHTMLを作成します。
const $ = cheerio.load(res.body) $('pre code').each((_, elm) => { const result = hljs.highlightAuto($(elm).text()) $(elm).html(result.value) $(elm).addClass('hljs') }) return { props: { article:res, highlightedBody:$.html(), tableOfContents:toc }, }
今回は言語を指定せず、オートで言語を判断させています。
$.html()がHTML要素になるので、これを引数として渡せばOKです。
ハイライト付HTMLの表示
export default function XXX の中に記載します。
export default function BlogId({article, highlightedBody, tableOfContents}:props) { return ( <div className={styles.container}> // 省略 <div className={styles.post} dangerouslySetInnerHTML={{__html: highlightedBody}}/>
まず、引数でハイライト付HTML(例のhighlightedBody)を受け取ります。
これを表示するのに変更が必要な箇所は、例の最後の行のように、ハイライト済みのHTML要素を指定するところだけです。