GitHubを活用して、クライアントと協働してWebサイトをAngularでつくろう。

この記事は[Angular Advent Calendar 2018](https://qiita.com/advent-calendar/2018/angular)の6日目の記事です。

# 概要
- GitHubもCMSだよね
- クライアントがGitHub上で修正したらもっと幸せな世界が待ってる
- リスク管理や速度の部分はAngularのAOTビルドが担ってくれるよ
- Webサイト構築でこそ、Angularを使おう

# CMSに代わるGitHubという見方
CMSって皆さん利用されていますか？Contents Management System、簡単にいうと動的に入出力できるシステムで国内で最も活用されているWordPressもそのひとつです。
ちなみに、よく聞く「導入する理由」は「クライアントが更新できるから」。

ちなみに、CMSがない世界だと受託業務の業務負担はこんな感じです。

![スクリーンショット 2018-12-06 12.54.12.png](https://qiita-image-store.s3.amazonaws.com/0/100460/5b4cff70-ffdc-8ebc-99a7-6c4f43c0e996.png)

まぁ今だと修正依頼はメールがメインだと思いますが、せっかくクライアントが文面をデータ入力してくれても（もうFAXで修正依頼くる世界は滅んだはず！）、Web制作会社はそれをHTMLに挿入または差し替えるという仕事が発生します。
保守されるWebサイトほど、クライアントの仕事量はそのままWeb制作会社の仕事量へと直結します。

それを変えてくれたのが、WordPressをはじめとしたCMS。

![スクリーンショット 2018-12-06 12.54.22.png](https://qiita-image-store.s3.amazonaws.com/0/100460/06c6780f-1aa7-9544-1284-51057a1b48b9.png)

Webサイトのタイトルから、文面まで、「クライアントが更新できる部分」を用意することで、タスクをクライアントとWeb制作会社が分け合えるようになりました。

めでたしめでたし。

---

とならないのが、Webの世界です。
具体的にいうと、ここで「カスタムフィールド職人」が生まれました。ブログの本文などはそのまま全部クライアントがさわってくれたらいいのですが、会社情報や細かいデザイン・レイアウトで組まれた本文をクライアントにさわってもらおうとするために、1ページあたりのカスタムフィールドが10個20個になってしまい、Web制作者の中には「私はWebサイトをつくるのが仕事なのか、カスタムフィールド製造業をしてるのかよくわからない」と嘆く人が生まれるまでになりました。

本来、作業を分担して楽になるはずなのに、あれ・・・？

## GitHubというCMS
GitHubを、GitのWebサービスと捉えるか、CMSととらえるかによるのですが、GitHubにはCMS的役割があります。そうです、Web上で編集・更新ができます。かつユーザ別に、しかも承認機能（プルリク）までついてる！

![スクリーンショット 2018-12-06 13.03.18.png](https://qiita-image-store.s3.amazonaws.com/0/100460/fab05e9d-9594-755b-eb8d-4f92cf4fc1ef.png)

誰がどれだけ更新したか、バージョン管理まで完璧にこなしてくれます。CMS的機能がついてるというか、GitHubがCMSでは。

見方を変えると、

- 直接ホスティングしているサーバをさわることなく
- つまりはクライアントがFTPやSFTPをつかって直接HTMLをさわることなく
- Webサイトのソースコードをさわることができる

という画期的なシステムなのです。GitHubすごい！

# クライアントはHTMLをさわれない？なら、Angularだ。
こういう話をすると「クライアントが直接HTMLをさわるのはハードルが高い」という声をよく聞きます。もう平成も終わるのに、HTML上のテキストも編集できないクライアントさんはどれだけいるの？という意見もありますが、まぁわかります。特にクライアントさんによっては「何かあって、Webサイトを壊してしまっては・・・」とリスク面をおっしゃる方が多いです。

そこで、でてくるのがJavaScriptフレームワークのAngularです。

## 1. コンテンツは別ファイルにまとめよう
クライアントさんが怖いのは、こういうHTML内で必要な部分だけを抜き出してさわることです。

![スクリーンショット 2018-12-06 13.09.27.png](https://qiita-image-store.s3.amazonaws.com/0/100460/00a44732-cdd2-2923-7342-946c766e9500.png)

具体的にいうと、全体に占める日本語の割合がよくて10%程度というか。Web制作をしてる私たちはざっと読めてしまいますが、HTMLに慣れてない方だと日本語だけを探し出すのがまず大変らしいです。まぁ、私もシェイクスピアの原書に10%は日本語だけだから、そこを読めといわれるとハードルが高い。

なので、コンテンツ更新の必要があるところだけを抜き出しましょう。そして、専用のフォルダ・ファイルをつくって保存しましょう。

![スクリーンショット 2018-12-06 13.12.11.png](https://qiita-image-store.s3.amazonaws.com/0/100460/7077458f-a75f-6d2f-dcc2-0ee2004e65a2.png)

ちなみにこのスクリーンキャプチャした画面だけで、10のフィールドがあります。これをひとつひとつカスタムフィールド職人してると保守も管理も大変。でも、GitHubとAngularがあれば大丈夫。

このオブジェクトを `export` で他ファイルから呼び出せるようにして、使うページで `import` するしてバインディングするだけです。

```ts
import { WritingText } from '../../writing/home';
@Component(...)
export class HomePage implements OnInit, OnDestroy {
writing = WritingText;
```

改行には `<br />` が必要？

```ts
export const txt = `改行を
    反映させる`;
```

として、`innerText`でバインディングすれば改行は直接反映します。

簡単ですね。

## 2. 複雑なオブジェクトには型で対応しよう
といっても、複雑なオブジェクトを用意しないといけない場合もあります。そういう場合はTypeScriptの型をちゃんと用意しましょう。例えばこんな感じです。

```ts
export interface ISchool {
  public: boolean;
  name: string;
  org: string;
  email: string;
  fragment: string;
  description: string;
  option: string;
  challengeBooks: boolean;
  overview: {
    description: string;
    term: string;
    price: string;
    condition: string;
    capacity?: string;
    option: string[];
  };
  schedule: {
    name: string;
    schoolId: number;
    term: {
      label: string;
      line: {
        period: string;
        content: string;
        active?: boolean;
      }[];
    }[];
  }[];
  curriculum: {
    process: {
      name: string;
      description: string;
    }[];
    option: string[];
  };
  curriculumGroup: {
    description: string;
    process: {
      name: string;
      description: string;
    }[];
  };
  curriculumJob: {
    description: string;
    process: {
      name: string;
      description: string;
    }[];
  };
  lecturer: {
    name: string;
    image: string;
    title: string;
    messageLink?: string;
  }[];
  question?: string[];
  discount?: {
    name: string;
    price: number;
    type: string;
    description: string;
    option: string[];
    label?: string;
    labelOption?: string;
  }[];
}
```

## 3. 更新失敗したらビルドに失敗するから安心
なぜ型を用意するかなのですが、ビルドに失敗するためです。クライアントさんがさわるのはローカルにDLしてきて静的解析がされている場ではなく、ただテキストを編集するGitHub上なのです。

なので、`,`を間違って消してしまった、閉じタグが抜けてる、キーを一文字消してしまった、一行まるまる消したことに気づかなかったなど、ミスを考えだしたらきりはありません。

けどですね、Angularで型を用意して、AOTビルドしてる限り、そういったミスによってWebサイトが表示されなくなったり、デザインが崩れたりすることはありません。
だって、ビルドに失敗しますもの。

これは最大のメリットだと思ってまして、 `export` で他ファイルからオブジェクトを読み込んでくるのはどういった環境でもさほど難しくありませんが、ビルドにちゃんと失敗してくれるのはHTMLのDOMを
構文解析してくれたり、TypeScriptを採用してるAngularの特徴です。
閉じタグひとつ忘れただけでもビルドに失敗してくれるので、クライアントがライティング部分を直接さわって壊れることはありえません。安心してクライアントにタスクを振ってください。

## 4. パフォーマンスはどうなの？
`ajax` `HTTPクライアント` など外部コンテンツとしてとってきたら当然遅延しますが、ビルドしてるので内部コンテンツとして遅延なく表示してくれます。AOTコンパイルを信じよう。（ざっと流し読みした感じ、jsonとしてComponents側に保持してくれてる模様）

## 5. 実際どうだった
この手法で https://www.ppp-ps.net/ をリリースしました。文面の9割はクライアントがさわることができるようになっていて、コミット履歴をみてみると大学事務局の方もコミットしてくださってます。リリースしたばかりなのでさほどHTMLがわからない人のコミット数はさほどありませんが、それでも合計24commits、200行+、180行-ぐらいの変更がすでに行われています。なお、commitの失敗も度々ある模様。

![スクリーンショット 2018-12-06 13.39.26.png](https://qiita-image-store.s3.amazonaws.com/0/100460/bc56b220-4c98-4444-c721-d25cd865b4b6.png)

commitに成功してたら5分後ぐらいにビルド終了して反映されるので、クライアント自身が「反映されない。ミスったか」と更に修正した箇所もあります。

# まとめ
WebアプリケーションでこそJavaScriptフレームワークをつくろうといった意見や、AngularはWebサイト構築ではオーバースペックという意見もありますが、こういったクライアント協働型では力を発揮します。

それでは、また。