きっかけ
以前のサイトはRust言語でできたYewというWASMに変換するフロントエンドのフレームワークを用いていました。
しかし以下の欠点あります。
- あまり周辺ライブラリが揃っていない
- wasmファイルのサイズが大きかったり、初期ロードの時間があったりして、(キャッシュがない状態では)サイト全体が表示されるまで10秒以上かかる
SEO対策のためにプリレンダーをしていたが、docker-composeでwebpackを動作させると、pkgフォルダーを読み込めないというエラーが出るようになりました。entryのファイルはwasmが出力された後に実行してほしいが、entryが先に実行されるようになったのが原因です。
少し格闘したが、欠点を思い出してここで時間を費やしても現状維持でしかなく、その時間があれば爆速のサイトを別の技術で開発した方がいいじゃないかと思い、開発する事に至りました。
要件
まず要件として
- 各記事はMarkdownファイルから自動生成
- 動的な部分も欲しいため、SSRを行う
- 以前のサイトとほぼ変わらないデザインにする
を挙げました。
基本的に有名なライブラリやフレームワークを用いれば実現できそうなサイトです。
技術選定
私のフロントエンドフレームワークの知識は
Vue
をバイトで使用React
やAngular
の名前は知っている
という状態なので、使用する技術の選定から始めることにしました。
きっかけにあるようにwasmを用いるようなマイナーな技術では、自分で実装しないといけないことをしみじみと感じました。
そのため以下の順でフロントエンドフレームワーク、選定することにしました。
- 一番有名なフレームワーク
- 今後数年も発展していきそうか
一番有名なフレームワーク
個人的に一番有名であることのメリットとして、ライブラリやベストプラクティスが発達しており、メンテナンスもしっかりされていると所だと思います。
更に私はPHPのLaravel
をよく触っており、その恩地を受けてきて、有名である重要性を感じてきました。
どれが有名か調べてみると、React
がダウンロード数や検索数がここ近年圧倒的に多いことがわかりました。
またSSR
を使用するうえでは、Next.js
一択しかないと思いそちらも使用することにしました。
今後数年も発展していきそうか
発展しなければすぐサイトをリニューアルしなければならなくなるので、こちらも念のため考えることにしました。
フレームワークが危うくなる原因として、他の言語のものや他の技術が発展して圧倒的に開発しやすくなり、皆がそちらを使いだすことだと思っています。
個人的にWebAssembly
やGraphQL
が将来的に発展しそうな技術です。
WebAssembly
WebAssembly
は速度とか速くなったり、色々なプラットフォームでも使えたりして、とても推しています。
しかしJavaScript
でも十分速いし、置き換えるためのコストがとても高く、広く使われるのは先かまたは使う人が少なくメンテナンスする人も減り廃れていく可能性があります。
GraphQL
GraphQL
ではApollo
というプラットフォームがあり、GraphQL
に最適化されています。
しかしNext.js
でも問題なく使用できそうなので、わざわざそちらを学んで使う必要はないと思う人が多そうと感じました。
以上からReact/Next.js
を使うことにしました。
学習
TypeScript
まずHandbookを読んで概要をつかむことにしました。
型アノテーションとかがRustと似ていたりして、馴染みがありました。
Unionの変数の扱い方やinterfaceとtypeの二つあることは、馴染みがありませんでした。
総合的には、型の安全性と記述量が増えないようにすることに関して、バランスがよくとれている言語だと思いました。
Next.js
Next.jsの公式サイトのStart Learning
で学ぶと良いという情報を頂いたので、次に進めていきました。
Markdown
の記事からHTML
に変換して表示させるサイトを作っていく内容でした。
また基本的な処理だけでなく、SEOについての説明とかもあり、とてもぴったりな内容でした。
サイトのリニューアル
先程の学習を活かして、現在のサイトを置き換えていきました。
見た目
html!
が書いてある見た目の部分を移植するところから始めました。
HTML
HTML
の部分は
class
アトリビュートをclassName
- ルート部分を
Link
img
タグをImage
- svgのアトリビュートをキャメルケース
- 処理の必要な部分を消去 のみ変更しました。
以下のようにYew
でもReact
でも内部処理の扱い方は変わらないので、ほとんど問題なく移行できました。
{ "Hello World!" }
CSS
デザインはTailwind CSS
を使っていたので、以下のように入れました。
npm install tailwindcss postcss-preset-env postcss-flexbugs-fixes
特に問題はなかったのですが、Tailwind
のバージョンが3.0.0
になっててびっくりしました。
postcss.config.js
とtailwind.config.js
はそれぞれ以下のようになりました。
module.exports = {
plugins: [
'tailwindcss',
'postcss-flexbugs-fixes',
[
'postcss-preset-env',
{
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3,
features: {
'custom-properties': false
}
}
]
]
}
module.exports = {
purge: [
'./pages/**/*.tsx',
'./components/**/*.tsx'
],
// ...
}
処理
MarkdownからHTML
unified
を使って変換を行いました。
これによりコードのハイライトなど様々なことができるようになりました。
import {unified} from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeSlug from 'rehype-slug'
import rehypeHighlight from 'rehype-highlight'
import rehypeStringify from 'rehype-stringify'
//...
const processedContent = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeSlug)
.use(rehypeHighlight)
.use(rehypeStringify)
.process(matterResult.content)
Meta情報の取得とエラー
gray-matter
により、以下のようにmarkdown
ファイルの上部に記入した内容を取得することができます。
---
title: たいとる!!!
published_time: 2021-12-14T12:00:00+09:00
modified_time: 2021-12-14T12:00:00+09:00
---
const matterResult = matter(fileContents)
しかし以下のようなエラーがでてくることがあります。
Server Error
Error: Error serializing `data.published_time` returned from `getStaticProps` in "/".
Reason: `object` ("[object Date]") cannot be serialized as JSON. Please only return JSON serializable data types.
対応していないDateTime
型のデータをそのまま読み込もうとしているため、エラーが起こっています。
そのためpublished_time.toISOString()
というようにstring
型に直して対処しました。
デプロイ
速度
これまで最初の表示まで10秒程度かかっていたので、とても爆速になりました。
React/Next.jsで開発してみて
検索やsvgをリアルタイムでアニメーション処理していた部分は実装できていないが、主な部分は移行できました。
Vue
だとフレームワークを使っているという感じが強かったが、React/Next.js
は言語をそのまま書いているように感じました。
まだ状態管理部分にあまり触れられていないので、結局どちらの方が使いやすいか調べていきたいです。