EJSとJSONファイルを使ってパンくずリストをパーツ化する

##はじめに
テンプレートエンジン等を使って制作している場合は、作業量とミスを減らすためにも、なるべくパーツ化しておきたいです。

今回はEJSとJSONファイルを使って、2つのパンくずリストをパーツ化する方法をまとめました。

* HTMLパンくずリスト
* JSON-LD を使用したパンくずリスト

このようなディレクトリ構造のHTMLを作成する場合を考えてみます。

| 第1階層 | 第2階層 | 第3階層 | ディレクトリ |
----|----|----|----|
| トップ | | | / |
| | アバウト | | /about/ |
| | | メッセージ | /about/message/ |

尚、gulpの導入、ejsの構文、パンくずリスト等について説明を入れると話が広がりすぎるので、ここでは必要なファイルの書き方までに留めます。あとは案件に合わせて`gulpfile.js`、`jsonファイル`、`index.ejsのinclude()関数`を調整すれば、`_breadcrumb.ejs`、`_structured-data.ejs`はおそらくそのまま使用できると思います。スタイルの調整は適宜行ってください。

##パンくずリストについて
細かな説明は省きますが、以下のようなものを作ります。
###HTMLパンくずリスト
ウェブサイト内に階層順にリストアップされた、一般的なパンくずリストです。
[Googleのパンくずリストの制作例](https://developers.google.com/search/docs/data-types/breadcrumb?hl=ja#html_example)に習い、`<ol>`を用いて作成します。
###JSON-LD を使用したパンくずリスト
マークアップできる構造化データの形式は、基本的に`JSON-LD`、`microdata`、`RDFa`の3つがありますが、中でもGoogleは[JSON-LDを推奨](https://developers.google.com/search/docs/guides/intro-structured-data#%E6%A7%8B%E9%80%A0%E5%8C%96%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%BD%A2%E5%BC%8F)しています。


##ファイル一覧
最終的には、以下のようになります。
>gulpfile.js
htdocs/
├ develop/
│　　└ json
│　　　　└ breadcrumb.json
│　　└ ejs
│　　　　└ _breadcrumb.ejs
│　　　　└ _structured-data.ejs
│　　　　└ index.ejs
│　　　　└ about/
│　　　　　　└ index.ejs
│　　　　　　└ message/
│　　　　　　　　└ index.ejs
├ public/
│　　└ index.html
│　　└ about/
│　　　　└ index.html
│　　　　└ message/
│　　　　　　└ index.html

##gulpfile.jsとdevelopディレクトリの各ファイル作成
前項のファイル一覧の順番に、ひとつずつファイルの作り方をみていきます。

###1. gulpfile.js
*gulpバージョン 3.9.1*

```ruby:gulp
const gulp = require('gulp'),
  ejs = require('gulp-ejs'),
  watch = require('gulp-watch'),
  fs = require('fs');

const json = JSON.parse(fs.readFileSync('htdocs/develop/json/breadcrumb.json', 'utf8'));

gulp.task('ejs', function () {
  return gulp.src([
    'htdocs/develop/ejs/**/*.ejs',
    '!' + 'htdocs/develop/ejs/**/_*.ejs'
  ])
  .pipe(ejs({
    'breadcrumb': json
  }, {}, {
    ext: '.html'
  }))
  .pipe(gulp.dest('htdocs/public/'));
});

gulp.task('default', ['ejs', 'watch']);

gulp.task('watch', function () {
  watch('htdocs/develop/ejs/**/*.ejs', function () {
    gulp.start('ejs');
  });
});
```

###2. JSONファイル
```ruby:_breadcrumb.json
{
  "top": {
    "text": [
      "HOME"
    ],
    "directory": [
      ""
    ],
    "url": [
      "https://example.com/"
    ]
  },
  "about": {
    "text": [
      "HOME",
      "会社紹介"
    ],
    "directory": [
      "/",
      ""
    ],
    "url": [
      "https://example.com/about/"
    ]
  },
  "message": {
    "text": [
      "HOME",
      "会社紹介",
      "メッセージ"
    ],
    "directory": [
      "/",
      "/about/",
      ""
    ],
    "url": [
      "https://example.com/about/",
      "https://example.com/about/message/"
    ]
  }
}
```
###3. _breadcrumb.ejs
```ruby:_breadcrumb.ejs
<%_ if (Object.keys(breadcrumb[page].text).length > 0) { _%>
<ol>
  <%_ for (var i = 0; i < Object.keys(breadcrumb[page].text).length; i++) { _%>
  <%_ if (i + 1 === Object.keys(breadcrumb[page].text).length) { _%>
  <li>
    <span><%- breadcrumb[page].text[i] %></span>
  </li>
  <%_ } else { _%>
  <li>
    <a href="<%- breadcrumb[page].directory[i] %>"><%- breadcrumb[page].text[i] %></a>
  </li>
  <%_ } _%>
  <%_ } _%>
</ol>
<%_ } _%>
```
###4. _structured-data.ejs
```ruby:_structured-data.ejs
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": "HOME",
    "item": "<%- breadcrumb['top'].url %>"
  <%_ if ( page !== 'top' ) { _%>
  <%_ if ( Object.keys(breadcrumb[page].text).length > 0 ) { _%>
  <%_ for (var i = 1; i < Object.keys(breadcrumb[page].text).length; i++) { _%>
  },{
    "@type": "ListItem",
    "position": <%- i + 1 %>,
    "name": "<%- breadcrumb[page].text[i] %>",
    "item": "<%- breadcrumb[page].url[i-1] %>"
  <%_ } _%>
  <%_ } _%>
  <%_ } _%>
  }]
}
</script>
```

###5. index.ejs
```ruby:index.ejs
<!doctype html>
<html lang="ja">
<head>
<%- include('./_structured-data', {page: 'top'}) %>
</head>
<body>
<main>
<%- include('./_breadcrumb', {page: 'top'}) -%>
</main>
</body>
</html>
```

###6. about/index.ejs
```ruby:about/index.ejs
<!doctype html>
<html lang="ja">
<head>
<%- include('../_structured-data', {page: 'about'}) %>
</head>
<body>
<main>
<%- include('../_breadcrumb', {page: 'about'}) -%>
</main>
</body>
</html>
```

###7. message/index.ejs
```ruby:message/index.ejs
<!doctype html>
<html lang="ja">
<head>
<%- include('../../_structured-data', {page: 'message'}) %>
</head>
<body>
<main>
<%- include('../../_breadcrumb', {page: 'message'}) -%>
</main>
</body>
</html>
```
##publicディレクトリに出力されたファイル
###1. index.html
```ruby:index.html
<!doctype html>
<html lang="ja">
<head>
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": "HOME",
    "item": "https://example.com/"
  }]
}
</script>
</head>
<body>
<main>
<ol>
  <li>
    <span>HOME</span>
  </li>
</ol>
</main>
</body>
</html>
```

###2. about/index.html
```ruby:about/index.html
<!doctype html>
<html lang="ja">
<head>
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": "HOME",
    "item": "https://example.com/"
  },{
    "@type": "ListItem",
    "position": 2,
    "name": "会社紹介",
    "item": "https://example.com/about/"
  }]
}
</script>
</head>
<body>
<main>
<ol>
  <li>
    <a href="/">HOME</a>
  </li>
  <li>
    <span>会社紹介</span>
  </li>
</ol>
</main>
</body>
</html>
```

###3. message/index.html
```ruby:message/index.html
<!doctype html>
<html lang="ja">
<head>
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": "HOME",
    "item": "https://example.com/"
  },{
    "@type": "ListItem",
    "position": 2,
    "name": "会社紹介",
    "item": "https://example.com/about/"
  },{
    "@type": "ListItem",
    "position": 3,
    "name": "メッセージ",
    "item": "https://example.com/about/message/"
  }]
}
</script>
</head>
<body>
<main>
<ol>
  <li>
    <a href="/">HOME</a>
  </li>
  <li>
    <a href="/about/">会社紹介</a>
  </li>
  <li>
    <span>メッセージ</span>
  </li>
</ol>
</main>
</body>
</html>
```
今回はこのように作成しましたが、EJS + JSONファイルを使った書き方でも、こんな書き方もあるよ！とかあれば、是非コメントください。

また、他のテンプレートエンジンだとこんなふうに作れちゃうよ、とかも是非！