目的
Nuxtを使用しないプロジェクトに参画するため、vue-routerやvuexの設定等を復習したい。
環境
- PHP7.3
- Laravel7.30
- vue 2.6.12
手順
- Dockerでローカルの環境構築
- TypeScript(とデコレータ)を導入する
- コード整形ツールを導入する
- browsersyncの設定をし、ブラウザのリロードの手間を省略する
- vuex, vue-routerの設定をする
- 別記事でログイン機能も実装する
Dockerでローカルの環境構築
プロジェクト用ディレクトリを用意
Terminal
$ mkdir -p ~/workspace/myapp
$ cd ~/workspace/myapp
$ mkdir -p laravel mnt/mysql /docker/{php,nginx}
$ mkdir docker/nginx/{conf.d,logs}
.envの準備
先に.env.exampleを編集してからコピーして.envをつくる
myapp
$ touch .env.example .gitignore
.env.exampleと.gitignoreを編集
.env.example
PROJECT_PATH=./laravel
TZ=Asia/Tokyo
WEB_PORT=10080
DB_PORT=13306
DB_TESTING_PORT=13307
DB_CONNECTION=mysql
DB_NAME=myapp
DB_USER=willrewrite
DB_PASS=willrewrite
DB_ROOT_PASS=willrewrite
MAILHOG_PORT=18025
MAIL_HOST=mail
MAIL_PORT=1025
COMPOSE_HTTP_TIMEOUT=70
.gitignore
.env
.idea
# その他個別に追加
.env.exampleをコピー
myapp
$ cp .env.example .env
コピー後、個別のプロジェクトに合わせて.envの環境変数を上書きする
必要なファイルを作成
myapp
$ touch docker-compose.yml \
docker/php/{php.ini,Dockerfile} \
docker/nginx/{conf.d/default.conf,Dockerfile} \
docker/mysql/mysql_conf/my.cnf \
mnt/mysql/.gitignore
各ファイルを編集
docker-compose.yml
version: "3"
services:
web:
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
args:
- TZ=${TZ}
volumes:
- ./docker/nginx/logs:/etc/nginx/logs
- ./docker/nginx/conf.d:/etc/nginx/conf.d
- ${PROJECT_PATH}:/var/www/laravel
ports:
- ${WEB_PORT}:80
links:
- app
depends_on:
- app
app:
build:
context: .
dockerfile: ./docker/php/Dockerfile
args:
- TZ=${TZ}
volumes:
- ${PROJECT_PATH}:/var/www/laravel
links:
- db_master
environment:
- DB_CONNECTION=${DB_CONNECTION}
- DB_HOST=db_master
- DB_DATABASE=${DB_NAME}
- DB_USERNAME=${DB_USER}
- DB_PASSWORD=${DB_PASS}
- TZ=${TZ}
- MAIL_HOST=${MAIL_HOST}
- MAIL_PORT=${MAIL_PORT}
db_master:
image: mysql:5.7
volumes:
- ./mnt/mysql:/var/lib/mysql
- ./docker/mysql/mysql_conf:/etc/mysql/conf.d
environment:
- MYSQL_DATABASE=${DB_NAME}
- MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASS}
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASS}
- TZ=${TZ}
ports:
- ${DB_PORT}:3306
Nginxの設定
docker/nginx/Dockerfile
FROM nginx:1.15.7-alpine
# timezone
ARG TZ
COPY ./docker/nginx/conf.d/ /etc/nginx/conf.d/
COPY ./docker/nginx/logs/ /etc/nginx/logs/
COPY ./laravel/ /var/www/laravel/
RUN apk update && apk --update add tzdata && \
cp /usr/share/zoneinfo/${TZ} /etc/localtime && \
apk del tzdata && \
rm -rf /var/cache/apk/*
docker/nginx/conf.d/default.conf
server {
listen 0.0.0.0:80;
# server_nameで設定した名前をローカルマシンの/etc/hostsにも設定する
server_name www.example.org example.org;
charset utf-8;
client_max_body_size 5M;
root /var/www/laravel/public;
index index.php;
location / {
access_log /etc/nginx/logs/access.log main;
error_log /etc/nginx/logs/error.log;
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
PHPの設定
docker/php/Dockerfile
FROM php:7.3.0RC6-fpm-alpine3.8
# timezone
ARG TZ
WORKDIR /var/www/laravel
COPY ./docker/php/php.ini /usr/local/etc/php/
COPY ./laravel/ /var/www/laravel/
RUN apk upgrade --update && apk add --no-cache \
coreutils freetype-dev jpeg-dev libjpeg-turbo-dev libpng-dev libmcrypt-dev \
git vim unzip tzdata \
libltdl && \
docker-php-ext-install pdo_mysql mysqli mbstring && \
docker-php-ext-install -j$(nproc) iconv && \
docker-php-ext-configure gd \
--with-freetype-dir=/usr/include/ \
--with-jpeg-dir=/usr/include/ && \
docker-php-ext-install -j$(nproc) gd && \
cp /usr/share/zoneinfo/${TZ} /etc/localtime && \
apk del tzdata && \
rm -rf /var/cache/apk/*
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
docker/php/php.ini
log_errors = on
error_log = /var/log/php/php-error.log
upload_max_filesize = 5M
memory_limit = -1
post_max_size = 100M
max_execution_time = 900
max_input_vars = 100000
default_charset = UTF-8
[Date]
date.timezone = ${TZ}
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
mysqlの設定
docker/mysql/mysql_conf/my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqldump]
default-character-set=utf8
[mysqld]
character-set-server=utf8
mysqlのマウントによるファイルはコード管理の対象外
mnt/mysql/.gitignore
/*
!/.gitignore
立ち上げ
myapp
$ docker-compose run app composer create-project --prefer-dist "laravel/laravel=7.*" .
$ docker-compose up -d
$ docker-compose exec app ash
/var/www/laravel
$ php artisan -V // バージョン確認
$ php artisan migrate
$ chmod -R a+rw storage/ bootstrap/cache
$ exit
$ cd laravel
$ npm install
デフォルトの認証機能を使う場合
webpack.mix.jsを上書きされる前に、このタイミングで公式ドキュメントどおりコマンドを打つ
~/workspace/myapp
$ docker-compose exec app ash
// バージョン指定しないとエラーが出る
/var/www/laravel # composer require laravel/ui:^2.4
/var/www/laravel # php artisan ui vue --auth
TypeScript(とデコレータ)を導入する
~/workspace/myapp/laravel
$ npm i -D vue vue-template-compiler \
ts-loader \
typescript \
vue-property-decorator \
vue-mixin-decorator
$ mv resources/js resources/ts resources/ts/app.ts
$ touch tsconfig.json resources/ts/vue.shims.d.ts resources/views/index.blade.php
tsconfig.json
{
"files": [
"resources/ts/vue.shims.d.ts"
],
"compilerOptions": {
"outDir": "./public/",
"sourceMap": true,
"strict": true,
"noImplicitReturns": true,
"noImplicitAny": true,
"module": "es2015",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node",
"target": "es5",
"lib": [
"es2016",
"dom"
]
},
"include": [
"resources/ts/**/*"
]
}
resources/ts/vue.shims.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
routes/web.php
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/{any?}', function () {
return view('index');
})->where('any', '.+');
resources/views/index.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{ config('app.name') }}</title>
<!-- Scripts -->
<script src="{{ mix('js/app.js') }}" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Merriweather%7CRoboto:400">
<link rel="stylesheet" href="https://unpkg.com/ionicons@4.2.2/dist/css/ionicons.min.css">
<!-- Styles -->
<link href="{{ mix('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app"></div>
</body>
</html>
resources/ts/app.ts
require('./bootstrap');
import Vue from 'vue'
new Vue({
el: '#app',
template: '<h1>Hello world</h1>'
})
コード整形ツールを導入する
.editorconfig
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
~/workspace/myapp/laravel
$ npm i -D eslint \
eslint-config-prettier \
eslint-plugin-prettier \
prettier \
babel-eslint \
eslint-plugin-vue \
vue-eslint-parser \
@nuxtjs/eslint-config-typescript
$ touch .eslintrc
.eslintrc
{
"env": {
"es6": true,
"node": true
},
"extends": [
"@nuxtjs/eslint-config-typescript",
"eslint:recommended",
"plugin:prettier/recommended",
"plugin:vue/recommended",
"prettier/vue"
],
"parser": "vue-eslint-parser",
"parserOptions": {},
"rules": {
"strict": 0,
"prettier/prettier": [
"error",
{
//ここはprettierの公式ドキュメントのoptionsを見てカスタマイズする
"singleQuote": true,
"trailingComma": "es5",
"semi": false,
"endOfLine": "lf"
}
]
}
}
browsersyncの設定
$ cd laravel
$ npm i -D browser-sync browser-sync-webpack-plugin
webpack.mix.js
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/
const mix = require('laravel-mix')
mix.browserSync('example.org:10080')
.ts('resources/ts/app.ts', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.version()
const path = require('path')
mix.webpackConfig({
resolve: {
extensions: ['.js', '.ts', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.resolve('/resources/ts'),
},
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: { appendTsSuffixTo: [/\.vue$/] },
exclude: /node_modules/
}
]
}
})
一旦画面確認
~/workspace/myapp/laravel
$ npm run watch
localhost:3000にアクセスし、Hello world
の初期画面が出ればOK
Userモデルの移動関連
var/www/laravel
/var/www/laravel # mkdir app/Models && \
mv app/User.php app/Models/
app/Models/User.php
<?php
// App\Modelsに修正
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
// 以下略
database/factories/UserFactory.php
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Models\User; // ここを修正
use Faker\Generator as Faker;
use Illuminate\Support\Str;
// 以下略
config/auth.php
<?php
return [
// 中略
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class, // ここを修正
],
],
// 以下略
カラムの最大長を設定
app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Schema;
// (中略)
public function boot()
{
Schema::defaultStringLength(191);
}
vuex, vue-routerの設定をする
~/workspace/myapp/laravel
$ npm i -D vue-router vuex
$ mkdir resources/ts/pages
$ touch resources/ts/pages/{Index,Login}.vue \
resources/ts/App.vue \
resources/ts/router.ts
resources/ts/pages/Index.vue
<template>
<div>Index page.</div>
</template>
resources/ts/pages/Login.vue
<template>
<div>Login page.</div>
</template>
resources/ts/App.vue
<template>
<div>
<main>
<div class="container">
<router-view />
</div>
</main>
</div>
</template>
resources/ts/router.ts
import Vue from 'vue'
import VueRouter from 'vue-router'
// ページコンポーネントをインポートする
import Index from './pages/Index.vue'
import Login from './pages/Login.vue'
// VueRouterプラグインを使用する
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: Index
},
{
path: '/login',
component: Login
}
]
// VueRouterインスタンスを作成する
const router = new VueRouter({
mode: 'history', //URL中の#(ハッシュ)を消す
routes
})
// VueRouterインスタンスをエクスポートする
export default router
resources/ts/app.ts
import Vue from 'vue'
// ルーティングの定義をインポートする
import router from './router'
// ルートコンポーネントをインポートする
import App from './App.vue'
new Vue({
el: '#app',
router, // ルーティングの定義を読み込む
components: { App }, // ルートコンポーネントの使用を宣言する
template: '<App />' // ルートコンポーネントを描画する
})
vuexの下準備
~/workspace/myapp/laravel
$ mkdir resources/ts/store
$ touch resources/ts/store/index.ts
resources/ts/store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
// ここに随時追加
},
})
export default store
resources/ts/app.ts
import Vue from 'vue'
import router from './router'
import App from './App.vue'
import store from './store' // 追加
new Vue({
el: '#app',
router,
store, // 追加
components: { App },
template: '<App />'
})
画面確認
$ npm run watch
localhost:3000/loginにアクセスし、**Login page.**の文字が表示されたらOK