クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【HTML】EJSをGulpでコンパイルしてみる(SyntaxErrorでちょい苦戦)

Gulpの続きです。前回はHTMLテンプレートエンジンのPugをGulpでコンパイルしました。今回はEJSのコンパイルにトライ。それではいきましょう!

【目次】

※参考:前回記事
【HTML】PugをGulpでコンパイルしてみる(メタ言語初コンパイル!) - クモのようにコツコツと

※参考:メタ言語(HTMLテンプレートエンジン、AltCSS、AltJS)まとめ
qiita.com

フォルダ作成→移動→package.json作成→Gulpインストール

前回のPugと同じ手順。

※参考:【HTML】PugをGulpでコンパイルしてみる(メタ言語初コンパイル!) - クモのようにコツコツと

node.jsとnpmは入っている前提(下記のコマンドでバージョン番号が出る)

node -v
npm -v

コンパイルを実行したいフォルダを作成する。今回は「gulp_ejs」とする。

cdコマンドで移動する

cd /(フォルダ)/gulp_ejs

package.jsonを作成

npm init -y

ローカルにGulpインストール

npm install -D gulp

EJSパッケージ(gulp-ejs他)のインストール

EJSコンパイルに必要なnpmのパッケージをインストールする。こちらの記事を参考に。

※参考:EJSの使い方!静的なHTMLサイトで「共通パーツ」と「変数」を使おう | HPcode

  • gulp-ejs:EJSコンパイル
  • gulp-rename:拡張子リネイム(.ejs→.html)
  • gulp-replace:空白行削除(任意)

まず「gulp-ejs」をインストール

npm install -D gulp-ejs

次に「gulp-rename」

npm install -D gulp-rename

これはEJSファイルの拡張子「.ejs」を「.html」に変換する役割。以前は不要だったが最近はこれがないと拡張子が「.ejs」のままになってしまうとのこと。

※参考:gulp-ejsで拡張子がejsになってしまう問題(.htmlにしたい) - Qiita

最後に「gulp-replace」

npm install -D gulp-replace

後述する「インクルード」時にインクルードファイルに変数を読み込むとEJSコンパイル時に変数の行が空白行になる。その空白行を削除する役割。これは必須ではなくコードの見た目を整える目的でインストールした。

全てインストールが成功するとpackage.jsonに追記された!

  "devDependencies": {
    "gulp": "^4.0.2",
    "gulp-ejs": "^5.0.0",
    "gulp-rename": "^2.0.0",
    "gulp-replace": "^1.0.0"
  }

ファイルを作る

「gulp_test」フォルダの中に下記の構成のファイルを追加する。前回と似た構成。

当初、commonフォルダの中に_header.ejs_footer.ejsを作った。

gulp_ejs
├ejs
│├common
││├_header.ejs
││└_footer.ejs
│└index.ejs
└gulpfile.js

そのファイルの中身をindex.ejsでインクルードさせようとした。そしたらコンパイル実行時にSyntaxErrorが起こった。

シンタックスエラーとはコンパイル時にわかる構文エラーのこと。

※参考:https://wa3.i-3-i.info/word14894.html

原因を調べたが、なかなか特定にいたらなかった。。そのため、今回はインクルードは諦めてindex.ejsファイル単体でコンパイルすることにした。

gulp_ejs
├ejs
│└index.ejs
└gulpfile.js

gulpfile.jsにgulp.task()を記述

gulpfile.jsにgulp.task()メソッドでコンパイルの設定を記述。

const gulp = require("gulp");
const rename = require("gulp-rename");
const ejs = require("gulp-ejs");
const replace = require("gulp-replace"); 

