JavaScript UI
ビューのレンダリングをTwigなどのPHPのテンプレートエンジンが行う代わりに、サーバーサイドのJavaScriptが実行します。PHP側は認証・認可・初期状態・APIの提供を行い、JavaScriptがUIをレンダリングします。既存のプロジェクトの構造で、アノテーションが付与されたリソースのみに適用されるため、導入が容易です。
前提条件
注:V8Jsがインストールされていない場合、Node.jsでJavaScriptが実行されます。
用語
- CSR: クライアントサイドレンダリング(Webブラウザで描画)
- SSR: サーバーサイドレンダリング(サーバーサイドのV8またはNode.jsが描画)
JavaScript
インストール
プロジェクトにkoriym/ssr-module
をインストールします:
# 新規プロジェクトの場合
# composer create-project bear/skeleton MyVendor.MyProject; cd MyVendor.MyProject
composer require bear/ssr-module
UIスケルトンアプリケーションkoriym/js-ui-skeleton
をインストールします:
composer require koriym/js-ui-skeleton 1.x-dev
cp -r vendor/koriym/js-ui-skeleton/ui .
cp -r vendor/koriym/js-ui-skeleton/package.json .
yarn install
UIアプリケーションの実行
まずはデモアプリケーションを動かしてみましょう。表示されたWebページからレンダリング方法を選択して、JavaScriptアプリケーションを実行します:
yarn run ui
このアプリケーションの入力はui/dev/config/
の設定ファイルで行います:
<?php
$app = 'index'; // index.bundle.jsを指定
$state = [ // アプリケーションステート
'hello' => ['name' => 'World']
];
$metas = [ // SSRでのみ必要な値
'title' => 'page-title'
];
return [$app, $state, $metas];
設定ファイルをコピーして、入力値を変更してみましょう:
cp ui/dev/config/index.php ui/dev/config/myapp.php
ブラウザをリロードして新しい設定を試します。このように、JavaScriptや本体のPHPアプリケーションを変更せずに、UIのデータを変更して動作を確認することができます。
このセクションで編集したPHPの設定ファイルは、yarn run ui
で実行する時のみに使用されます。PHP側が必要とするのは、バンドルされて出力されたJavaScriptファイルのみです。
UIアプリケーションの作成
PHPから渡された引数を使ってレンダリングした文字列を返すrender関数を作成します:
const render = (state, metas) => (
__AWESOME_UI__ // SSR対応のライブラリやJSのテンプレートエンジンを使って文字列を返す
);
state
はドキュメントルートに必要な値、metas
はそれ以外の値(例えば<head>
で使う値など)です。render
という関数名は固定です。
ここでは名前を受け取って挨拶を返す関数を作成します:
const render = state => (
`Hello ${state.name}`
);
ui/src/page/index/hello/server.js
として保存して、webpackのエントリーポイントをui/entry.js
に登録します:
module.exports = {
hello: 'src/page/hello/server'
};
これでhello.bundle.js
というバンドルされたファイルが出力されるようになりました。
このhelloアプリケーションをテスト実行するためのファイルをui/dev/config/myapp.php
に作成します:
<?php
$app = 'hello';
$state = [
['name' => 'World']
];
$metas = [];
return [$app, $state, $metas];
以上です!ブラウザをリロードして試してください。
render関数内では、ReactやVue.jsなどのUIフレームワークを使ってリッチなUIを作成できます。
通常のアプリケーションでは、依存を最小限にするためにserver.js
エントリーファイルは以下のようにrenderモジュールを読み込むようにします:
import render from './render';
global.render = render;
ここまでPHP側の作業はありません。SSRのアプリケーション開発は、PHP開発と独立して行うことができます。
PHP
モジュールインストール
AppModuleにSsrModule
モジュールをインストールします:
<?php
use BEAR\SsrModule\SsrModule;
class AppModule extends AbstractAppModule
{
protected function configure()
{
// ...
$build = dirname(__DIR__, 2) . '/var/www/build';
$this->install(new SsrModule($build));
}
}
$build
フォルダはJavaScriptファイルがあるディレクトリです(ui/ui.config.js
で指定するwebpackの出力先)。
@Ssrアノテーション
リソースをSSRするメソッドに@Ssr
とアノテートします。app
にJavaScriptアプリケーション名を指定する必要があります:
<?php
namespace MyVendor\MyRedux\Resource\Page;
use BEAR\Resource\ResourceObject;
use BEAR\SsrModule\Annotation\Ssr;
class Index extends ResourceObject
{
/**
* @Ssr(app="index_ssr")
*/
public function onGet($name = 'BEAR.Sunday')
{
$this->body = [
'hello' => ['name' => $name]
];
return $this;
}
}
$this->body
がrender
関数の第1引数として渡されます。
CSRとSSRの値を区別して渡したい場合は、state
とmetas
でbodyのキーを指定します:
/**
* @Ssr(
* app="index_ssr",
* state={"name", "age"},
* metas={"title"}
* )
*/
public function onGet()
{
$this->body = [
'name' => 'World',
'age' => 4.6E8,
'title' => 'Age of the World'
];
return $this;
}
実際にstate
とmetas
をどのように渡してSSRを実現するかは、ui/src/page/index/server
のサンプルアプリケーションをご覧ください。
影響を受けるのはアノテートしたメソッドだけで、APIやHTMLのレンダリングの設定はそのままです。
PHPアプリケーションの実行設定
ui/ui.config.js
を編集して、public
にWeb公開ディレクトリを、build
にwebpackのビルド先を指定します。build
はSsrModule
のインストール時に指定したディレクトリと同じにします:
const path = require('path');
module.exports = {
public: path.join(__dirname, '../var/www'),
build: path.join(__dirname, '../var/www/build')
};
PHPアプリケーションの実行
yarn run dev
ライブアップデートで実行します。PHPファイルの変更があれば自動でリロードされ、Reactのコンポーネントに変更があれば、リロードなしでコンポーネントがアップデートされます。
ライブアップデートなしで実行する場合はyarn run start
を実行します。
lint
やtest
などの他のコマンドについては、コマンドをご覧ください。
パフォーマンス
V8のスナップショットをAPCuに保存する機能を使って、パフォーマンスの大幅な向上が可能です。ProdModule
でApcSsrModule
をインストールしてください。ReactやアプリケーションのスナップショットがAPCu
に保存され再利用されます。V8Jsが必要です:
$this->install(new ApcSsrModule);
APCu以外のキャッシュを利用するには、ApcSsrModule
のコードを参考にモジュールを作成してください。PSR-16対応のキャッシュが利用可能です。
さらなる高速化のためには、V8をコンパイルする時点でJavaScriptコード(Reactなど)のスナップショットを取り込みます。詳しくは以下をご覧ください:
- 20x performance boost with V8Js snapshots
- v8js - Possibility to Improve Performance with Precompiled Templates/Classes?
デバッグ
- ChromeプラグインReact Developer Tools、Redux DevToolsが利用できます。
- 500エラーが返ってくる場合は、
var/log
やcurl
でアクセスしてレスポンスの詳細を確認してみましょう。
リファレンス
- ECMAScript 6
- Airbnb JavaScript スタイルガイド
- React
- Redux
- Redux GitHub
- Redux DevTools
- Karma テストランナー
- Mocha テストフレームワーク
- Chai アサーションライブラリ
- Yarn パッケージマネージャー
- Webpack モジュールバンドラー
その他ビューライブラリ
以前のReact JSページはReactJsをご覧ください。