前置き
最近はReactやらVueやらを日々触っている人です。
ここらでひとつ個人的な技術ブログやらポートフォリオやらを作ってみようかと思いひと調べしたところ、なんだかSEOとかパフォーマンスとかを考慮すると一周回って静的サイトが今イケてるんじゃないかと思いまして。
というのもコンテンツ内容とかを考えるとブログにSSRだPWAだというのはややファットというか、オーバーエンジニアリング感がありまして、あと正直色々考えるのがめんどくさいのでそのへんいい感じにミニマムにできてくれ〜〜というヨコシマな思いもあり。
で、JSベースの静的サイトジェネレーターとしてはNuxt.jsだったりNext.jsだったりGatsbyだったりと色々と選択肢があるわけですが、今回はそれらよりも後発のReact Staticが一番そのへんの省エネメンタリティにフィットしそうだったので使ってみました。本音をいうとミーハーなのでより新しいやつが使いたかった。
React Staticを使う理由
以下、個人的バイブス偏重甚だしい理由でReact Staticを持ち上げますので、その優位性に関しては公式のイントロダクションが良い感じにまとめてありますのでご一読ください。聡明なエンジニア諸氏におかれましては英語でも全く問題ないと思います。すみません僕はややしんどかったです。
なぜReact Staticを使ってみることにしたか?というと、静的サイトを生成する機能を持ったJSフレームワークを色々と触ってはみたものの、それぞれにとても良かったのですが、「したかったこと」に対して今ひとつハマらなかった点があったためです。
Next.js
まずシンプル、ミニマル、なんかシュッとしてるでおなじみのNext.jsはさすがの完成度というか、こりゃオシャレな使い心地やでェ〜サイコ〜〜というのが触り始めの感想だったのですが、当然ながらSSRを手軽に実装することが目的のフレームワークですので、静的サイトのジェネレートはあくまでオマケという印象でした。
静的サイト構築をメインに使おうとするとHot reloading周りとかで地味にハマったりした記憶があります。あとpugとstyled jsxのかみ合わせがあまり良くなかった。pug使いたかった。
Nuxt.js
同じくあんまり深く考えなくてもいい感じにSSRを提供してくれるVue.js界の雄Nuxt.jsも、肌触りの良い使い心地でスラスラとサイトが組み上がりとっても良いです。pugもsassもstylusもTypescriptもなんでもござれという懐の深さで、基本これでいいんじゃないかな?というスキのなさですが、当然ながらVue及びNuxtの流儀を覚える必要があります。
Vueのほうが好き!という方はNuxt.jsオススメです。でも今回はなんとなくReact使いたかった。
Gatsby
そしてそしてReactを使って猛烈にチューニングされた静的サイトを吐き出してくれるスーパーイケメンGatsby。上記2つと違いピュアな静的サイトジェネレータとしてこの世に生を受けたフレームワークなので、選択肢的には本命です。実際パフォーマンスも良いしService Workerもついでに設定してくれるのでPWA化できるしGraphQLでデータフェッチできるしで完璧です。ぜひ使いましょう。
ただ本当に申し訳ないんですがGraphQLが僕にはややめんどくさかった。勉強して出直してきます。
ということでReact Staticです。
お察しの通り、わたしが「したかったこと」は「楽」です。
React Staticのおもしろいところ
こちら公式のOverviewとなっておりますのでご査収ください。
個人的におもしろいなと思ったのは、ビルド時にheadlessCMS等のデータソースからデータをフェッチし、ページツリー内のそれぞれの静的ページごとに使うデータを小分けにして静的なjsonファイルとして設置しておいてくれるところです。
なんのこっちゃという文で申し訳ないですが、要はブログであれば記事ごとの内容データをあらかじめ記事HTMLとセットでローカルに配置しておいてくれるんですね。
ふつうのSPAとかであれば
- 表示時に一旦HTTPリクエストを行ってデータソースから記事データを引っ張ってくるなりして
- それをpropsに渡して
- その情報を元に色々レンダーする
ということが必要だったわけですが、その通信が必要なくなるという事です。省エネ感ありますね。
実コードでみてみましょう。
一部抜粋ですが、ビルド時にジェネレートするルーター情報などの設定ファイルの内容です。
export default {
getRoutes: async () => {
// 今回はCMSとしてContentfulを使っているので、そのクライアントモジュール
const { items: posts } = await client.getEntries({
content_type: 'post',
})
return [
{
path: '/',
component: 'src/containers/Home',
getData: () => ({ posts }), // そのページ内で使用するデータを渡す
children: posts.map(({ fields: post }) => ({
path: post.articleId, // URLに記事IDを使いたいので動的にルーター設定
component: 'src/containers/Post',
getData: () => ({
post,
}),
})),
},
]
},
}
どのURLで、どのComponentを使って、どういったデータをpropsとして渡すか、という情報を簡潔に記述できます。
npm run build
を実行してジェネレートされたファイル郡が以下です。
test_kiji
というのが記事IDなので、ビルド時のデータフェッチで取得した記事の数だけディレクトリとindex.html
とrouteInfo.json
がジェネレートされる事になります。
{
"path":"test_kiji",
"templateID":1,
"sharedPropsHashes":{},
"localProps":{
"post":{
"articleId":"test_kiji",
"title":"テスト記事",
"article":"ちなみにCMSはContentfulを利用しました",
},
},
}
なるほど。
半ば力技とも言えますが、こうした仕組みの恩恵によりクライアント表示時にPreloadを行えたりするのですごいです。
また、ビルド時にHTMLをあらかじめレンダーしておくことにより、クライアントのファーストビュー時にはそれをサッと表示し、あとからこっそりReactをその上にマウントしてSPAにしちゃう事になっているようで、大変素晴らしいです。語彙が消失してきました。
書いてみてどうなのか
個人的に嬉しかったのは、ビルド時に利用データの取得と各コンポーネントへの分配を一気にやるスタイルなので、やれReduxだVuexだというステート管理の諸々だとか、データをロードしている間のローディングをどうごまかすだとか、従来のSPAで地味にめんどくさかった事をあまり気にしなくて良いところでした。
基本パパパーッとStateless Functional Componentsとしてまとめていけるのは可視性も高くてスッキリ気分が良いです。
と言いつつ結局はReactで組んでいるので、ページ遷移アニメーションとか色々凝ったことにも手を出して発展させていけるというのもステキだなと。
シンプルに小さめにまとめられるので、React初学者の方とかにもおすすめできるんじゃないかなと思っています。
「見たところ成果物がないんですけど」
この文を読んでいるということは僕は記事公開までにデプロイできなかったということですね。すみません。
いっちょアドベントカレンダーに寄稿してみようということで書き始めたのですが、イキって掲載日をだいぶ早めのところにしてしまった事が敗因です。反省しています。後ほどこっそり成果物を公開すると思いますので。
追記
↓↓↓ React Staticを利用した技術ブログをつくりました。 ↓↓↓
4RCHIV3S
あまりお上品ではないソースはこちら
おわり
内容のわりにだいぶ長ったらしい記事になってしまいました。
Reactからやや離れ、Vueをしばらく書いていたのですが久々にReactを書いてみるとやはりキュートだなと思いました。
React Staticはまだプロダクトとして若く、やや荒削りではありますがシンプルさが魅力的です。
Qiitaにはまだあまり記事が上がっていなさそうですが、みなさまもぜひ気軽に一度触ってみていただけますと幸いです。