tohokuaikiのチラシの裏

技術的ネタとか。

laravel-mixでnpm run watchしたら無限ループに陥ったので対処したこと

何気なくsassを書き直したら、npm run watchしてるのが無限ループしてた…

原因は画像のタイムスタンプ?

原因を探ってみると、

header {
    background-image: url("../images/icon_header.png");
}

が原因っぽい。

試しに、npm run prodしてみると、無事にコンパイルされて

  DONE  Compiled successfully in 24206ms                                                                   2:45:32 AM 

                                                    Asset       Size  Chunks                    Chunk Names 
                                             /css/app.css  724 bytes       1  [emitted]         /js/user
  images/icon_header.png?5154d06ae582f6e2548c6d920674da59   1.04 KiB          [emitted] 

とか出る。images/icon_header.png のタイムスタンプ見ると

なるほど、sassコンパイルする時に画像も変更するらしい。変更するんだけど、

$ md5sum ~/resources/images/icon_header.png ~/public/images/icon_header.png
5154d06ae582f6e2548c6d920674da59  ~/resources/images/icon_header.png
5154d06ae582f6e2548c6d920674da59  ~/public/images/icon_header.png

という感じでファイル自体は変更してなさそう。

対応方法

この機能をOFFにしてしまえばいいっぽい。

直接的な対応方法

laravel-mixのオプションでこの機能をOFFにするには

mix.options({
  processCssUrls: false
})

とする。

…なんだけど、これをOFFにするのはrun prodする時だけで良いので

const is_prod = mix.inProduction() ? true : false;
mix.webpackConfig({
  devtool: is_prod ? "" : "inline-source-map",
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': __dirname + '/resources/js'
    }
  },
}).options({
  processCssUrls: is_prod
})
.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css/')

…ということで、watchしなければ問題ないので、productionコンパイルの時だけは聞くようにした

Laravelのview(bladeテンプレート)からVue.jsにグローバルパラメータを渡したい時など

最初、

<router-view app_name="{{ config('app.name') }}"></router-view>

とかしてたけど、こんなの逐一やってらんねー。

検索したけどあんまり見つからない…ajaxで渡せとかそんな面倒なこと…

ということで、「ぼくのかんがえるさいきょうのLaravelからVueへの変数の渡し方」

Laravel 側

Controllerで変数を渡す

<?php
    /**
     * @brief vue用のViewを返す
     */
    public function vue()
    {
        $params = [
            'app_name' => config('app.name')
        ];
        return view('index')
            ->with('params', $params);
    }

bladeでJavaScriptグローバル変数に振ってやる

@section('content')
<div id="app">
    <router-view></router-view>
</div>
<script>var globalParams = @json($params);</script>
<script src="{{ asset(mix('js/app.js')) }}" defer></script>
@endsection

Vue側

Vueのrootにcomputedにgparamをつける

import Vue from 'vue';
// 省略
const app = new Vue({
    el: '#app',
    // 省略
    computed: {
        gparam: function(){
            return globalParams;
        }
    },

Vueの各Vueやコンポーネントでは$rootでcallする。

<template>
<div>
     <h1>{{ $root.gparam.app_name }}</h1>

ドヤァ

PhpStormでXdebugがつながってるのにブレークポイントで止まってくれない時

./artisan serveだと止まってくれるのにApacheだとブレークポイントで止まってくれないなぜだ!!!???

とずっと思ってました。

色々と困ってる人がいました。
Googleで「file path is not mapped to any file path on server」とか検索すると

Debug problems: "remote file path ... is not mapped to any file path in project" – IDEs Support (IntelliJ Platform) | JetBrains
PHP(xdebug)+IntelliJでブレークポイント置いてるのに、そこで止まってくれないとき - カイワレの大冒険 Third
PhpStorm throws an error "Remote file path ... is not mapped to any file path in project" in the client-to-API context – IDEs Support (IntelliJ Platform) | JetBrains

で、ようやくわかりました。

ファイルのマッピングがうまくいってないんです。

artisan serveの場合は、相対パスで上手く決めてくれるっぽいんですが、Apacheだとそうはいきませんよね。

なので、ネットワークドライブに割り当てた後、こういう感じでProjectFilesにバーチャルパスをマッピングするとうまくいきました。

f:id:tohokuaiki:20200916152151p:plain

あー。こんなことで…

MySQLのUNIQUE制約のキー長制限に引っかかった

LaravelのユーザーテーブルのEmailのUNIQUEが掛けられなかった。

Server version: 5.5.65-MariaDB MariaDB Server

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))

maxで767Byteなんだけど、…ってことは、UTF8が1文字4byteで計算されてるのかな?

767÷4=191.75なので…191文字までなら大丈夫なのかな?

ということで実験

VARCHAR(192)にしてみる

MariaDB [foodb]> alter table users change email email varchar(192) not null;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [foodb]> alter table `users` add unique `users_email_unique`(`email`);
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

ダメだって…

VARCHAR(191)にしてみる

MariaDB [foodb]> alter table users change email email varchar(191) not null;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [foodb]> alter table `users` add unique `users_email_unique`(`email`);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

計画通り(夜神ライトAA略

理由

show create table users;

してみると、

CREATE TABLE `users` (
...略...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

ってなってて、utf8mb4だった。ので4byteなのね。

Vue + Laravelでサブディレクトリに展開する際にやったこと。

Laravel

Apachehttpd.confにてバーチャルホスト設定にAliasを書く

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName www.example.com
        DocumentRoot /home/vagrant/htdocs

        Alias /baccarat_campaign_form "/home/vagrant/laravelapp/public"

        <Directory "/home/vagrant/laravelapp/public">
        Options FollowSymLinks
        AllowOverride All
        Require all granted
        </Directory>

こんな感じでAlias

Laravelのpublic/.htaccessRewriteを書き直す。

    RewriteEngine On
    RewriteBase /subdirectory_name #追加

...
    # RewriteRule ^ %1 [L,R=301] # コメントアウト
    RewriteRule ^(.*)/$ /subdirectory_name/$1 [L,R=301] #追加

bladeテンプレートの{{ mix(/js/foo.js) }} を描き直す

{{ mix(/js/foo.js) }}

{{ asset(mix(/js/foo.js)) }}

に変更。cssも。

Vuejsの変更

routerにbaseを入れる

export default new Router({
    mode: 'history',
    base: '/subdirectory_name/',
    routes: [
        {

axiosのbaseUrlを変更する。

これ、なんかいい方法ないのかな?とは思うけど、とりあえず。

import Vue from 'vue';
import "es6-promise/auto";
import VueRouter from 'vue-router';
import router from './router.js';
axios.defaults.baseURL = '/subdirectory_name';
window.Vue = require('vue');
Vue.use(VueRouter);

って感じで、axios.defaults.baseURL を設定する。