CakePHPとVue-cli2でSPA①CakePHPにVue.jsを導入

CakePHPとVue-cli2でSPA①CakePHPにVue.jsを導入

430 回閲覧されました

みなさんこんにちは、jonioです。

CakePHPにVue-cli2を導入してSPAを実装する方法を3回に分けて解説します。

知ることができる内容

下記になります。

  • 1回目の解説 : CakePHPにVue-cliを導入
  • 2回目の解説 : コントローラーからvueに変数を渡して表示
  • 3回目の解説 : SPAを実装

前提

CakePHPのバージョン4.5.3に導入しますが多分3系でも使えると思います。

CakePHPはインストール済みとします。

使用パソコン

Macです。

CakePHPにVue-cliの導入

resourcesディレクトリに移動します。

cd resources

そして下記のコマンドを叩きます。

vue create プロジェクト名

プロジェクト名は今回は「vue_demo」とします。

Vue.jsのバージョン選択が表示されますが「2」にします。

Vue CLI v5.0.8
? Please pick a preset: (Use arrow keys)
Default ([Vue 3] babel, eslint) 
  Default ([Vue 2] babel, eslint)             //←を選択
  Manually select features 

成功すると下記の表示になります。

🎉  Successfully created project vue_demo.
👉  Get started with the following commands:

 $ cd vue_demo
 $ npm run serve

「npm run serve」を叩くとアクセスするURLが表示されます。

App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://172.16.80.181:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

URLにアクセスすると下記の画面になります。

Laravel Mixのインストール

「npm run serve」を叩いてアクセスするURLを表示してそこに入ってもVue.jsを単体で起動させているだけなので意味がありません。

CakePHPの中でVue.jsを使わないといけないです、今からそれをやります。

CakePHPの中にあるVue.jsのプロジェクトのvue_demoに移動します。

cd vue_demo

「vue_demo > src」の下の階層にmain.jsがあるのですがこれを「CakePHPのプロジェクト > webroot > js」の下の階層に配置してVue.jsを動作させます。

main.jsの配置にLaravel Mixを使います。

vue_demoにいる状態で下記のコマンドを叩きます。

npm i --save-dev laravel-mix

「vue_demo > src > package.json」に下記の記述があればLaravel Mixが入っています、バージョンはインストールした時期によって異なります。