gulp.task("ejs", done => {
  gulp
    .src(["ejs/**/*.ejs", "!ejs/**/_*.ejs"])
    .pipe(ejs({}, {}, { ext: ".html" }))
    .pipe(rename({ extname: ".html" }))
    .pipe(replace(/[\s\S]*?(<!DOCTYPE)/, "$1"))
    .pipe(gulp.dest("./"));
  done();
});
  • 変数gulpgulpを読み込む
  • 変数renamegulp-renameを読み込む
  • 変数pjsgulp-ejsを読み込む
  • 変数replacegulp-replaceを読み込む
  • gulp.task()メソッド実行。第一引数はejs、第二引数は無名関数で引数はdone
  • 無名関数の中はgulp.src().pipe().pipe().pipe().pipe()とチェーンになっている
  • src()の第一引数は「○○.ejs」ファイル、第二引数は「_○○.ejs」ファイル以外(!)
  • 一つ目のpipe()ejs()メソッドでhtmlにコンパイル
  • 二つ目のpipe()rename()メソッドで拡張子を.htmlにリネイム
  • 三つ目のpipe()replace ()メソッドで<!DOCTYPE〜より上の行を削除
  • 四つ目のpipe()gulp.dest()メソッドで上のディレクトリに吐き出す

前回より記述は増えているものの全体的な構成は似ている。

index.ejsを作成

以前の「EJSでFizzBuzz」のコードをベースに

※参考:【HTML】テンプレートエンジンEJSでFizzBuzzる!(Pugとの比較あり) - クモのようにコツコツと

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>はじめてのEJSコンパイル</title>
<meta name="description" content="GulpでEJSコンパイル、ひとりでできるかな?">
</head>

<body>
    <header>
        <h1>はじめてのEJSコンパイル</h1>
    </header>

<% var h1Title = 'EJSでフィズバズる'; %>
<% var count = 30; %>

<section>
  <h1 class="red"><%= h1Title %></h1>
  <p>EJSで変数、for文、if文を使ってフィズってバズってみた。</p>
  <ul>
    <% for (var i = 1; i < count+1; i++) { %>
        <% if (i % 3 == 0 && i % 5 == 0) { %>
        <li>フィズってバズった!</li>
        <% } else if (i % 3 == 0) { %>
        <li>フィズった!</li>
        <% } else if (i % 5 == 0) { %>
        <li>バズった!</li>
        <% } else { %>
        <li><%= i %></li>
        <% } %>
    <% } %>
  </ul>
</section>

<footer>
  <p>©️イイダリョウ</p>
</footer>
</body>
</html>

(後述するように記述ミスがいくつか見つかったので、修正しています)

EJSコンパイル実行

コンパイル実行!

npx gulp ejs

前回書いたようにローカルでの実行は頭にnpxが必要。

どうだ? f:id:idr_zz:20191206064434j:plain やった、成功!

フォルダ直下にindex.htmlが追加された!

gulp_ejs
├ejs
│└index.ejs
├gulpfile.js
└index.html

HTMLコード

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>はじめてのEJSコンパイル</title>
<meta name="description" content="GulpでEJSコンパイル、ひとりでできるかな?">
</head>

<body>
    <header>
        <h1>はじめてのEJSコンパイル</h1>
    </header>




<section>
  <h1 class="red">EJSでフィズバズる</h1>
  <p>EJSで変数、for文、if文を使ってフィズってバズってみた。</p>
  <ul>
    
        
        <li>1</li>
        
    
        
        <li>2</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>4</li>
        
    
        
        <li>バズった!</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>7</li>
        
    
        
        <li>8</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>バズった!</li>
        
    
        
        <li>11</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>13</li>
        
    
        
        <li>14</li>
        
    
        
        <li>フィズってバズった!</li>
        
    
        
        <li>16</li>
        
    
        
        <li>17</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>19</li>
        
    
        
        <li>バズった!</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>22</li>
        
    
        
        <li>23</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>バズった!</li>
        
    
        
        <li>26</li>
        
    
        
        <li>フィズった!</li>
        
    
        
        <li>28</li>
        
    
        
        <li>29</li>
        
    
        
        <li>フィズってバズった!</li>
        
    
  </ul>
</section>

<footer>
  <p>©️イイダリョウ</p>
</footer>
</body>
</html>

むむ?なんだこれ、スッカスカ。gulp-replaceの空行削除が実行されていないようだ?

(まぁページ表示上は問題ないから今回は良しとしておくか…)

外部ejsファイルをインクルードする書き方(include)

