WordPress 4.7では、これまでプラグインとして提供されていたWP REST APIが機能として組み込まれ、標準でREST APIが使えるようになりました。このことにより予想されることは、PHP以外のプラットフォームで、WordPressのブログテーマやWordPressの機能を使ったサービスが今後どんどん生まれてくると言うことです。
ちょうど自分の扱っている新規事業の企画でブログメディアを作ることになりました。新しいメディアを運営する上で、技術的にも注目されるようなものを作りたいと思ったので、今回このWordPressのREST APIを使って、React + Reduxベースでブログを作ることにしました。爆速なブログができあがったので事例として紹介させてください。
人々の日常生活に役立つ情報(ライフハック術、ガジェット、アプリ、サービスなどの情報)を記事として提供するブログメディアです。ライター自身の体験に基づいたオリジナル色の強い記事を提供することをコンセプトにしています。興味がありましたら、ぜひ見てみてください。私もこちらで記事を書いています(ちなみに現在はテスト運用中です)。追記: 残念なことにサービス終了しました。
技術的なこと
アクセスしてもらうとわかると思いますが、WordPressのブログとしてはかなり爆速で表示されます。GTMetrixでのスピード調査結果も以下のようになっています。思った以上に良い結果なので驚いています。
このブログを作る際にやってみようと思ったことは、冒頭でも述べたようにReactとReduxベースで作ることです。サーバーサイドもReact + Reduxで実装するUniversal JavaScriptアプリの開発に挑戦してみようと思いました。
これまでサーバーサイドをJavaScriptで実装する機会がなかったので、最初はクライアントサイドのJavaScriptの実装との違いに若干手こずりましたが、サーバーサイドであっても結局はReactとReduxでの実装がメインであり、そういう意味ではいつも通りフロントエンドを開発するような感覚で開発ができたと思います。
技術的なことについて、簡単ですが以下にまとめておきます。
サーバーサイド
サーバーはさくらのVPS(4Gプラン)で、Node.js上にExpressでWebアプリを構築し、nginxでリクエストを受け取った際に、リバースプロキシでそのWebアプリを呼び出しています。セキュリティやパフォーマンスに関しては、以下のExpressのドキュメントなどを参考に、helmetやcompressionなどなど入れています。プロセス・マネージャーはPM2を使っています。
- 実稼働環境における Express のセキュリティーに関するベスト・プラクティス – Express
- 実稼働環境におけるベスト・プラクティス: パフォーマンスと信頼性 – Express
- Node.js Security Checklist | @RisingStack
WordPress環境
WordPressは、さくらのVPSのnginx上にKUSANAGIという超高速WordPress仮想マシンを乗せて、そこで動かしています。プラグインは、Autoptimize(記事の圧縮)、EXIF-Remove-ImageMagick(画像情報の削除)、Jetpack by WordPress.com(関連記事などの情報取得、画像のCDN化)、WP Smush(画像の圧縮)などを入れています。
ルーティング
ルーティングは、nginxでもexpressでもなく、React-Routerで行っています。expressで受け取ったURLの情報をReact-Routerのmatch
メソッドを使って、URLごとに呼び出すコンポーネントを取得するようにしています。さらにここでは、React-Router-Reduxを使って、Rouretの状態をReduxのstore
で管理するようにしています。
アプリケーション
ブログのアプリケーション自体は、ReactとReduxベースで作っています。React-Routerで受け取ったURLにマッチするcontainer
を呼び出すようにしています。container
内には、サーバーサイドから呼び出せるstaticなメソッドを設けて、WordPressのAPIを叩くようにしています。クライアントサイドでも同様にcontainer
内に設けたReactのcomponentDidMount
メソッドからこのstatic
メソッドを呼び出すようにしています。このような方法でサーバーサイドからもクライアントサイトからもWordPressの情報を取得できるようにしています。(ただ今となっては、サーバーもクライアントも共通のReactのcomponentWillMount
メソッドから呼び出したり、React-Router側でページ遷移のタイミングで呼び出してもよかったかなと思っています。)
最終的に出力するコンポーネントは、クライアント側はreact-domのrenderToString
メソッドを使ってサーバーサイドレンダリングさせています。この辺りの作法は以下を参考にしました。
- Server Rendering · Redux
- Quick Start Tutorial: Universal React, with Server Side Rendering
- react-router/ServerRendering.md at v2.0.0 · ReactTraining/react-router
- Server-Side Rendering with Redux and React-Router | Codementor
- redux と react-router での非同期API呼び出しを含む universal app の作り方 – Qiita
- アメブロ2016 ~ Isomorphic JavaScriptの詳しい話 | CyberAgent Developers Blog | サイバーエージェント デベロッパーズブログ
機能周り
ページング(Pager / Pagenation)は、独自実装です。記事の一覧を取得する際に、APIのレスポンスヘッダに、ページ総数、現在のページ数、記事の総数などが含まれているので、それらを元に必要最小限のものを実装しました。
スムーズスクロールは、react-scrollchorで実装しています。そもそもreact-routerを使っていると、ページ内のアンカーリンクも機能しなくなるので、何か対策が必要です。
非同期周り
非同期処理には、node-fetchを使っています。node-fetchはFetch APIをNode.js上で使えるようにしたものですが、エラーの扱いに癖があり、これを選択したことに若干後悔しています。非同期処理はReduxのミドルウェアであるredux-thunkを使って行い、最終的に得た結果をAction Creatorに渡し、dispatch
させています。Promise
主体で書いていますが、若干複雑になりかけている部分もあったりします。
CSS
CSSはnode-sassで普通に書いて、最終的にstyle.css
としてファイルを出力して読み込ませています。Reactとは完全に切り離しています。これはただ単に時間がなかったという理由からですが、これが意外とCSSの変更もしやすくて良かったりします。
IE対応
見落としがちでしたが、気付いた時にはすでに時遅し。意外とこれが厄介でした。fetch
、Promise
、Object.assign
、Array.prototype.find
…などES2015の機能を使っていたのですが、これらが軒並みIE11では動かないと怒られました。一つ一つPolyfillを入れていきましたが、エラーが次から次へと出てくる状態でした。試行錯誤した挙句、最終的に行き着いたのがbabel-polyfillでした。これを入れたら一発でした。IE11や古いiPhoneのSafariでも正常に動くようになりました。
テスト周り
テストは今のところ手動のみです。今後サービスが継続されることとなれば、Jestでも使ってユニットテストくらいは書いておきたいと考えています。その他、構文チェックにはESLint + eslint-config-airbnbを使っています。Propsのバリデーションは、ReactのPropTypesを使っています。
ビルド
ビルドはbrowserify + babelifyで行なっています。プロダクション環境用にビルドする際は、loose-envify(envifyより高速ということらしい)を使って環境変数の振り分けを行い、UglifyJS2を使ってビルドしたファイルの圧縮を行なっています。
まとめ
書き忘れている部分もあるかと思いますが、今回書いたような方法でReact + Redux + WP REST APIのブログを実現させています。まだまだパフォーマンスを向上させるために、レンダリングやAPIのリクエスト回数を減らすなどチューニングが必要だったります。特にStore周りの設計がうまくできていない(思考錯誤していたころのままとなっている)ので、そこは改善の余地が十分にあります。その辺りは、その他のパフォーマンス改善を含めて余裕ができたらやっていく予定です。
それよりもブログなので、以下のようなブログに必須の機能を早く実装したいと思っているところです。
- RSS
- 関連記事
- ソーシャルボタン
- AMP対応
RSSは、jpmonette/feedやdylang/node-rssを使えばいけるかなと思っています。関連記事は、WordPressのプラグインJetpack by WordPress.comで取得できているので、すぐに実装できそうです。ソーシャルボタンは、シェア数まで表示させてようとすると厄介かなと思っています。自分の作ったjQueryプラグインをReact用に改造しようと考えています。AMP対応は独自実装が可能かどうかまずは調査からですね。
今回は自分の好きなReactとReduxを使ってブログを作ってみましたが、通常のWordPressのテンプレートよりも高速なブログができたことに改めてReactのパフォーマンスの良さを実感しているところです。まだテスト運用中なので長続きするかわかりませんが、ぜひ事例として参考にしていただければ幸いです。
以下の『WEB+DB PRESS』では、ReactでのSPA(シングル・ページ・アプリケーション)の開発について特集記事が掲載されています。その中で、React Routerやサーバーサイドレンダリングの実装方法なども詳しく解説されています。Universal Webアプリを開発する際には参考になる貴重な情報源になるかと思います。最後に紹介しておきます。
コメント