ReactとAPI Gateway with serverless frameworkのアプリケーションをオフラインで開発する


変更点をいちいちdeployするのは遅いのでオフライン開発を試す。
結論としては割と簡単。

## Reactのセットアップ (client側)
`create-react-app` で作ればサーバ付きでよしなにしてくれるのでこちらはほぼ何もしなくておk。
`create-react-app` して `yarn start` すればサーバが立つしファイル変更時に自動再読み込みまでしてくれる。

```
create-react-app client --typescript 
cd client
yarn start
```


## serverlessのセットアップ (server側)
### まずはオフラインで普通に動かす

プロジェクト作成。

```
mkdir server
cd server
sls create --template aws-nodejs
```

次に必要なプラグインをinstall

```
yarn add serverless-offline
yarn add serverless-dynamodb-local
```

次にserverless.ymlの設定。

上でインストールしたpluginの設定と、offline用の設定を追加する。
その他serverless自体の設定、functionとresourceの設定もしていく。

```serverless.yaml
service: aws-nodejs

plugins:
 - serverless-dynamodb-local
 - serverless-offline

custom:
  dynamodb:
    start:
      port: 8000
      inMemory: true
      migrate: true
      seed: true
    seed:
      development:
        sources:
          - table: chat
            sources: 
              - ./data.json

provider:
  name: aws
  runtime: nodejs8.10
  stage: dev
  region: us-east-1

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: test
          method: get

resources:
  Resources:
    ChatTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: chat
        AttributeDefinitions:
          - AttributeName: user
            AttributeType: S
          - AttributeName: unixtime
            AttributeType: N
        KeySchema:
          - AttributeName: user
            KeyType: HASH
          - AttributeName: unixtime
            KeyType: RANGE
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
```

設定ファイルを書いたらDynamoDB Localのファイルをinstallしてstart。

```
sls dynamodb install
sls dynamodb start
```

無事に起動したみたいなログが出ていたらモードを起動！

```
sls offline
```

### 起動時のエラー

アクセスごとにソースを読んでいるっぽいのでソースを変えた際の再起動的な操作は不要。

`sls dynamodb start` の時に下記のエラーが出るときはjavaのversionが古いので `brew cask install java` でupgradeしましょう。

```
Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/logging/log4j/spi/ExtendedLogger : Unsupported major.minor version 51.0
``` 

### DynamoDB Localについて

設定で指定したdata.jsonは以下の感じ。起動時に初期データを読み込んでくれる。

```data.json
[
    {   
        "user": "user1",
        "unixtime": 1482419900
    },  
    {   
        "user": "user2",
        "unixtime": 1482418800
    }   
]
```

`sls dynamodb start` 時にデータは突っ込んでくれるけれど、起動したままデータを再度突っ込むときは `sls dynamodb seed` を実行する。truncate & insertではなく単純に上書きっぽい。

再起動したいときは `sls dynamodb remove` and `sls dynamodb start`

### DynamoDB Localを見にいく

agent作成時にendpointを指定する。
offlineかどうかを取得できるので書き換えが不要なようにしておく。

```
module.exports.hello = async (event) => {
  const dynamodb = new aws.DynamoDB.DocumentClient(
    event.isOffline
      ? { region: "localhost", endpoint: "http://localhost:8000" }
      : {}
  );  

  const ret = await dynamodb.scan({ TableName: 'chat' }).promise();
  console.log(ret);

  return {
    statusCode: 200,
    body: "Hello!!!",
  };  
};
```

### DynamoDB shell

`http://localhost:8000/shell/` にアクセスするとコードを実行できるshellが起動する。
JavaScriptのコードを書いて実行ボタンを押せば実行結果を取得できる。べんり。

```
var params = {
    TableName: 'chat',
};
dynamodb.scan(params, function(err, data) {
    if (err) ppJson(err);
    else ppJson(data);
});
```

## 二つを合わせる

面倒なので同時に起動できるように `foreman` 使っておきましょう。

```
cd server
yarn add -D foreman
```

server側のディレクトリに `Procfile` を作る。


```Procfile
server: serverless offline --port 3001
client: cd ../client; yarn start
```

で、`nf start`。

```
[WARN] No ENV file found                     
11:39:29 client.1   |  yarn run v1.15.2      
11:39:29 client.1   |  $ react-scripts start 
11:39:30 server.1   |  Serverless: Starting Offline: dev/us-east-1.                        
11:39:30 server.1   |  Serverless: Routes for hello:                                       
11:39:30 server.1   |  Serverless: GET /test 
11:39:30 server.1   |  Serverless: Offline listening on http://localhost:3001              
11:39:32 client.1   |  Starting the development server...                                  
11:39:37 client.1   |  Compiled successfully!
11:39:37 client.1   |  You can now view client in the browser.                             
11:39:37 client.1   |    Local:            http://localhost:5100/                          
11:39:37 client.1   |    On Your Network:  http://10.0.1.6:5100/                           
11:39:37 client.1   |  Note that the development build is not optimized.                   
11:39:37 client.1   |  To create a production build, use yarn build.      
```

OK！
コマンドは忘れるので `yarn start` で起動できるようにnpm scriptに登録しておきましょう。

```package.json
{
  "dependencies": {
    "serverless-dynamodb-local": "^0.2.37",
    "serverless-offline": "^4.10.0"
  },  

  "scripts": {
    "start": "nf start"
  },  
  "devDependencies": {
    "foreman": "^3.0.1"
  }
}
```


道具が整っていて意外と楽にオフライン開発ができるように。
先人のみなさまに感謝。

## 参照
https://qiita.com/noralife/items/e36621ddd0e5b8ff4447