Edited at

EJSでルートへのパス(相対、絶対)を取得して変数化する

※ 2019年5月19日 EJSで<%= filename %>でパスの取得ができなくなっているので、gulp-dataを使って、gulpfile.js内で取得する方法に変更しました。

EJSではインクルードするパスを相対パスで指定する必要があります。設定ミスを防ぐために、メタタグ内のURLなども自動化したいところです。

開発環境はmacOS High Sierra 10.13.6、Node.js 9.4.0、gulp-ejs 4.0.0で確認しています。


gulpfile

const ejs = require('gulp-ejs');

const fs = require('fs');
const data = require('gulp-data');
const rename = require('gulp-rename');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');

/**
* 開発用ディレクトリ
*/

const src = {
root: 'src/',
ejs: ['src/**/*.ejs', '!src/**/_*.ejs'],
data: 'src/_data/',
};

/**
* テスト用ディレクトリ
*/

const dest = {
root: 'htdocs/',
};

/**
* EJSをHTMLにコンパイルします。
*/

gulp.task('ejs', () => {
return gulp
.src(src.ejs)
.pipe(
data(file => {
const absolutePath = `/${file.path
.split(src.root)
[file.path.split(src.root).length - 1].replace('.ejs', '.html')
.replace(/index\.html$/, '')}`;
const relativePath = '../'.repeat([absolutePath.split('/').length - 2]);
return {
absolutePath,
relativePath,
};
}),
)
.pipe(
ejs({
site: JSON.parse(fs.readFileSync(`${src.data}site.json`)),
}),
)
.pipe(rename({ extname: '.html' }))
.pipe(plumber({ errorHandler: notify.onError('Error: <%= error.message %>') }))
.pipe(gulp.dest(dest.root));
});


site変数

サイト共通で使う変数を/src/_data/site.jsonに定義します。この変数はgulpfile.jsを介して、すべてのEJSファイル内でsite.nameのように呼び出すことができます。

{

"name": "Site Title",
"description": "Site Description",
"keywords": "Site Keyword1, Site Keyword2",
"rootUrl": "http://example.com",
"ogpImage": "http://example.com/ogp-image.jpg",
"facebookAdmins": "",
"facebookAppId": "",
"twitterCard": "summary_large_image",
"twitterSite": "@SiteAccount"
}

製品リストのような別の変数を定義したい場合は、jsonファイル(/src/_data/products.json)を作成して、gulpfile.jsで以下のように読み込んでください。

// 変更前

.pipe(
ejs(
{
site: JSON.parse(fs.readFileSync(`${src.data}site.json`)),
},
{},
{ ext: '.html' },
),
)

<%= products.items %>のように呼び出すことができます。

// 変更後

.pipe(
ejs(
{
site: JSON.parse(fs.readFileSync(`${src.data}site.json`)),
products: JSON.parse(fs.readFileSync(`${src.data}products.json`)),
},
{},
{ ext: '.html' },
),
)


absolutePathrelativePath

gulpfile.jsでfsパッケージを使用して、そのページのルート相対パスをabsolutePathに、ルートまでの相対パスをrelativePathに格納しています。この変数は、すべてのEJSファイル内で<%= absolutePath %>のように呼び出せます。


index.htmlは削除され、以下のように出力されます。



  • /index.ejsで使用した場合



    • <%= absolutePath %> => /


    • <%= relativePath %> => 出力なし




  • /products/index.ejsで使用した場合



    • <%= absolutePath %> => /products/


    • <%= relativePath %> => ../




  • /products/product.ejsで使用した場合



    • <%= absolutePath %> => /products/product.html


    • <%= relativePath %> => ../



site.rootUrlと組み合わせることで、ドメインを含んだ絶対パスを出力することもできます。

<%= site.rootUrl %><%= absolutePath %>


メタタグの自動出力

共通のデータやルート相対パスなどは出力できるようになったので、メタタグも自動で生成することができます。

例えば、以下のようにindex.ejsを作成します。include()の第二引数にpage変数を渡して、ページごとの設定をインクルード先(src/_partial/_head.ejs)で使えるようにしておきます。

<%

var page = {
title: "",
description: "",
ogpType: "website",
ogpImage: "",
// Do not change.
absolutePath: absolutePath,
relativePath: relativePath
};
-%>
<%- include(page.relativePath + '_partial/_head', {page: page}); %>

_head.ejsでは以下のように、page.titleを設定していればページタイトルとサイトタイトルを、page.titleがなければサイトタイトルを生成のように、テンプレートを作れます。

<% if(page.title) { %><title><%= page.title %> | <%= site.name %></title><% } else { %><title><%= site.name %></title><% } %>