React Static とは
Reactベースの静的サイトジェネレータです。
つまり、全てハードコードの静的サイトはもちろん、ブログのようなCMSベースのサイトも
- React+αの知識で!
- DBなしに!
- サーバーの(大した)設定もせず!
- 超高速表示に!
作れる優れもの。
僕のようなフロントエンドに知識が偏ってる人間には特に福音だったりします。
その中でもReact Staticは、Mediumで3,000clapを叩き出した記事 「2019年のReactジェネレータ」でもGatsbyに続き2番手に選ばれたイケてる子!
しかもGatsbyよりも学習コスト≒React+αのα部分が少ないと僕の中で噂に。
ということで公式ドキュメントの「基礎概念」(Core concepts)部分を以下に訳します。
続編 React Static 設定大全 https://qiita.com/IYA_UFO/items/b01ca2eb1ec0082c4b79
MIT License
Copyright (c) 2013-present, Nozzle, Inc.
https://github.com/nozzle/react-static/blob/master/LICENSE
概要
React Staticは他の多くのReactベースの静的サイトジェネレータとは異なります。データから静的ファイル、さらにはプログレッシブに強化された(progressively enhanced)Reactアプリケーションに至るまでのとても自然なデータの流れを持っています。これにより、「データ」と「テンプレート」の関心の分離を手軽に行えます。また、データとテンプレートを可能な限りはっきり分離し、React自身がそうであるように、データの写像としてのサイトを、1つの流れの中でビルド・視覚化することができます。
開発中に起きること
- サイトに必要な全てのデータは、事前に
static.config.js
に好きな方法で集められます。取得元はマークダウンファイル、ヘッドレスCMSs、GraphQLのエンドポイントからなどなど自由です。データはビルド段階でコンパイルされます。 - ページは1つのReactコンポーネントをexportするファイルとして定義され、必要なときにレンダリングされます。
pages
内のファイルは自動的にルーティングされます。 - ページコンポーネントを指定して、静的なルーティングを設定することも可能です。
- React Staticのコンポーネントにある
RouteProps
やSiteProps
を使ってルートごとのデータを取得しページをレンダリングすることができます。これらのコンポーネントのHOC版も利用できます。 - 以上を設定すれば、React Staticは正確に、スピーディーに全ページを出力します。
クライアントサイドで起きること
- 最初のロードでは、最速でページを表示するために最低限のアセットだけがダウンロードされます。これには、ページ特有のHTMLと、ビルド時にエクスポートされた全てのCSSが含まれます。
- そのページに同期的に必要なデータがHTMLから抽出されます。
- ReactがHTMLにアプリケーションをマウントします
- サイトの残りの部分は、ページ遷移が起こるたびにpreload・キャッシュされ、遷移は即座に起きているように見えます。
コード・データの分割
React Staticはとてもユニークで素晴らしいやりかたで、各ページに必要な最小限のデータをピッタリのタイミングでリクエストします。React Staticは以下の要素に従ってコードとデータを分割します。
ページテンプレート
static.config.js
にルートを書いておくだけで、React Staticは内部的・自動的に各ルート用のテンプレートを分割します。
ページデータ
各ルート用のgetData
関数の結果が、そのページ専用のJSONファイルとしてHTMLの隣にexportされます。これで9割のケースでデータをうまく分割できます。また、複数のページで何度もアクセスされるデータなどについてさらに最適化したい場合は、以下で説明するsharedData
とcreateSharedData
の2つのAPIでより詳しい操作が可能です。
サイトデータ
多くのルートで必要なデータは、config.getSiteData
関数に渡すことで全てのページからアクセスできるようになります。
react-universal-componentを使った手動のコード分割
React Staticはデフォルトでreact-universal-component
をサポートしています。つまり、React Staticが持つ自動コード分割に加え、必要であれば手動で巨大なコンポーネントを分割することができます。動的インポートの例を見てください。簡単です!
ページ共有データ(上級者向け)
ほとんどのプロジェクトでは必要ありませんが、稀に「全てのページで使うわけではないが、複数のページで全く同じデータを使う」場合があります。その対応には、ページ共有データAPIを使って複数ルートで同じデータを1つのJSONファイルとして共有することができます。例はこちら
ユニバーサルな、「Nodeセーフな」コードを書く
React StaticはブラウザとNode(ビルド中)の両方で動くため、コードの全てが「ユニバーサル」、言い換えれば「Nodeセーフ」であることがとても重要です。私達の多くはブラウザでJavaScriptを書くことになれているので、以下のような点に注意が必要です。
-
window
、document
やブラウザAPIを利用する場合、利用の前に存在チェックをしてください。最も簡単な方法は、これらを利用するコードをcomponentDidMount
の中に書くか、if文の中に書くことです。
if (typeof document !== 'undefined') {
// documentオブジェクトを使う
}
-
window
、document
やブラウザAPIに依存するライブラリがNode環境でインポートされないようにしてください。これらのライブラリの一部はブラウザのオブジェクトをすぐに必要とするので、ビルド時にエラーが出ます。エラーを解消するには、スタブを用意して条件分岐で内容をrequireしてください。
let CoolLibrary = {} // Nodeで動かす必要があるコードではこのスタブを利用する.
if (typeof document !== 'undefined') {
CoolLibrary = require('cool-library').default
}
環境変数
色々試すなかで、特定の環境変数が必要になるかもしれません。以下がReact Static全体で利用できます。
process.env.REACT_STATIC_ENV
以下のどれかになります
- production - webpackで本番用にビルド中
- development - webpackで開発用にビルド中
- node - nodeでSSR用にビルド中
本番用のビルド
本番用ビルドの前に、いくつか追加で準備することをおすすめします
-
static.config.js
にsiteRoot
を追加してください。siteRoot
によってReact Staticは絶対パスのリンクを最適化します。また、もしもアプリケーションがhttps://mysite.com/my-static-site/
などルート以外の場所で動作する場合も、この設定により普通に機能するようになります。 -
react-static build --staging
を使って、ローカルで本番ビルドをテストしてください。このコマンドでは、本番用のビルドを行いますが、特別にlocalhostで普通に見られるようになります。 - 本番ビルドでバグを見つけたら、ビルドコマンドに
--debug
をつけてコードの圧縮を停止できます。
ビルドの準備ができたら、react-static build
で本番用ビルドを開始してください。本番用のファイルはdist
ファイル、またはあなたがカスタム設定したフォルダに出力されます。このフォルダの中身をホストにアップロードしてください。
継続的インテグレーション
サイトが頻繁に更新される場合、何らかのサービスを使って継続的インテグレーションを設定すると良いかもしれません。よくあるのは、NetlifyとそれにリンクしたGithubリポジトリの組み合わせです。これにより、コードが変更された時に自動でサイトを再ビルドすることができます。素晴らしい!
カスタマイズ可能なホスティングサービスを探している場合、Travis CIを使ってカスタマイズされた場所にデプロイするのも良いでしょう。可能性は無限大!
ホスティング
過去、静的サイトのデプロイがこんなに簡単だった時代はありません。静的サイトを安く、または無料でホストできるサービスがたくさんあります。実際これは静的サイトの最大のメリットの1つでもあります。つまり、サーバーのメンテナンスが不要で、スケーラビリティをあまり心配しなくて良いのです。以下はおすすめのサービスです。
CMSを使う
CMSはサイトの整理や更新にとても便利です。React Staticチームのお気に入はGraphCMS、Contentful、
Netlify CMSですが、 https://headlesscms.org/ (React Staticで作られています)で自分に合うものを選んでも良いでしょう。
Webhookで再ビルドする
CMSをつかう場合、CMSが変わったときサイトをビルドし直したいな、と考えると思います。
Webhookを使いましょう!ほとんどのモダンなCMSはWebhookを提供します。これらは、単純にCMSに変更があったときにpingされるURLです。CIツールやホスティングサービスに自動リビルドさせるのに使うのが効果的です。
例:
404エラーのハンドリング
React Staticで404ページを作るのは簡単です。サーバーによっていくつかの異なる方法で設定できます。
-
404.js
Reactコンポーネントをpagesに置く - 以下のルートを設定する
{
path: '404',
component: 'path/to/your/404/component.js'
}
404コンポーネントはどう使われるか
- 404 コンポーネントはビルド時にルートの
404.html
ファイルとして出力されます。多くのサーバーはルートが存在しない時に自動的にこのファイルを利用します。 - もし
<Routes />
コンポーネントがレンダリングされて、マッチするルートやテンプレートがない場合、404コンポーネントが表示されます。
動的ルーティング
訳者がよくわからないのでスキップ
https://github.com/nozzle/react-static/blob/master/docs/guides/dynamic-routes-reach-router.md
Webpackのカスタム設定とプラグイン
React StaticはReact用に調整された素晴らしいデフォルトのWebpack configを持っています。これだけでほとんどの場合は十分なはずです。しかし、設定を変えたくなったらnode.api.js
ファイルを設置してwebpack APIで拡張することができます。
ページネーション
ページネーションガイドをお読みください!
ブラウザサポート
React StaticはReact自体のサポートブラウザとあなたが選ぶBabelのpolyfillに依存してサポートの範囲を決めます。
- モダンブラウザ(Chrome, Firefox, Safari)の最新版はデフォルトでサポートされています。
- IEはサポートできますが、
babel-polyfill
をが必要です。
static.config.js
を拡張してIEに対応させるには、まずはbabel-polyfill
をインストールしてください。
その後、以下のオブジェクトをstatic.config.js
のエクスポートに追加して、既存のwebpack設定を拡張してください。
webpack: (config, { stage }) => {
if (stage === 'prod') {
config.entry = ['babel-polyfill', config.entry]
} else if (stage === 'dev') {
config.entry = ['babel-polyfill', ...config.entry]
}
return config
},