FullCalendar 4をlaravel/mixでビルドして利用する

LaravelのプロジェクトでFullCalendarを導入する方法についてまとめてみました。

FullCalendarを利用するにはscriptタグでソースを読み込む方法もありますが、メンテナンス性を考えるとパッケージをnpmで管理して、Laravel Mixを利用してビルドするのが良い方法です。

特にFullCalendar 4からはコア以外の機能はプラグインの形で都度追加する必要があるためよりパッケージ管理システムを利用することが推奨されています。

Laravel Mixとは

以前の記事、Laravel 6.x laravel/uiを利用してbootstrap 4を適用する で少し触れていますが、Laravel Mixは、Laravelのフロントエンド ビルド環境で、Webpackを簡単に利用するラッパーみたいなものです。

Laravel Mixのセットアップは以下のようにプロジェクトの作成後npm installするだけで、自らWebpack環境を用意しなくてもLaravelと組み合わせてVue.jsやReactを簡単に使い始められます。

$ composer create-project --prefer-dist laravel/laravel laravel-fullcalendar
$ cd laravel-fullcalendar
$ npm install

ビルドの設定はwebpack.mix.jsファイルに記述します。例えば、jsとcssのビルドする場合、以下のように入力ファイルと出力するディレクトリを指定するだけです。

mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css');

とても簡単ですね。

ビルドはnpm run dev、開発中はnpm run watchしてすぐ開発が進められます。

また、通常Webpackで複数の入力ファイルを扱うのは工夫が必要ですが、Laravel Mixなら以下のように簡単に追加できます。

mix.js('resources/js/blog.js', 'public/js')
    .sass('resources/sass/blog.scss', 'public/css');
mix.js('resources/js/admin.js', 'public/js')
    .sass('resources/sass/admin.scss', 'public/css');

例えば、これはブログ記事と管理画面のビューで使うjsやcssのアセットをビルドするイメージです。

FullCalendarのインストール

ここから本題ですが、まずFullCalendarのパッケージをnpmで追加していきます。

この記事では、FullCalendarのビューはTimeGrid Viewのみを使用します。
また、予定をドラッグで変更できるようにするのと、複数のタイムゾーンに対応したいので、interactionmoment-timezoneも追加します。
まとめるとコアも含めFullCalendar関連は以下の4つのパッケージをインストールします。

  • @fullcalendar/core
  • @fullcalendar/timegrid
  • @fullcalendar/interaction
  • @fullcalendar/moment-timezone

また、@fullcalendar/moment-timezoneは、moment-timezoneを別途インストールする必要があります。

以下のコマンドでインストールします。

$ npm install @fullcalendar/core @fullcalendar/timegrid @fullcalendar/interaction moment-timezone @fullcalendar/moment-timezone

FullCalendarの実装

resources/js/app.jsを編集しても良いですが、FullCalendarはすべてのページで使用することは無いと思うので、js、cssファイルを分けます。

resources/js/fullcalendar.jsを追加して以下を記述します

// resources/js/fullcalendar.js
import { Calendar } from '@fullcalendar/core'
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import momentTimezonePlugin from '@fullcalendar/moment-timezone';

document.addEventListener('DOMContentLoaded', function () {
  const calendarEl = document.getElementById('calendar');

  const calendar = new Calendar(calendarEl, {
    allDaySlot: false,
    plugins: [timeGridPlugin, momentTimezonePlugin, interactionPlugin],
    timeZone: 'Asia/Tokyo', // momentTimezonePlugin
    defaultView: 'timeGridWeek',

    events: []
  });

  calendar.render();
});

次に、スタイルシートresources/css/fullcalendar.scssを追加して以下を記述します。

// resources/css/fullcalendar.scss
@import "~@fullcalendar/core/main.css";
@import "~@fullcalendar/timegrid/main.css";

Laravel Mixの設定ファイルに上記のファイルを読み込む設定を追加します。

// webpack.mix.js

mix.js('resources/js/fullcalendar.js', 'public/js')
  .sass('resources/sass/fullcalendar.scss', 'public/css');

ここでビルドしてみましょう。

$ npm run dev