先ほど書いたインクルードを行う場合は、ヘッダーフッター部分はこのような書き方になる。

<!--ヘッダー-->
<% include common/_header %>

<!--フッター-->
<% include common/_footer %>

include の次にフォルダ、ファイル名を書く。commonがフォルダ名。_header_footerとファイル名に拡張子は書かないようだ。

さらにページ固有のtitlemeta discriptionindex.ejsの冒頭に書いてそれを_headerに読み込ませることもできる。(コンパイル後にこの変数部分が空行になるためgulp-replaceを使う)

先ほど書いたようにSyntaxErrorが起こってうまくいかなかったため今回は断念した。

SyntaxErrorは何度も起こった

また、インクルード部分以外にページ本体のFizzBuzz部分にもSyntaxErrorは何度も起こった。記述ミスを結構見つけて書き直して、ようやくエラーがなくなった。

例えばEJSの閉じ記号%>が抜けていたり、変数を表示する記号<%=<%になっていて表示されなかったり。

※参考:テンプレートエンジンEJSで使える便利な構文まとめ - Qiita

やはり実際にコンパイルしてみないとわからないなーと感じた。

元記事の方も修正しておきました。

※参考:【HTML】テンプレートエンジンEJSでFizzBuzzる!(Pugとの比較あり) - クモのようにコツコツと

SyntaxErrorはこのような表記になった。

まず冒頭の3行に実行状況

[(時間)] Using gulpfile ~/(フォルダ)/gulp_ejs/gulpfile.js
[(時間)] Starting 'ejs'...
[(時間)] Finished 'ejs' after 8.47 ms

そのあとにエラー通知

events.js:187
      throw er; // Unhandled 'error' event
      ^
PluginError [SyntaxError]: Unexpected identifier in /(フォルダ)/gulp_ejs/ejs/index.ejs while compiling ejs

Google翻訳

events.js:187
      スローer; //未処理の「エラー」イベント
      ^
PluginError [SyntaxError]:ejsのコンパイル中に/Users/iidaryou/Desktop/ir/gulp_ejs/ejs/index.ejsの予期しない識別子

そのあとにこのような助言が。

If the above error is not helpful, you may want to try EJS-Lint:
https://github.com/RyanZim/EJS-Lint
Or, if you meant to create an async function, pass `async: true` as an option.
    at new Function (<anonymous>)
    at Template.compile 

Google翻訳

上記のエラーが役に立たない場合は、EJS-Lintを試してください。
https://github.com/RyanZim/EJS-Lint
または、非同期関数を作成する場合は、オプションとして「async:true」を渡します。

EJS-Lintを使えばエラーの解決方法がもっと早くわかるのかも。ES-Lintと名前が似ている。これか。

※参考:ejs-lint - npm

このあとには膨大なエラーコードが続く…

なお、ターミナルがエラーコードで埋め尽くされて見にくくなったらclearコマンドで綺麗にできる。

※参考:【シェル】ターミナル画面をリセット(クリア)するコマンド&ショートカットキー

最後に

ということでPugに続き、EJSのコンパイルも体験できまいした!

今回、本当はテンプレートエンジンならではの共通パーツ(ヘッダーフッターなど)をインクルードするところまで行きたかった。

SyntaxErrorが頻発して原因特定に時間がかかりそうだったため、単体ファイル構成にした。SyntaxErrorがなくなるまで修正し続けてなんとか成功しました!

Pugに比べるとEJSはHTMLとほぼ同じ書式で読み書きしやすいが、その文、閉じ括弧など記述量が増えているため、エラーが起こる確率は増えているように感じました。

その代わり、Pugと違ってEJSは閉じ括弧が目印なのでインデントについては厳密ではないので良し悪しがありますね。

ただ、記述ミスは完全に防ぐのは難しいため、ミスを解決しやすくする仕組み(EJS-Lintなど)を検討した方がいいのかもしれない、と感じました。

次回は、AltCSS!Sass(SCSS)のコンパイルにトライしようと思います。それではまた!


※参考:メタ言語(HTMLテンプレートエンジン、AltCSS、AltJS)まとめ
qiita.com