なぜ、私がウェブアプリ開発にWeb Componentsを採用したのか

# 開発したウェブアプリの紹介
　先日、[LEADYOU](https://leadyou.hacknock.com)というサービス名でREADME Generatorを友人（ @Kyome ）と開発しリリースしました。このサービスは、READMEに書く内容に迷わないようにREADMEのフォーマットを提案し、開発者がREADMEを作成したい自身の公開リポジトリのURLを入力することで、自動的にBadgesやContributersなどの情報を取得し、いい感じにREADMEを作る手助けをしてくれるというサービスです。LEADYOUについては、『[GitHubのREADMEをサクッと高品質で書けるサービス作ってみました。
](https://qiita.com/Kyome/items/2112e9d1871ec0a367ea)』で紹介されていますので、興味のある方はご覧ください。

# Web Componentsとは
　Web Componentsについては、今回説明を省きますが、以下の記事が参考になると思います。一言で言うと、繰り返し使う要素については、custom elementという独自の要素を定義して使い回そうという仕組みです。

* [Web Components](https://developer.mozilla.org/ja/docs/Web/Web_Components)
* [カスタム要素 v1: 再利用可能なウェブ コンポーネント](https://developers.google.com/web/fundamentals/web-components/customelements?hl=ja)
* [Using custom elements](https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_custom_elements)

# フロントエンド描画の仕組み
　フロントエンドを構成するディレクトリ構造は以下になります。以下に示すのは、変更可能なファイルのみであり、他にcustom-elementを流し込む枠のようなHTMLファイルが存在します。template.json以外はJavaScriptで記述されています。

```:ディレクトリ構造
readme-generator-plugins/
　├ custom-scripts/
　├ template.json
　├ custom-elements/
　　└ wrap-multiline-field.js
　　└ wrap-oneline-field.js
　　└ ...（作りたいレイアウトの分だけファイル）
```

　それぞれのファイルには役割があります。それを以下に示します。

* custom-element：各入力項目のフォームのレイアウトやDOM操作を行います。
* template.json：各入力項目のタイトルや説明文、placeholderといったユーザーに提示する文字や、入力の長さなど、入力についてのルールを設定します。
* custom-script：Project NameやBadgesなど、ユーザーにフォームで提示するべき値を取得するものです。

　これらをnode.jsを経由してroutingし、描画することでフォームの動的な生成が可能となっています。node.jsのコードは基本的に書き換えることなく、これら今紹介したファイルを編集したり追加または削除することでフォームの修正ができます。

![README-Generator-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81253/02e75575-f700-4663-96a3-c72e579fe8da.png)

# Web Componentsを採用した理由
　Web Componentsと類似のことができるフレームワークにReactがあります。しかし、環境導入が必要であり、全ての人が等しく同じ環境を整えるのが困難です。一方で、Web ComponentsはWebの標準技術であるため、特別な環境導入は不要で、JavaScriptを記述するだけでcustom elementが作成できます。作成したcustom elementの動作確認は、作成したcustom elementをブラウザで読み込むだけです。このように、これから多くの人が編集するかもしれない可能性を考えると、開発者の開発者環境によらず開発が出来ることに大きな利点を感じWeb Componentsを採用しました。
　タイトルの答えは、以上になるのですが、以下に今回作ったcustom-elementとtemplate.jsonがやっていることを解説しているので、興味のある方は読んでください。

# custom-elementのやっていること
 custom-elementは何をやっているかというと、1つの入力項目に必要なelementを定義してレイアウトを作成することと、template.jsonで定義された値をどこに入れるかを定義しています。
　例えば、実際の例だと、Project Nameにはwrap-oneline-fieldが使われています。Short Descriptionにはwrap-multiline-fieldというcustom-elementが使われています。wrap-oneline-fieldを例に説明すると、以下のようにtemplate.jsonの値がwrap-oneline-fieldというcustom-elementに挿入されます。

![wrap-oneline-field.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81253/b033601a-1b60-d581-9fd8-c8318293e723.png)

 この枠を一度用意しておけば、これを使い回すことが可能です。[LEADYOU](https://leadyou.hacknock.com)ではProject Name、Badges、Tags、ContributorsでUserswrap-oneline-fieldを用いています。これらの順番や書くDOMに入れるテキストを定義しているのが、次に説明するtemplate.jsonです。

# template.jsonがやっていること
 template.jsonは、入力項目は何か、その入力項目にどのcustom-elementを使うか、使ったcustom-elementの詳細な設定（例えば、文字数や複数項目の入力を可能にするか、タイトルを表示するか否かなど）を行います。一例を以下に示します。

```json:template.json
   {
      "title": "Project Name",
      "hiddenTitle": false,
      "required": true,
      "replacement": true,
      "multiple": false,
      "component": "wrap-oneline-field",
      "description": "Please type the project name.",
      "kindsOfValues": ["plain"],
      "formats": ["%s"],
      "attributes": {
        "placeholder": "Your project/repository name",
        "maxlength": 50
      },
      "script": "getProjectName.js"
    }, 
    {
      "title": "追加したい項目名",
    }, ...
```

　Project Nameの部分だけを抜粋しました。項目を増やしたい場合は、一番上位の{}を増やします。例として `"title":"追加したい項目名"`　を入れています。少し中身について説明すると、componentは用いるcustom-elementを指定します、今回は先ほど説明したwrap-oneline-fieldを用いています。kindsOfValuesは、どのようなデータ型を入力データとして受け付けるかを示しています。今回はplain textを入力として受け付けたいので、plainと設定しています。attributesの中には、表示する際に用いられる属性が割り当てられています。placeholderはその名の通り、フォームが表示された時にplaceholderに表示される文字を定義しており、maxlengthは入力できる最大文字数を示しています。
　このように、jsonにデータを追加していくだけでフォームの入力項目が増やせ、設定項目を変更するだけで自在にフォームの性質を変えることができます。ちなみにですが、一つ一つの入力項目のレイアウトはcustom-element内にあるstyleで変更が可能です。

# まとめ
　以上のように、custom-elementを定義し、入力して欲しい項目をtempale.jsonに書き加えるだけでformが生成されるという仕組みを実現しました。この方法を用いることで、custom-elementを一度定義すれば**１つの入力フォームのテンプレートをcustom-elementに作成するだけで、複数の入力項目に使いまわせる**だけでなく、入力項目を追加したり削除するための**設定用のjsonファイルを書き換えるだけで、入力項目の設定が可能**となり、この仕組みがデフォルトのWebの技術で成り立っているため、**特別な環境導入をしなくてもcustom-elementと設定用のjsonファイルをGitHubに公開するだけで、誰でもpull requestを送ったりforkしたりして提案、開発が可能となる**仕組みが実現したのです。

# お問い合わせやご意見など
　何かお問い合わせやご意見等ございましたら、本記事のコメント欄にコメントいただくか、以下のメールアドレスまでメールください。長文ですが、最後まで読んでいただきありがとうございます。

akira.kashihara [at] hotmail.com
（[at]を@に変えてください）

# 参考など
1) [LEADYOU README Generator](https://leadyou.hacknock.com)
2) [readme-generator-plugins](https://github.com/Hacknock/readme-generator-plugins)
3) [Web Components](https://developer.mozilla.org/ja/docs/Web/Web_Components)
4) [カスタム要素 v1: 再利用可能なウェブ コンポーネント](https://developers.google.com/web/fundamentals/web-components/customelements?hl=ja)
5) [Using custom elements](https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_custom_elements)


custom-elementについてのノウハウは、後日書こうと思いますが、今まで書いている備忘録的なものは以下になります。
6) [とりあえずCustom elementsを作りたい](https://qiita.com/AkiraKashihara/items/31ab1c5ab401d3b66231)
7) [Custom Elementsの属性を変化させた時に、その描画が変化しない](https://qiita.com/AkiraKashihara/items/9aba074f3ece4bb5b94d)