EJSで特定のファイルを共通ファイルとしてインクルードさせるとき、その共通ファイル内にあるパス指定部分にページ毎で異なる相対パスを設定させる方法で、インクルード時の引数を利用する方法としない方法とで2パターン紹介します。
- 紹介する方法はgulpを使用した実装方法になるので、予めgulpが使用できる環境を用意してください。
- EJSの基本的な使用方法などについては割愛しているので、「EJS -- Embedded JavaScript templates」や「GitHub - mde/ejs: Embedded JavaScript templates」などで確認してください。
使用するプラグインとファイル構成
プラグインのインストール
今回はgulpでEJSを使用するので、まず下記コマンドで「gulp-ejs」をインストールします。
$ npm i -D gulp-ejs
ファイル構成
ここで使用する方法は以下のようなファイル構成のものを使用した想定になり、後述するコード内のパスなどについてもこの構成をもとにしています。
/src
直下のindex.ejs
がTOPページ、/src/page
のindex.ejs
は下層ページ扱いとして、いずれも共通ファイルである/src/templates/_nav.ejs
を読み込んで表示させるというものになり、この_nav.ejs
内にあるパス指定を相対パスになるようにしていきます。
├─ /src
│ └─ /ejs
│ ├─ index.ejs
│ ├─ /page
│ │ └─ index.ejs
│ └─ /templates
│ └─ _nav.ejs
└─ gulpfile.js
インクルードの引数を利用する
タスクの記述
タスクは特別な記述などは必要なく、単純に/src
をgulp.dest()
するという感じでgulpfile.js
に下記のように記述します。
var gulp = require( 'gulp' ),
ejs = require( 'gulp-ejs' );
gulp.task('ejs', function() {
return gulp.src(['src/ejs/**/*.ejs', '!src/ejs/**/_*.ejs'])
.pipe(ejs({}, {}, {ext: '.html'}))
.pipe(gulp.dest('dist'));
});
EJSへの記述
まず、各index.ejs
に共通ファイルとして読み込む/src/templates/_nav.ejs
をインクルードさせ、その際include
には引数として後ほど相対パスとして利用するパスを記述しておきます。
今回のサンプルの場合はそれぞれ下記のようになります。
<%-
include('./templates/_nav', {
path: './'
});
%>
<%-
include('../templates/_nav', {
path: '../'
});
%>
次にインクルードするように指定した_nav.ejs
の作成で、今回はファイル名にもあるようにナビゲーションが記述されたファイルと想定してベースとなるHTMLとしては下記のようなものを使用します。
<nav>
<a href="/">home</a>
<a href="/page/">page</a>
</nav>
ベースHTMLにあるa
要素のhref
にはどちらもルート相対パスで指定されていますが、このパス部分を下記のように頭にある/
を<%= path; %>
に変更し、こうすることで先ほどインクルード時に引数として記述したものがここに出力されます。
<nav>
<a href="<%= path; %>">home</a>
<a href="<%= path; %>page/">page</a>
</nav>
あとは$ gulp ejs
で/src
の並列に出力される/dist
の中にあるHTMLを確認すると、同じファイルをインクルートさせていても下記のようにそれぞれ異なる形で相対パスが設定されているのを確認できます。
<nav>
<a href="./">home</a>
<a href="./page/">page</a>
</nav>
<nav>
<a href="../">home</a>
<a href="../page/">page</a>
</nav>
インクルードの引数を利用しない
こちらは先ほどとは違って、インクルード時の引数は使用せずにファイルパスを取得して処理を加えることで相対パスを設定するというものです。
プラグインのインストール
理由は後述しますが、こちらの方法はファイルパスを取得するために「gulp-data」を使用するので、まず下記コマンドでプラグインをインストールします。
$ npm i -D gulp-data
タスクの記述
タスクはgulpfile.js
に下記のように記述し、こちらの場合はEJSの処理の他に「gulp-data」の読み込みと処理を追加します。
var gulp = require( 'gulp' ),
ejs = require( 'gulp-ejs' ),
data = require( 'gulp-data' );
gulp.task('ejs', function() {
return gulp.src(['src/ejs/**/*.ejs', '!src/ejs/**/_*.ejs'])
.pipe(data(function(file) {
return { 'filename': file.path }
}))
.pipe(ejs({}, {}, {ext: '.html'}))
.pipe(gulp.dest('dist'));
});
EJSへの記述
まず、各index.ejs
に共通ファイルとして読み込む/src/templates/_nav.ejs
をインクルードさせ、今回のサンプルの場合はそれぞれ下記のようになります。
<% include ./templates/_nav %>
<% include ../templates/_nav %>
次にインクルードするように指定した_nav.ejs
の作成で、今回はファイル名にもあるようにナビゲーションが記述されたファイルと想定してベースとなるHTMLとしては下記のようなものを使用します。
<nav>
<a href="/">home</a>
<a href="/page/">page</a>
</nav>
ベースHTMLにあるa
要素のhref
にはどちらもルート相対パスで指定されていますが、このパス部分を相対パスになるようにするために_nav.ejs
は下記のような記述をします。
<%
path = function(fileName) {
var depth = filename.replace(/\\/g, '/').split('src/ejs')[1].split('/').length - 2;
var path = depth > 0 ? '../'.repeat(depth) : './';
if ( fileName !== undefined ) {
path += fileName;
}
return path;
};
-%>
<nav>
<a href="<%= path(); %>">home</a>
<a href="<%= path('page/'); %>">page</a>
</nav>
コード上部は相対パスを出力するための処理を行っており、ファイルパスを取得する際に以前(v2.3.0など)は<%= filename %>
で取得できたのが現在(v3.0.1)は取得できなくなっているために、ここで「gulp-data」を使って取得したファイルパスを利用します。
行っている処理の内容としては取得したパスを任意の部分(このサンプルの場合は'src/ejs'
)で分割してから階層を調べ、その数に応じて相対パスを出力するといったものになります。
パスを出力させたい部分には<%= path(); %>
といった形で記述し、単純に記述した場合は./
や../
などが出力されますが、例えば<%= path('page/'); %>
のように引数を付けて記述した場合は./page
や../page/
などのように、ディレクトリ名やファイル名付きで出力させることができます。(<%= path(); %>page/
のような形でも可)
あとは$ gulp ejs
で/src
の並列に出力される/dist
の中にあるHTMLを確認すると、同じファイルをインクルートさせていても下記のようにそれぞれ異なる形で相対パスが設定されているのを確認できます。
<nav>
<a href="./">home</a>
<a href="./page/">page</a>
</nav>
<nav>
<a href="../">home</a>
<a href="../page/">page</a>
</nav>