serverless-plugin-split-stacksでAppSyncのResolverをデプロイする

# 環境
```
"serverless-plugin-split-stacks": "^1.9.3",
"serverless-appsync-plugin": "^1.3.1",
"serverless": "^1.78.1",
```

# appsyncをserverless fwでデプロイするのはつらい

[serverless-appsync-plugin](https://github.com/sid88in/serverless-appsync-plugin) でappsyncをデプロイしてみると、以下のようなエラーによく遭遇する。

```
template may not exceed 460800 bytes in size
```

具体的には、Resolverをプロビジョンする部分のテンプレートが大きくなりがちという問題がある。

## ResolverのCloudFormationを見てみる
```json

    "GraphQlResolverQuerylistUsers": {
      "Type": "AWS::AppSync::Resolver",
      "DependsOn": [],
      "Properties": {
        "ApiId": {
          "Ref": "GraphQlApiApiIdParameter"
        },
        "TypeName": "Query",
        "FieldName": "listCards",
        "RequestMappingTemplate": "\n  #set( $limit = (中略) n$util.toJson($ctx.result)\n  ",
        "Kind": "UNIT",
        "DataSourceName": {
          "Ref": "GraphQlDsUserNameParameter"
        }
      }
    },
```

こんな感じのJSONがResolverの数だけ並んでいる。  
例では略しているが、`RequestMappingTemplate` フィールドにvtlのソースがすべて入っているのがサイズの増大に寄与していることがわかる


# serverless-plugin-split-stacks

## 素直に使う

https://github.com/dougmoscrop/serverless-plugin-split-stacks

serverless fwでデプロイされるcloudformationテンプレートを分割してくれるやつ。  

[serverless-appsync-plugin](https://github.com/sid88in/serverless-appsync-plugin#split-stacks-plugin) では、以下のように使うよう書いてある。  

> You can use serverless-plugin-split-stacks to migrate AppSync resources in nested stacks in order to work around the 200 resource limit.

略

> Create stacks-map.js in the root folder
module.exports = {
  'AWS::AppSync::ApiKey': { destination: 'AppSync', allowSuffix: true },
  'AWS::AppSync::DataSource': { destination: 'AppSync', allowSuffix: true },
  'AWS::AppSync::FunctionConfiguration': { destination: 'AppSync', allowSuffix: true },
  'AWS::AppSync::GraphQLApi': { destination: 'AppSync', allowSuffix: true },
  'AWS::AppSync::GraphQLSchema': { destination: 'AppSync', allowSuffix: true },
  'AWS::AppSync::Resolver': { destination: 'AppSync', allowSuffix: true }
}

この設定の意味するところは`AWS::AppSync::Resolver` タイプのリソースを`AppSyncNestedStack`みたいな名前のテンプレートに移動させるというものになる。
ただ、見ての通り、この通りにしたところで、`AWS::AppSync::Resolver` タイプのリソースの分割先は一つのままなので、Resolverのリソースが十分に大きい場合、サイズ問題は解決できない。  

## 工夫する

[serverless-plugin-split-stacks](https://github.com/dougmoscrop/serverless-plugin-split-stacks#advanced-usage) のドキュメントをよく読むと、動的に移動先のテンプレートを決められるとある。  
なのでこれをうまく利用してみる。  
結果的に以下のようになった。

```javascript
// stacks-map.js
const def = {
  'AWS::AppSync::ApiKey': { destination: 'AppSyncApi', allowSuffix: true },
  'AWS::AppSync::DataSource': { destination: 'AppSync', allowSuffix: true },
  'AWS::AppSync::FunctionConfiguration': { destination: 'AppSyncFunction', allowSuffix: true },
  'AWS::AppSync::GraphQLApi': { destination: 'AppSyncApi', allowSuffix: true },
  'AWS::AppSync::GraphQLSchema': { destination: 'AppSyncSchema', allowSuffix: true },
}

let count = 0
module.exports =
  (resource, logicalId) => {
    if (resource.Type in def) {
      return def[resource] // 何か設定したいとき向け
    }

    if (resource.Type === 'AWS::AppSync::Resolver') {
      count++
      return {
        destination: `AppSyncResolver${Math.floor(count / 100)}`, // 100個ずつにする
        force: true // 既存のリソースが別のテンプレートにあった場合も、強制的に異動させる（Resolverは永続層などではなく単なるソースコードなので、移動しても影響はない）
      }
    }

// return undefinedすると、デフォルトの分割先が自動的にあてがわれるので特に指定不要
  };

```

すると、デプロイすると以下のようになる。

```
Serverless: Packaging service...
Serverless: [serverless-plugin-split-stacks]: Summary: 204 resources migrated in to 6 nested stacks
Serverless: [serverless-plugin-split-stacks]:    Resources per stack:
Serverless: [serverless-plugin-split-stacks]:    - (root): 106
Serverless: [serverless-plugin-split-stacks]:    - AppSyncApiNestedStack: 1
Serverless: [serverless-plugin-split-stacks]:    - AppSyncFunctionNestedStack: 10
Serverless: [serverless-plugin-split-stacks]:    - AppSyncNestedStack: 36
Serverless: [serverless-plugin-split-stacks]:    - AppSyncResolver0NestedStack: 99
Serverless: [serverless-plugin-split-stacks]:    - AppSyncResolver1NestedStack: 57
Serverless: [serverless-plugin-split-stacks]:    - AppSyncSchemaNestedStack: 1
```

意図したとおり、`AppSyncResolver0NestedStack` `AppSyncResolver1NestedStack` のように、動的に採番されたテンプレートが生成されるようになった。