豆腐とコンソメ

豆腐とコンソメ

もろもろのプログラム勉強記録

LaravelのBladeをPugで書くときに困ったこと

ヘロー!久しぶりの更新です。
わからないことが多すぎて、何から整理すればいいやらという状態で、ろくに記事も書いていませんでした。

このままフェードアウトするのも悲しいので、ピンポイントでかつあまり役に立たさなそうなことを書くことにしたよ!

もし同じ状況の人がいて、こうしているよ、っていうのがあればぜひ教えてください!

LaravelのBladeとPug

最近、Laravelを触っています。
Laravelには便利なテンプレートエンジンBladeがついていて、コントローラーから渡す変数を展開したり、テンプレートを継承したり、インクルードしたりできたりします。

node.jsのフレームワークexpressとpugの関係にそっくりですね。

今回は、そんなBladeをpugで書いて、Bladeファイルに変換して〜みたいなときに自分が苦労したことを書きます。

そもそも、Bladeに変換するなら、pugじゃなくって最初からBlade使えばいいんじゃない?っていう考えもあるかと思います。

pugで書くメリットとしては、

  • コーディングがPugの方が若干早い
  • Bladeで継承だったりインクルードするのはリクエストがあるごとに行われる。
    pugで事前に変換しといた方がパフォーマンスがいいかもしれない。

という理由があるかと思います。
1点目に関しては、エディタがemmetに対応していれば、あんまかわらなかったりするのかな?と思ったりもします。
とりあえずpugを使っていけば戻れない何かがある気がしています。

2点目に関しては、想像です。。。

といまいち、説得力がないかもしれませんが、続けます。

簡単なForm画面

まずはLaravelでこんな感じでpugファイルを置いてみます。
中身はシンプルなフォーム画面です。

ディレクトリ構成

├── components
│   └── _head.pug
├── index.pug
└── template
    └── _layout.pug


_head.pug


_layout.pug


index.pug


コンパイルしよう

Laravelに標準で用意されているlaravel-mixと、別途laravel-pug-mixを使って、pugからblade.phpにコンパイルしていきます。
コンパイルに関しては、こちらの記事を参考にさせていただきました!

qiita.com


webpack.mix.js

let mix = require('laravel-mix');
mix.pug = require('laravel-mix-pug');

mix.pug('resources/assets/pug/form_sample/index.pug', 'resources/views/form_sample',{});


コンパイル

$ npm run dev


ただ、私のWindowsのVagrant環境でlaravel-pug-mixを使ってると、コンパイルに結構な時間が掛かってちょっとしんどいです。

ただ遅いだけならいいんですが、私は大抵何かしらミスをしているので、時間がかかったあげくコンパイルエラーが頻発すると、作業効率がものすごく落ちます。

同じぐらいのスペックのMacのVagrantだと、そこまで気にならないのでちょっと不思議です。


gulpを使ってpugをコンパイルする

参考までに、gulpを使って、コンパイルもしてみたので、書いておきます。

コンパイルについては、こちらを参考にさせていただきました。

blog.mismithportfolio.com

まずは、gulpをインストールします。
グローバル環境にインストールしちゃいます。

gulpのインストール

$npm install gulp -g


また、pugにコンパイルするためのモジュール、gulp-pagもインストールします。

gulp-pugのインストール

$npm install gulp-pug


さらにデフォルトでは、拡張子がhtmlになってしまうので、renameできるgulp-renameもインストールします。

gulp-renameのインストール

$npm install gulp-rename


最後にgulpfile.jsを作成します。

gulpfile.js

var gulp = require('gulp');
var pug = require('gulp-pug');
var rename = require('gulp-rename');

gulp.task('pug', () => {
 return gulp.src(['./resources/assets/pug/form_sample/**/*.pug', '!./resources/assets/pug/form_sample/**/_*.pug'])
 .pipe(pug({
   pretty: true
 }))
 .pipe(rename({
     extname: ".blade.php"
 }))
 .pipe(gulp.dest('./resources/views/form_sample'));
});


上記を終えたらgulpでコンパイルタスクを実行します。

コンパイル

$gulp pug


こんな画面とHTMLが出力されるよ

bladeファイルにコンパイルされると、こんな感じのhtmlが出力されます。
bladeといっても、bladeの構文を使ってないので、ただのHTMLとかわりません。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
    <meta name="viewport" content="width=device-width">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>form_sample</title>
  </head>
  <body>
    <form method="post" action="/form_sample">
      <h1>シンプルなPOST </h1><br>
      <input type="text" name="food_name">
      <button>PushMe</button>
    </form>
  </body>
</html>


f:id:konoemario:20171101212420p:plain:w500
表示される画面


本題

blade構文をpugで書いてみる

ようやく本題です。

blade構文をpug上で書いてみます。

LaravelでFormを作るときに必ず?使うであろう「csrf_field()」で試してみます。

blade構文の例

    <form method="post" action="/form_sample">
        {{ csrf_field() }}  ←こいつ
      <h1>シンプルなPOST </h1><br>
      <input type="text" name="food_name">
      <button>PushMe</button>
    </form>


このcsrf_filed()は、Larabelが用意してくれているメソッドで、bladeからhtmlに展開されると、以下のようにCSRF攻撃を防ぐトークンを埋め込んでくれます。

csrf_filed()がhtmlに展開された

    <form method="post" action="/form_sample">
       <!-- csrf_token -->
       <input type="hidden" name="_token" value="krHTyotnNw9KA3NCMVNck1qZ3X8B8xCn7Qj3tATu">
      <h1>シンプルなPOST </h1><br>
      <input type="text" name="food_name">
      <button>PushMe</button>
    </form>


では、まずは無邪気に書いてみましょう。

無邪気にindex.pugに追加


これをコンパイルしてみると、{{csrなんて構文は知らんよと怒られちゃいます。

怒られる

unexpected text "{{csr"


と、いろいろ書こうと試していたんですが、 結論から書くと

span {{csrf_field()}}


で問題なくいけちゃいました。

@if構文を書いてみる

内容が微妙になってしまったので、こちらも試してみました。
フォームのバリデーションを表示する際によくやる?やつです。

よくあるエラーを表示するやつ

    <form method="post" action="/form_sample"><span>{{csrf_field()}}</span>
      <h1>シンプルなPOST </h1><br>
      <input type="text" name="food_name">
      <button>PushMe</button>
      @if(count($errors))
        <ul>
        @foreach($errors->all() as $error)
          <li style="color:red">{{ $error }}</li>
        @endforeach
        </ul>
      @endif
    </form>


空っぽで送信するとエラーを表示してくれる

f:id:konoemario:20171101225726p:plain:w500
@ifを使う例

こちらもいろいろと試してみたところ、 とりあえずできたのがこちらに書いてある、「.の後のインデントは文字列として評価される」というものです。

qiita.com

最初は公式を見てたんですが、どこに書いてあるんですかね。

ひどくわかりにくいのですが、こんな形で書いてみました。

_erros.pug


_errors.pugとして別ファイルで再利用可能なようにしておきます。

使う側は、こんな感じで使いたい箇所でincludeします。

index.pug

これで、無事bladeに展開することができました。