以下のように、ビルドされたresources/js/fullcalendar.jspublic/js/fullcalendar.jsに、resources/css/fullcalendar.scsspublic/css/fullcalendar.cssに出力されます。

Laravel Mixでjs、cssをビルド

生成したアセットをビューで読み込んで表示してみます。

とりあえずここではwelcome.blade.phpを以下のように置き換えてみます。

// resources/views/welcome.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">

        <title>Laravel</title>

        <link href="{{ asset('css/fullcalendar.css') }}" rel="stylesheet">
        <script src="{{ asset('js/fullcalendar.js') }}" defer></script>
    </head>
    <body>
        <div id="calendar"></div>
    </body>
</html>

開発サーバーを起動してhttp://127.0.0.1:8000を開きます。

$ php artisan serve

予定を表示したり追加したりできませんが、FullCalendarの表示ができました。

FullCalendarをLaravelのビューに表示

Laravel Homestead内のPostgreSQLにMacのpsqlから接続する手順

少し前に開発機のMacを買い替えたためHomesteadの環境を作り直してみました。
LaravelプロジェクトのデータベースにはPostgreSQLを使っているのですが、改めて環境を作るにあたってPostgreSQLをメインの仕事で使うことは無いし、psqlでHomesteadのPostgreSQLに接続するためだけにMacのローカルにPostgreSQLサーバーをインストールしたくないと思い、psqlだけ使えるようにする方法について調べてみました。

イマイチ一次情報にた取り付けずなところも多かったのですが、執筆時点でおそらくベストっぽい構成のような気がします。

psqlのインストール

homebrewでpsqlをインストールします。

homebrewには「psql」という名前のパッケージ(Formula)は無いですが、libpqをインストールするとpsqlが含まれています。

$ brew install libpq
...
<!--more-->

==> libpq
libpq is keg-only, which means it was not symlinked into /usr/local,
because conflicts with postgres formula.

If you need to have libpq first in your PATH run:
  echo 'export PATH="/usr/local/opt/libpq/bin:$PATH"' >> /Users/hrendoh/.bash_profile

For compilers to find libpq you may need to set:
  export LDFLAGS="-L/usr/local/opt/libpq/lib"
  export CPPFLAGS="-I/usr/local/opt/libpq/include"


$ brew link --force libpq
Linking /usr/local/Cellar/libpq/12.3... 370 symlinks created

If you need to have this software first in your PATH instead consider running:
  echo 'export PATH="/usr/local/opt/libpq/bin:$PATH"' >> /Users/hrendoh/.bash_profile

インストール時に出力されるメッセージで「libqdはkeg-onlyなので、/usr/localにシンボリックリンクは作成されませんよ」と言われています。

ところで「keg-only」とは、一般用語に直すと、homebrewのパッケージが配置されるディレクトリ(Celler)へライブラリなど(Keg)をダウンロードして配置するだけのパッケージ(Fomula)ということらしいです。

Homebrew用語、よく知らないで使っていたので調べてしまいまいした。

参照

話を戻すと、libqpをインストールしてもパスが通っていないので、以下のどちらかの手順を実行してパスを通します。

  1. brew linkコマンドで/usr/local/binにシンボリックリンクを作成する
$ brew link --force libpq
  1. .bash_profileなどでパスを通す
echo 'export PATH="/usr/local/opt/libpq/bin:$PATH"' >> /Users/$(whoami)/.bash_profile

以上で、psqlが使えるようになります。

では実際に接続してみます。

Homesteadは、PostgreSQLのポートは54320でフォワードされてますので以下のようにポートを指定して接続します。

