前回の記事はこちら
本記事は、『フロントエンド環境編』の続きです。
バックエンド側の環境構築
タイトルにある通り、バックエンドはPHP言語を利用します。
また、著者はWindows10で環境構築をしています。
ソースのルートディレクトリについて
前回に引き続き、C:\hello-vuejs
を前提に話を進めます。
インストールライブラリのまとめ
バックエンド側で必要なものは以下の通りです。
ソフトウェア | バージョン | 説明 |
---|---|---|
Apache | 2.4.* | Webサーバー |
PHP | 7.4.* | バックエンド言語 |
Slim Framework | 3.1.* | PHPフレームワーク |
Slim PHP-View | ^2.2 | PHPフレームワーク |
Monolog | ^2.0 | PHPロガー |
Xamppのインストール
ApacheとPHPを使いたいので、XAMPPをインストールしました。本記事は、XAMPPベースで説明を進めます。
また、XAMPPの7.4系(しっかり確認していませんが、PHPの7.x系なら全般的に動作可能な気がします)をチョイスしました。
HINT
XAMPPのインストールを進めると、コンポーネント選択画面が表示されます。
本記事で必要なものは、以下の通りです(最小限の指定)。
XAMPPインストールウィザード - Select Components
注意
著者の環境(OSはWindows10)では、インストール完了後に、XAMPPコントロールパネルを起動する際、"Error:Cannot create file "[XAMPPインストールパス]\xampp-control.ini". Access denied.
と表示されました。
エラーを解消するには、XAMPPインストールパスのxampp-control.exe
を管理者権限で起動(右クリックして管理者権限で起動)します。以後は通常の操作で起動できるようになりました。
Apacheの設定
ポート番号の変更
Apacheを起動すると、httpは80番、httpsは443番として、デフォルトのポート番号が割り当てられています。
デフォルトのままだと、他のアプリとポート番号が衝突する可能性があるので変更することにします。
本記事では、httpを5555番、httpsを5556番に変更しました。
# Listenの設定
Listen 80
↓
Listen 5555
# ServerNameの設定
ServerName localhost:80
↓
ServerName localhost:5555
# Listenの設定
Listen 443
↓
Listen 5556
# VirtualHostの設定
<VirtualHost _default_:443>
↓
<VirtualHost _default_:5556>
# ServerNameの設定
ServerName www.example.com:443
↓
ServerName www.example.com:5556
公開ディレクトリの設定
hello-vuejs
のpublic
ディレクトリをApacheの公開ディレクトリとして指定します。
公開ディレクトリの指定には幾つかありますが、ここでは、alias_module
を利用します。
...
<IfModule alias_module>
...
Alias /hello-vuejs "C:\hello-vuejs\public"
<Directory "C:\hello-vuejs\public">
AllowOverride All
Require all granted
</Directory>
</IfModule>
...
HINT
alias_moduleを使用すると、URLが ”http://[ドメイン]/hello-vuejs” のように1段階層が深くなります。
virtual_hostを使用するというのも良い選択肢かと思います。
PHPの設定
PHPの挙動を設定するファイルは、[XAMPPインストールパス]\php\php.ini
です。
今回は、デフォルト設定のままで問題ないので特に編集しません。
Apacheの起動
XAMPPのコントローラパネルからApacheを起動しましょう。下図のような画面になればOKです。
Composerで必要なパッケージを導入する
PHPの各種ライブラリを入手するために、Composerをインストールするところから始めます。
以下のページから最新版をダウンロードしてインストールしましょう。
HINT
ComposerはPHPのパッケージ管理システムです。こちらを使って、PHPの各種ライブラリを導入します。
Composerの初期化
コマンドプロンプトを開いて、C:\hello-vuejs
にcd
しましょう。
そして、最初に以下を実行してください。
色々聞かれますが、大体の質問にEnterを押して、最後にyesを入力して行けばとりあえずOKです。
詳細が知りたい人は、ググってみてください。
composer init
...
# パッケージ名は、<vendor>/<name>形式の必要があるので、"ison/hello-vuejs"と入力
Package name (<vendor>/<name>) [***/***]: ison/hello-vuejs
... その他の質問は適当にEnterとyesを入力する
Composerのパッケージインストール
次に、以下を実行して行きます。
composer require slim/slim:3.*
composer require slim/php-view
composer require monolog/monolog
HINT
composer require
は、npmで言うところのnpm install
と同じものです。
著者の環境では、コマンドを打ち込んでからしばらく反応が無く3分以上待たされてしまいました。気長に待ちましょう。
Autoloadの設定
次に、composer.jsonの"autoload"
部分を追記します。
{
...
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"config": {
"optimize-autoloader": true
}
}
ファイルの編集が終わったら、以下を実行します。
composer dumpautoload
autoloadは、PHPでモジュールファイルをロードする仕組みの事です。
簡単に説明すると、上の設定はsrcディレクトリに配置されるPHPのクラスファイルは、Appという名前空間で始まるという事を意味します。
また、最適化のために、"optimize-autoloader": true
というオプションも有効にしました。
詳細は、以下のページを確認してください。
オートローダーの最適化
HINT
クラスの追加や変更があった場合に、オートローダーの最適化を再適用するコマンドは以下の通りです。
composer dumpautoload ... 最適化あり
composer dumpautoload --no-dev ... 最適化ありで開発環境以外にリリース
バージョン管理システムからチェックアウトした直後などは、単にcomposer install [--no-dev]
するだけでOKです。
composer.jsonに"optimize-autoloader": true
を記述しない場合は、composer dumpautoload -o [--no-dev]
、composer install --optimize-autoloader [--no-dev]
とすればOKです。
全て実行し終えると、以下のようなファイルが出来上がっているはずです。
c:\hello-vuejs
+ vendor
+ composer.json
+ composer.lock
vendorには、インストールしたライブラリファイルが格納されています。こちらは、バージョン管理が不要なディレクトリです。
composer.jsonには、composer initした際の各種設定と、何をインストールしたかの情報が記載されています。
composer.lockには、インストール時の厳密なライブラリのバージョン番号のスナップショットが記載されています。
こちらの2ファイルはコミットが必要です。
他の開発者は、こちらのcomposer.jsonまたはcomposer.lockから、composer installを実行して必要なライブラリをインストールすることになります。
したがって、本節で実施した、composer initとcomposer require [ライブラリ名]は、一度限りの実行になります。
他の開発者は、バージョン管理ツールからチェックアウトしたソースに対して、composer installを実行するだけで必要なライブラリを揃えることができます。
index.php、.htaccess、bootstrap.phpの作成
Webリクエストを受信した際にPHPを動作させるために必要な起動用のファイルを作成します。
c:\hello-vuejs
...
+ public
+ index.php
+ .htaccess
+ src
+ bootstrap.php
Webリクエストを受信すると、以下の順序で処理が行われます。
- .htaccessの実行(リクエストされたファイルが存在しない場合に、mod_rewriteの書き換えルールが働きindex.phpが実行される)
- index.phpの実行(index.phpの先頭の処理でbootstrap.phpが読み込まれる。index.phpはURLの内容からコントローラークラスと実行すべきメソッドを特定して実行する)
.htaccessの内容は以下の通りです。
mod_rewriteというURL書き換えモジュールの適用と、PHP設定の初期化です。
<IfModule mod_rewrite.c>
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# If the above doesn't work you might need to set the `RewriteBase` directive manually, it should be the
# absolute physical path to the directory that contains this htaccess file.
RewriteBase /hello-vuejs
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</IfModule>
php_value "display_errors" "On"
php_value "error_reporting" "E_ALL"
php_value "max_execution_time" "0"
php_value "memory_limit" "1024M"
php_value "post_max_size" "1024M"
php_value "upload_max_filesize" "5G"
php_value "max_input_vars" "10000"
php_value "date.timezone" "Asia/Tokyo"
index.phpの内容は以下の通りです。
前述で作成したbootstrap.phpのロードと、HTTPリクエストのルーティング設定を行います。
例えば、http://[ドメイン]/hello-vuejs/hello
を実行するとsrc\Func\Hello\Controller\HelloController.php
のactionIndex
が実行されます。
<?php
use Slim\Exception\NotFoundException;
use Slim\Http\Request;
use Slim\Http\Response;
$app = require __DIR__ . '/../src/bootstrap.php';
$app->any('/[{func1}[/{func2}[/{func3}]]]', function (Request $request, Response $response, array $args) use($app) {
$func1 = $args['func1'] ?? null;
$func1 = ucfirst($func1);
$func2 = $args['func2'] ?? null;
$func2 = ucfirst($func2);
$func3 = $args['func3'] ?? null;
$func3 = ucfirst($func3);
$class = '';
$method = '';
$pattern = null;
if ($func1 && $func2 && $func3) {
// 例)/login/auth/exec → Login\Controller\AuthController#actionExec
$pattern = 1;
$class = '\\App\\Func\\' . $func1 . '\\Controller\\' . $func2 . 'Controller';
$method = 'action' . $func3;
} else if ($func1 && $func2) {
// 例)/login/exec → Login\Controller\ExecController#actionIndex
$pattern = 2;
$class = '\\App\\Func\\' . $func1 . '\\Controller\\' . $func2 . 'Controller';
$method = 'actionIndex';
if (!class_exists($class)) {
// 例)/login/exec → Login\Controller\LoginController#actionExec
$class = '\\App\\Func\\' . $func1 . '\\Controller\\' . $func1 . 'Controller';
$method = 'action' . $func2;
}
} else if ($func1) {
// 例)/login → Login\Controller\LoginController#actionIndex
$pattern = 3;
$class = '\\App\\Func\\' . $func1 . '\\Controller\\' . $func1 . 'Controller';
$method = 'actionIndex';
}
if (!class_exists($class)) {
throw new NotFoundException($request, $response);
}
$controller = new $class($app);
if (!method_exists($controller, $method)) {
throw new NotFoundException($request, $response);
}
try {
return $controller->$method();
} catch (Throwable $exc) {
$GLOBALS['unexpectedException'] = $exc;
throw $exc;
}
});
// Run app
$app->run();
bootstrap.phpの内容は以下の通りです。
PHPのフレームワークであるSlim関連のインスタンスを生成しています。
<?php
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Monolog\Processor\UidProcessor;
use Slim\App;
use Slim\Views\PhpRenderer;
const PUBLIC_PATH = __DIR__ . '/../public/';
const SRC_PATH = __DIR__ . '/';
$app = null;
/*
* Load the autoloader
*/
$autoloader = require __DIR__ . '/../vendor/autoload.php';
// Create Slim App instance
$app = new App([
'settings' => [
'displayErrorDetails' => true,
],
]);
/*
* Set up dependencies
*/
$container = $app->getContainer();
// View Renderer
$container['renderer'] = function ($c) {
$templatePath = SRC_PATH;
return new PhpRenderer($templatePath);
};
// monolog
$container['logger'] = function ($c) {
$settings = $c->get('settings')['logger'];
$logger = new Logger('app');
$logger->pushProcessor(new UidProcessor());
$handler = new RotatingFileHandler(__DIR__ . '/../log/app.log', 0, \Monolog\Logger::DEBUG, true, 0664);
$handler->setFilenameFormat('{date}-{filename}', 'Y/m/d');
$logger->pushHandler($handler);
return $logger;
};
return $app;
Controllerクラスの作成とHelloコンポーネントの修正
前述で作成したindex.phpから実行されるコントローラクラスを作成します。
Helloコンポーネントも合わせて修正します。
c:\hello-vuejs
...
+ src\Func
+ Base\Controller
+ BaseController.php ... Hello・Goodbyeなどの各コントローラの基底クラス
+ Goodbye\Controller
+ GoodbyeController.php ... Goodbyeのコントローラ
+ Hello
+ Controller
+ HelloController.php ... Helloのコントローラ
+ Front\View ... Helloコンポーネント(htmlとjsのみ修正)
+ Hello.html
+ Hello.js
BaseController.phpの内容は以下の通りです。
特に重要なのは、renderメソッドです。
このメソッドで、src\View\Layout\Base.php
内のHTMLテンプレートをレスポンスに出力しています。
<?php
namespace App\Func\Base\Controller;
use App\Common\DB\DBObserver;
use App\Common\Exception\ServiceException;
use App\Common\Log\AppLogger;
use App\Common\Message\MessageManager;
use App\Common\ResponseCache\ResponseCache;
use App\Common\Session\SessionData;
use App\Common\Util\DBUtil;
use App\Constant\CommonConstant;
use App\Func\Login\Service\LoginService;
use SebastianBergmann\RecursionContext\Exception;
use Slim\App;
use Slim\Container;
use Slim\Exception\NotFoundException;
use Slim\Http\Response;
use Slim\Http\Stream;
use const SRC_PATH;
/**
* 基本となるコントローラークラス。
* コントローラクラスは、本クラスを継承すること。
*/
class BaseController {
/**
* @var App Appオブジェクト
*/
protected $app;
/**
*
* @var Container Containerオブジェクト
*/
protected $container;
/**
* @var AppLogger ロガー
*/
protected $logger;
/**
* @var string レイアウト名
*/
protected $layoutName;
/**
* @var array リクエストパラメータ
*/
protected $requestParams;
/**
* コンストラクタ。
* @param App $app アプリケーションオブジェクト
*/
public function __construct(App $app) {
$this->app = $app;
$this->container = $app->getContainer();
$this->logger = $this->container['logger'];
$this->layoutName = 'Base';
$this->requestParams = null;
}
/**
* リクエストパラメータを取得する。
* @return array リクエストパラメータ
*/
protected function getRequestParams(): array {
if ($this->requestParams !== null) {
return $this->requestParams;
}
$request = $this->container->request;
$getParams = $request->getQueryParams() ?? [];
$postPutParams = $request->getParsedBody() ?? [];
$allParams = array_merge($getParams, $postPutParams);
$this->requestParams = $allParams;
return $allParams;
}
/**
* 描画メソッド。
* @param string $contentsViewPath コンテンツビューのパス … /srcディレクトリからのパスを指定する(例:/Func/Login/Front/View/Login)
* @param array $contentsData データ
* @param string $layoutName レイアウトページ名 … /src/View/Layout下のレイアウトページを指定する(例:Base.phpの場合は、"Base"と指定する)
* @param array $importWidget インポートするWidget
* @return type
*/
protected function render(string $contentsViewPath, array $contentsData, string $layoutName = null) {
if (!file_exists(SRC_PATH . $contentsViewPath . '.vue')) {
// ファイルが存在しないため、例外を発行する(基本的には発生しないエラー)
throw new \Exception("コンテンツビューファイル未存在エラー contentsViewPath={$contentsViewPath}");
}
$contentsViewName = basename($contentsViewPath);
// レイアウトページの設定
if ($layoutName === null) {
$layoutName = $this->layoutName;
}
$layoutPhp = '/View/Layout/' . $layoutName . '.php';
// コンテナから関連するオブジェクトを取得
$container = $this->container;
$request = $container->request;
$response = $container->response;
$renderer = $container->renderer;
$baseUrl = $request->getUri()->getBasePath();
// リクエストパラメーターを取得する
$requestParams = $this->getRequestParams();
// レイアウトページのデータオブジェクト
$layoutDataObj = [
'__baseUrl' => $baseUrl,
'__requestParams' => $requestParams,
'__contentsViewPath' => $contentsViewPath,
'__contentsViewName' => $contentsViewName,
'__contentsData' => $contentsData,
];
return $renderer->render($response
, $layoutPhp
, $layoutDataObj);
}
/**
* Json出力メソッド。
* @param mixed $data The data
* @param int $status The HTTP status code.
* @param int $encodingOptions Json encoding options
* @return type
*/
protected function renderJson($data, int $status = null, int $encodingOptions = 0) {
$response = $this->container->response;
return $response->withJson($data, $status, $encodingOptions);
}
}
HelloController.phpで重要なのは、actionIndex
メソッドです。
内部では、BaseController#render
メソッドを呼び出しています。引数にHelloコンポーネントのパスを渡すことで、最終的にVue.jsのHelloコンポーネントを表示するように指示しています。
また、Helloコンポーネント上のボタン押下時のajax通信に対応するために、actionTalk
メソッドを設けました。こちらは、BaseController#renderJson
メソッドでtalkMessage
データをレスポンスとして返却しています。
<?php
namespace App\Func\Hello\Controller;
use App\Func\Base\Controller\BaseController;
use Slim\App;
/**
* Helloコントローラー。
*/
class HelloController extends BaseController {
/**
* コンストラクタ。
* @param App $app アプリケーションオブジェクト
*/
public function __construct(App $app) {
parent::__construct($app);
}
/**
* 表示処理。
*/
public function actionIndex() {
return $this->render('/Func/Hello/Front/View/Hello', []);
}
/**
* 話す処理。
*/
public function actionTalk() {
$params = $this->getRequestParams();
$data = ['talkMessage'=>"Hi, I came from space."];
return $this->renderJson($data);
}
}
Helloコンポーネントのhtmlとjsファイルも修正します。
修正内容は、ボタンの追加・ボタン押下時の処理・返却メッセージの表示領域の追加です。
<div class="hello-component" v-cloak ref="view">
<div>
This is Hello Component.<br>
{{message}}
</div>
<div>
<button type="button" @click="talk">Hello?</button>
</div>
<div>
<p>{{talkMessage}}</p>
</div>
</div>
export default {
data() {
return {
message: 'Hello Vue.js',
talkMessage: ''
};
},
methods: {
talk() {
$.ajax({
url: AppContext.baseUrl + '/hello/talk'
}).then((data)=> {
this.talkMessage = data.talkMessage;
});
}
}
}
GoodbyeController.phpは、HelloController.phpとほとんど同じ内容です(ただしactionTalkメソッドは設けていません)。
<?php
namespace App\Func\Goodbye\Controller;
use App\Func\Base\Controller\BaseController;
use Slim\App;
/**
* Goodbyeコントローラー。
*/
class GoodbyeController extends BaseController {
/**
* コンストラクタ。
* @param App $app アプリケーションオブジェクト
*/
public function __construct(App $app) {
parent::__construct($app);
}
/**
* 表示処理。
*/
public function actionIndex() {
return $this->render('/Func/Goodbye/Front/View/Goodbye', []);
}
}
レイアウトHTML(Base.php)の作成
Base.phpは、前回の記事で作成したindex.htmlに代わるHTMLのテンプレートです。
ついでに、C:\hello-vuejs\public\index.html
を削除しましょう。
c:\hello-vuejs
...
+ public
+ index.html ... !!! 削除する
+ src\View\Layout
+ Base.php
前回の記事で、index.htmlではPOSTパラメータにアクセスすることができないと言いました。
ですが、Base.phpで動的にHTMLを生成して、リクエストパラメータ(GETやPOST)やサーバー側で任意に設定した情報を、JavaScriptコードとして生成することで、JavaScript側でPOSTパラメータやその他サーバーで設定した情報に(AppContextというグローバル変数経由で)アクセスできるようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="Mon, 26 Jul 1997 05:00:00 GMT">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale = 1.0, maximum-scale = 1.0, user-scalable = no">
<title>Hello Vue.js</title>
</head>
<body class="layout-base">
<div id="app" v-cloak>
</div>
<?php /* グローバル関連の定義 */ ?>
<script type="text/javascript">
// アプリケーションコンテキストの定義(アプリケーション全体で使用したいデータ等を定義、イミュータブルなオブジェクトにする)
var AppContext = Object.freeze({
name: 'Hello Vue.js',
baseUrl: '<?= $__baseUrl ?>',
requestParams: <?= json_encode($__requestParams) ?>,
contentsComponentPath: '<?= $__contentsViewPath ?>',
contentsComponentId: '<?= $__contentsViewName ?>Component',
contentsData: <?= json_encode($__contentsData) ?>
});
</script>
<?php /* バンドルファイルの読み込み */ ?>
<?php /* ※本ファイルの読み込み後に、main.jsで定義したグローバル変数などが読み込みできるようになる */ ?>
<script src="<?= $__baseUrl . '/dist/bundle.js?' . filemtime(PUBLIC_PATH . 'dist/bundle.js') ?>" ></script>
<?php /* Vue.js生成 */ ?>
<script type="text/javascript">
// Vue.js生成
window.AppFuncs.createVuejs(AppContext.contentsComponentPath, AppContext.contentsComponentId);
</script>
</body>
</html>
main.jsの修正
各種ファイルの新規作成に伴い、main.jsの修正が必要になります。
c:\hello-vuejs
...
+ src
+ main.js
その前に、jQueryをインストールしたいので、cd c:\hello-vuejs
して以下を実行しましょう。
jQueryは、ajaxメソッドを利用するために導入しました。axiosでもOKです。
npm install -D jquery
main.jsを以下の内容で置き換えます。
大きく変更された箇所は、jQueryのインポート、Vue.jsインスタンスの生成メソッドをAppFuncsに移動したこと。また、最後の行でwindowオブジェクトにjQueryとAppfuncsを設定しています。
windowオブジェクトはグローバルオブジェクトなので、このようにしないと、bundle.js(main.jsが含まれている最終成果物ファイル)の外から、これらのオブジェクトを参照することができないのです。
// -----------------------------------------------------------------------------
// ライブラリのインポート
// -----------------------------------------------------------------------------
// JQuery
import $ from 'jquery';
// VueJs
import Vue from 'vue';
/**
* アプリケーションの関数定義
*/
const AppFuncs = {
/**
* Vue.jsインスタンスを生成する。
* @param {String} componentPath コンポーネントパス
* @param {String} componentId コンポーネントID
* @returns {Vue} Vue.jsインスタンス
*/
createVuejs(componentPath, componentId) {
// 動的インポートを実施
//
// componentPathを以下のルールで変換
// 例)ログインの場合
// /Func/Login/Front/View/Login
// ↓
// ./Func/Login/Front/View/Login.vue
const componentLoadPromise = import("./" + componentPath.replace(/^\//, "") + ".vue");
componentLoadPromise.then(function (value) {
// 動的インポート完了
// VueのComponentのグローバル登録は、Vueインスタンス生成前に実施する必要あり
Vue.component(componentId, value.default /* import関数の戻り値に default があるので、そちらを使用する(defaultエクスポート定義を読み込むという意味になる) */);
// Vueインスタンスの生成
const vm = new Vue({
el: '#app',
render: h => h(componentId)
});
return vm;
});
}
};
// -----------------------------------------------------------------------------
// グローバル変数の定義
// -----------------------------------------------------------------------------
window.$ = $; // jQueryオブジェクト
window.AppFuncs = AppFuncs;
HINT
ES6で定義されたデータや関数にES6未満のJSコードからアクセスする場合、ES6側で対象データをwindowオブジェクト(グローバルな領域に)に設定することで、アクセスが可能になります。
webpack.dev.jsの修正
前回はNode.jsをWebサーバーとして利用していましたが、PHPを使用するために今回からApacheをWebサーバーとして使用することになります。ただ、Apacheを使用するとHMR(Hot Module Replacement)が機能しなくなります。そのためプロキシ設定を行います。
プロキシ設定は、webpack.dev.jsで行います。
c:\hello-vuejs
...
+ webpack.dev.js
修正内容は以下のdevServer
部分です。devServer
内の最終行にproxy
を丸ごと貼り付けてください。
ついでに、devServer
内のopenPage
を変更(index.htmlを削除したので)しましょう。
HMR(Hot Module Replacement)を利用するためには、dist/bundle.jsファイルは今まで通りNode.jsサーバーに処理させたいので、dist以下のファイルはNode.jsで、それ以外の全てのリクエストはApache Webサーバーにリクエストさせるといった事をproxy
部分に記述しています。
...
module.exports = merge(common, {
...
devServer: {
...
// ブラウザの表示ページ
openPage: prefixUri.substring(1) + '/hello',
...
// プロキシ設定
proxy: [
{
context: [
// すべてのリクエストを対象とする
'**',
// dist以下は対象外とする
'!' + prefixUri + '/dist/**'
],
// Apache Webサーバーに転送する
target: 'http://localhost:5555'
}
]
}
});
動かしてみる
処理イメージは下図の通りです。
C:\hello-vuejs
で以下のコマンドを実行してください。すると、ブラウザが起動してページが表示されるはずです。
npm run start
Helloコンポーネント上の『Hello?』ボタンを押してPHPと通信できるか試してみましょう。
すると、下図のように、『Hi, I came from space.』というメッセージが表示されましたね。
HMRが有効かどうかも試しましょう。Hello.jsを開いて、dataのmessageを編集してみると…。
...
data() {
return {
message: 'ニイハオ Vue.js',
talkMessage: ''
};
},
...
Goodbyeコンポーネントの画面も表示しましょう。
http://localhost:8080/hello-vuejs/goodbye
リリースビルドの実行
リリースビルドの実行については、フロントエンドで実行したnpm run build
と何ら変わりありません。
本番環境にリリースするファイルを作成するには、npm run build
してbundle.jsを作成しましょう。
それと、デバッグ時はNode.jsのWebサーバーを経由してApacheにアクセスしていましたが、リリース時はApacheに直接接続するので、URLは以下のように(Apacheに直接接続)します。
http://localhost:5555/hello-vuejs/hello
http://localhost:5555/hello-vuejs/goodbye
最終的なファイル構成
ファイルの最終的な構成は以下の通りです。
フロントエンドとバックエンドのソースが混合された構成になっています。
C:\hello-vuejs
+ node_modules ... npmでインストールしたライブラリ(バージョン管理対象外とするディレクトリ)
+ public ... Webサーバーの公開ディレクトリ
+ .htaccess ... Apache設定ファイル
+ index.php ... フロントコントローラ
+ src
+ Func ... 機能別ディレクトリ
+ Base
+ Controller
+ BaseController.php
+ Hello
+ Controller
+ HelloController.php ... Helloコントローラー
+ Front\View ... Helloコンポーネント
+ Hello.vue
+ Hello.html
+ Hello.css
+ Hello.js
+ Goodbye
+ Controller
+ GoodbyeController.php ... Goodbyeコントローラー
+ Front\View ... Goodbyeコンポーネント
+ Goodbye.vue
+ Goodbye.html
+ Goodbye.css
+ Goodbye.js
+ View
+ Layout
+ Base.php ... HTMLテンプレート
+ bootstrap.php ... PHP起動用共通処理
+ main.js ... webpackエントリポイントファイル
+ vendor ... Composerでインストールしたライブラリ(バージョン管理対象外とするディレクトリ)
+ composer.json ... Composerに関する設定ファイル
+ composer.lock ... composer requireのスナップショットファイル
+ package.json ... npmに関する設定ファイル
+ package-lock.json ... npm installのスナップショットファイル
+ webpack.common.js ... webpackの共通設定ファイル
+ webpack.dev.js ... webpackの開発用設定ファイル
+ webpack.prod.js ... webpackのリリース用設定ファイル
バックエンドのまとめ
以上で、本記事が目標としていたWebアプリケーションのひな型が完成しました。
SPA(シングルページアプリケーション)でもない、従来のページ遷移方式で、さらにはVue.jsのSFCを用いることもできました。
webpackのビルドも、設定さえ正しくできれば開発効率を妨げる要因はなく、むしろ開発効率が向上することが実感できました。
JavaScriptのES6も慣れてくると非常に書きやすいです。本記事を応用すればTypeScriptを導入することもできます。
ただ、webpackの流儀に従うのであれば、依存するライブラリが増えた場合には、main.jsにimportを追記する必要が有ります。
画像ファイルもbundle.jsにマージしたいこともあるでしょうし、Webフォントも一緒に取り扱うという事であればwebpackの設定と深く付き合っていく必要があります。これらは、公式リファレンスを見たり、色々な記事を見て勉強していくしかありませんね。
今回作成したソースはGitHubにアップしておきました。以下のページにアクセスして確認してみてください。
hello-vuejsソース(PHP統合版)