{
  "name": "vue_demo",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "laravel-mix": "^6.0.49",                     //←が入っていればいい
    "vue-template-compiler": "^2.7.16",
    "webpack": "^5.74.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

vue_demoにいる状態で下記のコマンドを叩いて「webpack.mix.js」を作成します。

touch webpack.mix.js

そしてwebpack.mix.jsに下記の記述をします。

const mix = require('laravel-mix');
mix
  .setPublicPath('../../webroot')
  .js('src/main.js', './js')
  .vue();

4行目でCakePHPの中にmain.jsを配置できるようにします。

そしてVue.jsをJavaScriptに変換してmain.jsに書き込みができるツールを下記のコマンドを叩いてインストールします。

npm install vue-loader@latest --save-dev

package.jsonを確認して下記になってればいいです。

{
  "name": "vue_demo",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "laravel-mix": "^6.0.49",              
    "vue-loader": "^17.4.2",                          //←が入っていればいい
    "vue-template-compiler": "^2.7.16",
    "webpack": "^5.74.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

そしてpackage.jsonに追記します。

{
  "name": "vue_demo",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    
    
    //ここから追加
    "dev": "npm run development",
    "development": "mix",
    "watch": "mix watch",
    "watch-poll": "mix watch -- --watch-options-poll=1000",
    "hot": "mix watch --hot",
    "prod": "npm run production",
    "production": "mix --production"
    //ここまで追加
    
    
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "laravel-mix": "^6.0.49", 
    "vue-loader": "^17.4.2",
    "vue-template-compiler": "^2.7.16",
    "webpack": "^5.74.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

そして下記のコマンドを叩いてmain.jsを配置します。

npm run dev

すると下記のエラーが表示されるはずです。

ERROR in ./src/App.vue
Module build failed (from ./node_modules/vue-loader/dist/index.js):
TypeError: Cannot read property 'styles' of undefined
    at Object.loader (/Applications/MAMP/htdocs/cakephp/sample/resources/vue_demo/node_modules/vue-loader/dist/index.js:96:34)

webpack compiled with 1 error

調べた結果package.jsonの「vue-loader」のバージョンがvue2に対応していないのが原因だとわかりました。(vue-loaderのバージョンは上がり続けるので今後も同じエラーが表示されると思います)

{
  "name": "vue_demo",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "dev": "npm run development",
    "development": "mix",
    "watch": "mix watch",
    "watch-poll": "mix watch -- --watch-options-poll=1000",
    "hot": "mix watch --hot",
    "prod": "npm run production",
    "production": "mix --production"
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "laravel-mix": "^6.0.49",
    "vue-loader": "^17.4.2",                     //←これ
    "vue-template-compiler": "^2.7.16",
    "webpack": "^5.74.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

vue-loaderのバージョンは17.4.2ですが16系以降はvue2に対応しないのでバージョンを下げないといけません。

package.jsonのvue-loaderのバージョンを15.4.2にしてください。

そして下記のコマンドを叩いてpackage-lock.jsonに適用してvue-loaderのバージョンを変更します。

npm install

これでpackage-lock.jsonを確認するとvue-loaderのバージョンが15.4.2になっているのを確認できます。

そしてもう一度下記のコマンドを叩きます。

npm run dev

コマンドが成功したらmain.jsが作成されているのが確認できます。

main.jsをCakePHPに配置しましたがまだVue.jsを使える環境にしていません。

それを「asset-mix」で実現します。

asset-mixの導入

CakePHPのプロジェクトまで移動して下記のコマンドを叩きます。

composer require ishanvyas22/asset-mix

成功したらCakePHPのプロジェクトの直下にある「composer.json」の「require」の項目を見るとasset-mixが導入されているのが確認できます。

"require": {
  "php": ">=7.2",
  "cakephp/authentication": "^2.10",
  "cakephp/cakephp": "~4.1",
  "cakephp/migrations": "^3.0",
  "cakephp/plugin-installer": "^1.2",
  "ishanvyas22/asset-mix": "^1.5",            //←これ
  "mobiledetect/mobiledetectlib": "^2.8"
}

そしてasset-mixを有効にする為に下記のコマンドを叩きます。

bin/cake plugin load AssetMix

CakePHPのビューでVue.jsを表示

いよいよVue.jsの表示です。

「CakePHPのプロジェクト > src > View > AppView.php」に追記します。

<?php
declare(strict_types=1);

/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link      https://cakephp.org CakePHP(tm) Project
 * @since     3.0.0
 * @license   https://opensource.org/licenses/mit-license.php MIT License
 */
namespace App\View;

use Cake\View\View;

/**
 * Application View
 *
 * Your application's default view class
 *
 * @link https://book.cakephp.org/4/en/views.html#the-app-view
 */
class AppView extends View
{
    /**
     * Initialization hook method.
     *
     * Use this method to add common initialization code like loading helpers.
     *
     * e.g. `$this->loadHelper('Html');`
     *
     * @return void
     */
    public function initialize(): void
    {
        $this->loadHelper('AssetMix.AssetMix');      //この行を追加
    }
}

そして「CakePHPのプロジェクト > templates > Pages > home.php」の中の全てのファイルを削除して「CakePHPのプロジェクト > templates > layout > default.php」に下記の記述をします。

<?php
/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @since         0.10.0
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 * @var \App\View\AppView $this
 */

$cakeDescription = 'CakePHP: the rapid development php framework';
?>
<!DOCTYPE html>
<html>
<head>
  <title>CakePHPにVue.jsを導入</title>
  <?= $this->AssetMix->script('main') ?>
</head>
<body>
    <div id="app"></div>
</body>
</html>

これでトップページにアクセスするとVue.jsを導入しているのが分かります。

25行目で「CakePHPのプロジェクト > webroot > js > main.js」を読み込んでこのページを表示しています。

これでCakePHPとVue-cliの連携ができました。

次回の解説

CakePHPのコントローラーからVue側に変数を渡して記述してブラウザで表示します。