$ psql -U homestead -h localhost -p 54320
Password for user homestead: 
psql (12.3, server 12.2 (Ubuntu 12.2-2.pgdg18.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

homestead=# 

無事接続できました。しかし、Laravelで開発しててpsqlでアクセスするのってcreate databaseするときくらいのような。。

参照: Ports | Laravel Homestead – Laravel – The PHP Framework For Web Artisans

補足

Error: The following directories are not writable by your userを解決するには

$ brew install libpq 
Error: The following directories are not writable by your user:
/usr/local/lib/pkgconfig

You should change the ownership of these directories to your user.
  sudo chown -R $(whoami) /usr/local/lib/pkgconfig

And make sure that your user has write permission.
  chmod u+w /usr/local/lib/pkgconfig

メッセージの説明に従い、自分に対して/usr/local/lib/pkgconfigに書き込み権限を付けます

$ sudo chown -R $(whoami) /usr/local/lib/pkgconfig
$ chmod u+w /usr/local/lib/pkgconfig

Express v4.xでJSONのリクエスト/レスポンスを取得する正しい方法

ExpressでJSONのリクエストを受け付けて、JSONのレスポンスを返す処理のメモです。

たまにExpressで検証などすることがあるのですが、いつもJSONの扱い方を検索している気がするので自分でもまとめておくことにしました。

また、検索するとbody-parserをインストールするように書かれている記事が多いのですが、2020年5月現在はExpress本体にミドルウェアが用意されています。
よって、以下の方法がおそらく現在最もシンプルで標準的な手順になると思います。(公式マニュアル読めばいいという話でもありますが)
“Express v4.xでJSONのリクエスト/レスポンスを取得する正しい方法” の続きを読む

Vue.js x TypeScriptのプロジェクトでjQuery UIを使う

以前の記事「React x TypeScript x Webpackの開発環境でjQuery (Bootstrap)を使うには」のVue.js x TypeScript版になります。

改めて調べた背景としては、Vue x TypeScriptのプロジェクトで、ある要素をドラッグしてただ移動するという機能をHTML5のDrag and Drop APIを使って実装しようとしたところ、ただの移動を実装するのは意外と面倒でした。そこで、昔ながらのライブラリの導入を検討してみるかと思いつき試したところです。

jQuery UI以外の候補としては、interactjsあたりがパッケージ内に型定義も含んでいて良さそうでしたが残念ながらコンパイルが通らずその修正は大変そうだったので、結局一番使われていて型定義もしっかりしていそうなJQuery UIを試してみることにしました。

この記事のサンプルはGithub hrendoh/vue-ts-jqueryui-example にアップしていますので参照ください。
動作については記事本文の最後にgifアニメを貼っていますが、箱を追加して移動できるというシンプルなサンプルです。

プロジェクトの作成

Vue CLIで、TypeScriptを使用するように設定し、その他はなしで作成したプロジェクトに設定していきます。

vue cliでtypescriptのプロジェクトを作成

その他設定は以下の通り。

jquery jquery-uiのインストール

$ npm install jquery jquery-ui --save
$ npm install @types/jquery @types/jqueryui --save-dev

TypeScriptのコンパイラーオプションのpathsにjquery-ui用の型定義ファイルを指定します。

// tsconfig.json
{
  "compilerOptions": {
    ...
    "paths": {
      "@/*": [
        "src/*"
      ],
      "jquery-ui": [
        "node_modules/@types/jqueryui/index"
      ]
    },
    ...

あとは、jQuery UIを使う箇所で以下のようにimportすればOKです。

import $ from "jquery";
import "jquery-ui";

サンプルではcomponents/Box.vueの12行目でimportしています。

jquery jquery-uiのソースの読み込み

ここまでの設定は、TypeScriptのコンパイルを通すところまでで、実際に動かすにはjQueryとjQuery UIのソースをビルド後のファイルapp.xxxx.jsに含める必要があります。

まず、npmパッケージjquery-uiにはビルド前のソースのみ含まれていないため、ビルド済みのソースを含むjquery-ui-distを追加でインストールします。

$ npm install jquery-ui-dist --save

追加したjquery-ui-distのソースをバンドルするWebpackの設定はVueプロジェクトの設定ファイルvue.config.jsに記述します。

vue.config.jsファイルはVue CLIを作成したプロジェクトにはデフォルトで含まれていないので作成して以下の記述を含めます。

// vue.config.js
const path = require("path");
module.exports = {
  configureWebpack: {
    devtool: "source-map",
    optimization: {
      minimize: false
    },
    resolve: {
      alias: {
        // bind version of jquery-ui
        "jquery-ui": "jquery-ui-dist/jquery-ui.js",
        // bind to modules;
        modules: path.join(__dirname, "node_modules")
      }
    }
  }
};

再度ビルドすると、dragableがちゃんと動くことを確認できます。

jQuery UIによるドラッグの実装

課題 VSCodeの補完ができない

“jquery-ui”は、型定義が”jqueryui”と名前が合っていないため、VSCodeの補完とエラーが解決できません。

VSCodeでjquery-uiの型が参照できない

おそらく設定で解決できるのではと思いますが、未調査です。

ちなみに、”jquery-ui”ではなく”jqueryui“をインストールするとちゃんとVSCodeの補完も効きますが、公式があるのにそちらを使う気にはなれないのでVSCodeの設定を調べる方が正攻法かなとは思います。

参考

以下の記事は簡潔にまとまっていて参考になりました。

【TypeScript】外部ライブラリ(jQueryなど)を使用する方法をまとめてみる

あとはこのあたり

Error when using JQueryUI with TypeScript and DefinitelyTyped definition file

Laravel 6.x laravel/uiを利用してbootstrap 4を適用する

Laravel2 Advent Calendar 2019 – Qiita の15日目の記事になります。
(ちょうど空いていたのでぎりぎりですが参加させていただきました。)

Laravel 5.8以前ではフロントエンド フレームワークとしてbootstrapとVueがはじめから利用可能なように設定されていましたが、Laravel 6.xではデフォルトでは含まれなくなりました。

6.xでBootstrapを利用するには、フロントエンドのScafolding機能を提供するlaravel/uiのコマンドを使用してJavascriptのビルドとCSSのプリプロセッサ設定を生成する必要があります。

この記事では、Laravel 6.xのプロジェクトにlaravel/uiを利用してBootstrapをプロジェクトに導入する手順についてシンプルなアプリケーションを例に解説しています。
想定しているケースは、主にサーバー側のビューテンプレートで画面を実装する場合に、アプリケーション全体でBootstrap 4の基本的な機能を使ってマークアップと多少画面の動きをつけたい(DatePickerを利用したいなど)といった構成のアプリケーションです。
本格的にフロントエンド開発の環境を整えるには、Laravel Mixについても学ぶ必要がありますが、デフォルトのwebpack.mix.jsの設定でできる範囲にとどめて深堀りしません。

この記事のサンプルソースは Github リポジトリ https://github.com/hrendoh/laravel-ui-bootstrap-tasks に公開しています。記事の中で解説していないソースコードについてはこちらを参照ください。
“Laravel 6.x laravel/uiを利用してbootstrap 4を適用する” の続きを読む

LaravelのセッションをHeroku Redisに保存する

LaravelアプリのセッションをHeroku Redisに保存する設定する手順についてまとめてみます。

HerokuでRedisを利用する場合、現在(2019.11)は公式のHeroku Redisを利用できます。

公式ドキュメントはこちら: Heroku Redis | Heroku Dev Center

セッションをキャッシュに入れるのはなぜか?

ところで、改めてHerokuでセッションをRedisなどのストレージに保存する必要があるのか?ってことなんですが、試しにfree Dynoを使っていてすぐにDynoがsleepしてしまうような場合は、DynoのファイルシステムはEphemeral Disk(揮発性ディスク)なのでRedisなどに保存しておかないとsleepするたびにセッションが切れてしまいます。
また、Hobby以上のDynoの場合でも1日一回は再起動されるとのことなのでやはりキャッシュストレージに入れておいた方が良さそうです。
参照: Restarting | Dynos and the Dyno Manager

一方、1日1回くらいならまあいいかとしてDynoが複数の場合はでは必要なのか?って話ですが、セッション固定機能のSession Affinityを使えば問題ないかもしれません。
“LaravelのセッションをHeroku Redisに保存する” の続きを読む

HerokuにデプロイしたLaravelアプリのアセットのURLをhttpsにする手順

HerokuではSSLの処理をロードバランサーで行っているので、Dyno上のLaravelアプリケーションはデフォルト設定ではhttpで動いていると判定されアセットのURLがhttpになってしまします。

そのまま表示すると以下のようにブラウザの警告が出てしまいます。

Herokuのロードバランサーまわりについては、公式ドキュメントのHTTP Routingで説明されています。

Laravelで、ロードバランサー経由のhttpsリクエストを判定するには、公式ドキュメント「HTTP Requests」の「Configuring Trusted Proxies」の「Trusting All Proxies」に記述されている通りApp\Http\Middlewar\TrustProxiesクラスのproxiesの値にロードバランサーのIPアドレスをセットします。
Herokuの場合、そもそもロードバランサーのIPアドレスは判らないのですし、Web DynoにはグローバルIPアドレスは割あたってない(はず)ので、すべてのプロキシからのリクエストを信頼する「*」をセットします。

“HerokuにデプロイしたLaravelアプリのアセットのURLをhttpsにする手順” の続きを読む

Laravel 6.x on Heroku mailgun アドオンでメール送信実装手順

Laravel 6.xでは、3rdパーティのメール送信サービスMailgun, Postmark, Amazon SESが標準で選択できます。バージョンによっては、MandrillやSparkPostもサポートしていたようです。Transportのクラスは残っているので設定すれば使えるかもしれません。

一方、この記事を書いている2019年10月時点でHerokuアドオンとして利用可能なメールサービス(SMS含む)のラインナップは以下の通りです。

よって、Laravel 標準サポートで、Herokuのアドオンとして利用可能なサービスはMailgunのみとなります。
“Laravel 6.x on Heroku mailgun アドオンでメール送信実装手順” の続きを読む

Laravel 6.x でCSV出力を実装する(レスポンスストリームにそのまま返す版)

LaravelでCSV出力を実装してみたので手順をまとめます。

動作確認はLaravel 6でしていますが、この記事の内容は5.6以降で利用可能です。

CSVのサイズが大きくなる場合は、コントローラはCSV生成タスクをバックグラウンドキューに入れて非同期ジョブでCSVを生成してS3などのストレージに追加、処理が完了したらファイルのURLを応答に含めて通知するというのが正しい実装な気がしますが、ここではCSVに含めるレコードが少なくファイルサイズが小さめな限定的なケースを想定し、CSVを生成しながらそのまま応答ストリームに流すような実装について解説します。

小さめと書きましたが、プロセスのメモリーを節約して実行するのでネットワーク環境と多重度が低くプロセスを長めに専有することを許容できるシステムであれば大量レコードでも使えるのでプロジェクトによっては大量レコードのダウンロードにも使える仕組みとなっています。

利用するLaravelフレームワークの機能を整理

まずサンプル実装に使うLaravelの機能について解説してみます。

ストリームを応答として返す

大容量のファイルをストリームで帰す場合は、streamDownloadメソッドを利用します。streamDownloadメソッドは、Laravel 5.6から導入されたメソッドです。

Laravelのドキュメント HTTP ResponsesのFile Downloads Streamed Downloads で説明されています。
“Laravel 6.x でCSV出力を実装する(レスポンスストリームにそのまま返す版)” の続きを読む

Heroku SchedulerでLaravelのartisanコマンドを実行する

LaravelのartisanコマンドをHeroku Schedulerを使って、定期実行する手順に確認したのでまとめてみました。

Laravelのバージョンは、2019年9月時点での最新6.0で確認しています。

Heroku Schedulerのとは

Heroku Schedulerは、cronジョブ的な仕組みを提供するHeroku公式アドオンです。

ドキュメントによると実行間隔は10分、1時間、1日のみです。
この要件で問題なければ非常に便利な機能です。

実行時刻は正確ではないので、ジョブを正確な時刻に実行する必要がある場合はここで説明するSchedulerではなくCustom Clock Processを利用する必要があります。

また、Heroku Schedulerジョブで実行するタスクの実行時間について「Long-running jobs」には、実行時間が数分を超えるような長いタスクを実行する場合は、バックグラウンドキューに入れてワーカーDynoでタスクを実行するべきと書いてあります。
更に、スケジューラーで起動されたDynoは、次のスケジュール実行時間になると停止するとも書いてあります。
よって、基本的にはLaravelの場合QueuesをワーカーDynoで起動しておいて、スケジュールジョブではジョブをディスパッチするのみにするのが正しい実装になります。

しかし、この記事では、まずはHeroku Schedulerの動作の雰囲気を掴むため、Heroku Schedulerのジョブからシンプルなartisan commandを直接実行して動作を確認してみます。
“Heroku SchedulerでLaravelのartisanコマンドを実行する” の続きを読む