会社やめて少しずつやる気が出てきたので、少しずつサイト更新。
Next.jsでSSGして成果物を放り込むという運用は継続しつつ一旦壊して再構築みたいなことをしてます。
Tailwind CSSを使用していましたが、導入がやや面倒なのとcss書いているというよりtailwind書いてる感が出てきたので乗り換えたいと思っていくつか試した中でgooberを選びました。
選んだ理由が「css書きたいけどcssファイルは作りたくないし、テンプレートに直に書きたい。でもstyle属性だとちょっと不便」なので下記のような使い方になっています。
<div className={css`
margin: 0;
padding: 0;
`}>
以前は@mdi/jsでちょこっとアイコンを入れていました。
やる気は出てきたけど、アイコン導入は面倒になってきたので全てテキストに。
以前はshowdown.jsでMarkdownをHTMLに変換したものをdangerouslySetInnerHTML
で描画していましたが、描画周りはReactで制御したいということでRemarkを使ってASTを取り扱うようにしました。
自前でcssファイルは置きたくなかったので、以前の構成だとtailwindでスタイルを当てるためにこのようなshowdown.jsの拡張を作成。
const classes: {[key:string]: string} = {
h1: '',
h2: 'my-6 text-xl md:text-2xl pb-1 border-b',
h3: 'my-3 text-lg md:text-xl',
h4: '',
h5: '',
h6: '',
p: 'my-3 text-sm md:text-base',
a: 'text-red-600',
ul: 'my-3 ml-6 text-sm list-disc',
img: 'my-3',
video: 'my-3',
pre: 'hljs my-3 text-sm md:text-base'
}
export default Object.keys(classes).map(key => ({
type: 'output',
regex: new RegExp(`<${key}(?: (.*)>|>)`, 'g'),
replace: `<${key} class="${classes[key]}" $1>`
})).concat({
type: 'output',
regex: /(?<!(?:<pre(?: (.*)>|>)))(?:\n?\s*<code(?: (.*)>|>))/g,
replace: '<code class="bg-gray-100 px-2 py-px mx-px" $1>'
})
これをもっとReactでやりたい放題したいということでRemarkに移行したあと、例えばpタグだとこのようなコンポーネントを作成。
export const AppMarkdownParagraph = ({ node }: Props) => {
return (
<p className={css`
font-size: 16px;
margin: 16px 0;
color: ${color['grey-5']};
`}>
{node.children.map((node, i) => (
<AppMarkdown
key={i}
node={node}/>
))}
</p>
)
}
同じ要領で各ノード種別毎にコンポーネントを作成してそれらをまとめたコンポーネントを作成しました。
コンポーネント未作成のノードが使用されてたら例外を投げて、ビルド時に気付くようになってます。
export const AppMarkdown = ({ node }: Props) => {
if (node.type === 'root')
return <AppMarkdownRoot node={node} />
if (node.type === 'paragraph')
return <AppMarkdownParagraph node={node} />
if (node.type === 'text')
return <AppMarkdownText node={node} />
if (node.type === 'list')
return <AppMarkdownList node={node} />
if (node.type === 'listItem')
return <AppMarkdownListItem node={node} />
if (node.type === 'image')
return <AppMarkdownImage node={node} />
if (node.type === 'heading')
return <AppMarkdownHeading node={node} />
if (node.type === 'code')
return <AppMarkdownCode node={node} />
if (node.type === 'link')
return <AppMarkdownLink node={node} />
if (node.type === 'inlineCode')
return <AppMarkdownInlineCode node={node} />
if (node.type === 'video')
return <AppMarkdownVideo node={node} />
throw new Error(
`Not something we can render: ${node.type}`
)
}
これでMarkdownの中身をReactでやりたい放題したいという願望が叶いました。
実はhugoぐらいしか静的サイト生成ツールを試したことがないので、Gatsbyとかもお試ししつつ少しずつ。