LoginSignup
1
0

More than 3 years have passed since last update.

【備忘録】DockerでLaravel + Vue環境構築(Nuxtなしver)

Last updated at Posted at 2021-04-09

目的

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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0