Angular6 で俺式 KOAN スタック Webアプリを構築する、ほぼ全手順（1）

## 概要
Angular6で「俺式 KOAN スタック」で Web アプリ構築するための個人的な備忘録記事。
概要については「[こちら](https://qiita.com/tomy0610/items/9e948154f9b8f56f28cf)」を参照。
今回は、Angular6 でのフロントエンド構築と Koa でのバックエンド構築を行い、簡単なクラサバ通信を行う。

## フロントエンドを作成

### 1．新規の Angular プロジェクト生成

適当な場所でディレクトリを作成し、以下のコマンドを実行。
※ 今回は、スタイルは CSS (デフォルト) ではなく SCSS を指定してみる。
※ オプション指定が気になる人は `--style=scss` を省略して実行すればOK。

```
ng new demo-app --routing --style=scss
```

`ng new` の後 (`demo-app` の部分) に、任意のプロジェクト名を指定する。
結果、以下の様な感じでコードが生成されるはず。

```bash:プロジェクト生成結果
demo-app
  ├─ e2e/ # E2E テスト用
  ├─ node_modules/ # ダウンロードされた関連ライブラリ群（削除可）
  ├─ src/ # メインとなるソースコード
  ├─ .editorconfig # エディタの設定ファイル
  ├─ .gitignore # Git によるバージョン管理 対象外設定
  ├─ angular.json # Angular 設定ファイル
  ├─ package-lock.json # 依存モジュールから、更にネストした依存関係を記録したファイル
  ├─ package.json # アプリのパッケージ情報や依存関係を記録したファイル
  ├─ README.md # アプリの概要を記載した添付文書
  ├─ tsconfig.json # TS → JS トランスパイル設定ファイル
  └─ tslint.json # 構文チェック設定ファイル
```

ちなみに、ルートディレクトリ (例だと、一番上の `demo-app`) は、出来上がった後に別の名前に変えても問題ない。

### 2．受付ポートを変更

アプリ起動時のポート番号をデフォルト (4200) ではなく、あとで任意のポートで動作確認やテストができる様に、別の適当なポート番号に変更しておく。
変更方法は、以下のとおり。

##### angular.json
ポート設定を追記する。データ構造的には、 `projects.プロジェクト名.architect.serve` にのオプションにポート設定を追加する

```json-doc:angular.json
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "demo-app": {
      ：
      "architect": {
        ：
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "demo-app:build", // カンマだけ追加
            "port": 3000 // １行追加
          },
          "configurations": {
            "production": {
              "browserTarget": "demo-app:build:production"
            }
          }
        },
        ：
      }
    },
    ：
```

##### protractor.js
テスト時のURLのポート番号を変更する

```js:e2e/protractor.js
...
  baseUrl: 'http://localhost:3000', // 4200 から修正
...
```

### 3．いったん起動確認

ここまでで、いったん Web アプリの起動を確認しておく。

起動コマンドを実行 (`--open` オプションで、アプリ起動したら勝手にブラウザ開くようにしてみる)

```bash
ng serve --open
```

`http://localhost:3000/` で Web ブラウザから以下の画面が表示されたら成功

<img width="1403" alt="Angular起動確認.png" src="https://qiita-image-store.s3.amazonaws.com/0/199602/97671010-3876-dfd5-bacd-c31084911143.png">

`Ctrl + C` でアプリを止めて次へ。

### 4．ビルド時のディレクトリ名を変更

今のままだと、`ng build` した時に、デフォルトのままだとビルド時に dist ディレクトリの配下に「`プロジェクト名`」の名前でソース群が生成される。
後でバックエンドまで全て用意した時に、ディレクトリが `client`, `server` で生成されるようにするため、ビルド時のディレクトリ名を `client` に変更しておく。（実際は他の名前でもいい。わかれば何でもいい）

#### 変更箇所

- ルートディレクトリ配下の `src` というディレクトリ名を `client` に変更
- angular.json を以下のとおりに修正
 - まず、`dist/プロジェクト名` → `dist/client` に文字列を置換
 - その後、`src` → `client` に全文字列を置換

#### ちゃんと動くか確認

以下のコマンドが問題なく成功するか確かめればOK。
ここをサボると後で支障出るので忘れずに。

- `ng lint`
 - `All files pass linting.` など成功メッセージが出ればOK
- `ng build`
 - `dist/client` ディレクトリがルートに自動生成され、中身があればOK
- `ng serve`
 - Web ブラウザから `http://localhost:3000/` にアクセスして表示されれば成功
- `ng test`
 - `TOTAL: 4 SUCCESS` など成功メッセージが出ればOK
- `ng e2e`
 - `Executed 1 of 1 spec SUCCESS in 0.626 sec.` など成功メッセージが出ればOK
 - ネットワークが繋がっていないと失敗する場合があるので、その時はスキップして良い

## バックエンドを作成

### 1．必要な関連モジュールをインストール

今回は Koa という Web フレームワークと、必要な Koa の関連モジュールを使用する。

```bash
# Koa モジュール群
npm install koa koa-static koa-router koa-bodyparser

# 型定義モジュール
npm install @types/koa @types/koa-static @types/koa-router @types/koa-bodyparser
```

- Koa： Web　フレームワークのコアモジュール
- Koa Static： Angular で生成した HTTP リソースと Koa をいい感じに紐付けるのに必要
- Koa Router： 画面遷移のルーティング機能を提供する
- Koa Bodyparser： 後々、クラサバ通信で JSON でPOST通信とかするのに必要

### 2．Web サーバを作成

ルートディレクトリ直下に、server というバックエンド用ディレクトリを作成し、
Web サーバーとして web-server.ts を以下のとおり作成する。

```ts:server/web-server.ts
/**
 * Web サーバ
 */

import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import * as Koa from 'koa';
import * as koaStatic from 'koa-static';
import * as KoaRouter from 'koa-router';
import * as bodyParser from 'koa-bodyparser';
import { join } from 'path';

const app = new Koa(); // Koa サーバ
const PORT = process.env.PORT || 3000; // アプリ起動時に PORT が直接指定された場合は, process.env.PORT が優先される.
const clientSrcPath = join(process.cwd(), 'dist/client');

// JSON リクエストをパースして受け取れるようにする
app.use(bodyParser({
  // application/x-javascript 型のリクエストを JSON として処理できるようにする
  extendTypes: {
    json: ['application/x-javascript']
  }
}));

// サーバサイド側 ミドルウェア ルーティングを定義
const koaRouter = new KoaRouter();
koaRouter.get('/api/*', (ctx) => {
  ctx.status = 200;
  ctx.body = 'API が呼ばれました';
});

// サーバサイド側 ミドルウェアの提供
app.use(koaRouter.routes());

// クライアント側 ミドルウェアの提供
app.use(koaStatic(clientSrcPath));

// HTTP サーバー開始
app.listen(PORT, () => console.log(`
======================================================================
KOAN stack Template App. アプリ名をここに表示
======================================================================
=========================================================== ver.${process.env.npm_package_version}
App is listening on http://localhost:${PORT}
`));

```

### 3．ts 設定ファイルを修正

server ディレクトリ配下に、サーバ側 tsconfig.json を以下のとおり作成する

```json-doc:server/tsconfig.json
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "module": "commonjs",
    "target": "es6"
  }
}

```

### 4．アプリ起動コマンドを package.json に追加
package.json の scripts を、以下のとおりに修正する

```json-doc:package.json
{
  "name": "demo-app",
  "version": "0.0.0",
  "scripts": {
    "start": "npm run clean && npm run build && npm run serve:node",
    "clean": "rm -rf dist",
    "build": "npm run build:client && npm run build:server",
    "build:client": "ng build",
    "build:server": "tsc --project server --outDir dist --allowjs true",
    "serve:node": "node dist/web-server.js",
    // 以下のコマンドは、もともとあったものを残すために退避したもの。無くても良い
    "ng": "ng",
    "ng:start": "ng serve",
    "ng:build": "ng build",
    "ng:test": "ng test",
    "ng:lint": "ng lint",
    "ng:e2e": "ng e2e"
    ...
}
```

### 5．Koa でアプリ起動

以下のコマンドを実行。
ビルド済みソースがあった場合は削除し、新たにビルドを行い、成功後の node アプリを起動するコマンド。

```bash
npm run start
```

コンパイル後、アプリが起動した時は以下のような表示になる。

```bash
...

> demo-app@0.0.0 serve /path/to/webapp/demo-app
> node dist/web-server.js

======================================================================
KOAN stack Template App. アプリ名をここに表示
======================================================================
=========================================================== ver.0.0.0
App is listening on http://localhost:3000

# ここまで表示されたら、起動完了。ブラウザで上記 URL にアクセス
```

#### ブラウザで確認

Web ブラウザから `http://localhost:3000/` にアクセスして表示されれば成功

<img width="1257" alt="univ起動確認_01.png" src="https://qiita-image-store.s3.amazonaws.com/0/199602/0cf4ca62-9b8f-d260-1ea4-4e5f22125feb.png">

#### API アクセス確認

web-server.ts に、以下の API としての URL パターンが記述があるので、これにアクセスしてみる

```ts
koaRouter.get('/api/*', (ctx) => {
  ctx.status = 200;
  ctx.body = 'API が呼ばれました';
});
```

上記は、ベースURL `http://localhost:3000` に対して、末尾に `/api/任意の文字列` が指定された時に、HTTPステータス 200、レスポンスに「API が呼ばれました」を返す処理になっているので、
Web ブラウザから `http://localhost:3000/api/aaa` にアクセスして以下のとおりに表示されれば成功

<img width="1256" alt="univ起動確認_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/199602/09e2b1b2-adb9-3e80-2086-d4c952aaa567.png">

これで、Web API として URL が呼ばれた場合に、データ返却できることが確認できた。

## この後やること

アプリの daemon（デーモン）化と環境変数操作

　→ [「Angular6 で俺式 KOAN スタック Webアプリを構築する、ほぼ全手順（2）」](https://qiita.com/tomy0610/items/2ca951f8e511f9f477e8)に執筆