技術メモ

プログラミングとか電子工作とか

Next.js (TypeScript) + Storybook + Amplify の初期構築(@2020-10-03)

f:id:ysmn_deus:20201003173613j:plain

前回からの続きです。
Amplifyを導入して嬉しいのは主に

  • AppSyncによるGlaphQL APIの利用
  • Cognitoによる認証

だと思います。
今回はAmplify DocsにあるようにGraphQL APIを利用することを持って初期構築としてみます。

まず最初に

必要最低限の環境構築

  • AWSアカウント(当たり前ですが)

Amplify CLIのセットアップ

インストール

AmplifyはCLI経由で色々することが多いです(というか、CLIは必須?)。
公式ドキュメント通りnpmでインストールします。

npm install -g @aws-amplify/cli

インストールが完了するとamplifyコマンドが利用できます。

初期設定

Amplify CLI経由でAWSサービスを触るユーザー設定を行います。

amplify configure

コマンドを実行するとAWSコンソールのログイン画面に飛ばされるので、ログインします。
その後、幾つか質問されるので回答していきます。

Specify the AWS Region
? region:  # 任意のリージョン、日本ならたぶんap-northeast-1
Specify the username of the new IAM user:
? user name:  # 分かりやすい名前付けといた方が後々困らない
Complete the user creation using the AWS console

アカウント作成の為にブラウザに飛ばされます。
うまくアカウント作成画面に移動できなかった場合はコンソールに表示されているURLに直接アクセスしましょう。
基本的に「次へ」を連打で良いと思います。好みがある場合は都度修正して下さい。

アカウントが作成できたら、コンソールへ戻ります。
accessKeyIdとsecretAccessKeyが問われますので、それぞれアクセスキーIDとシークレットアクセスキーを入力します。
両方を入力すると、プロファイル名を問われます。基本的にはdefaultで良いと思いますが、アカウントを使い分けたりしている人は名前を変えておくと良いかもしれません。
(一応この設定はC:\Users\ユーザー名\.aws内にあるcredentialsの中に記載されています。)

以上でAmplify CLIの初期設定は完了です。

Storybookのセットアップ

必須では無いんですが、Storybookを利用したいのでこのタイミングでセットアップします。
基本的には下記の記事を参考にさせていただきました。

Storybookのインストール

超絶簡単です。Storybookの公式にあるとおり

npx sb init

で完了です。
サンプルのコンポーネントsrc/storiesに生成されるようで、これらがtsxファイルで用意されているところを鑑みるとtypescriptのプロジェクトかどうかもインストール時にチェックしているようです。
試しに起動するには

yarn storybook

でStorybookが起動します。

Web上には、どうもトラブルがあったりする影響なのかnpm/yarnでパッケージをインストールしている方が多いように見受けられます。
もし今後触っていく内にトラブルが多いようでしたら手動でパッケージをインストールする方法を試してみたいと思います。

一応react-docgen-typescriptも便利そうだったのですが、基本的にデフォルトでTypeScript使っていれば型を表示してくれるのと、プロパティに?を付与した場合の挙動がめんどくさそうだったので導入しませんでした。
参考までに比較画像を掲載しておきます。

f:id:ysmn_deus:20200929173054j:plain
左が標準で、右が`react-docgen-typescript`を導入した画面

プロジェクトでのAmplifyのセットアップ

初期化

まずはプロジェクトのルートディレクトリでAmplify CLIを用いて初期化する必要があります。

ampllify init

いくつか質問されるので答えていきます。

? Enter a name for the project nextamplified
? Enter a name for the environment dev
? Choose your default editor: IntelliJ IDEA #(ここはお好きなIDEなどをお選び下さい)
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using react
? Source Directory Path:  src
? Distribution Directory Path: build
? Build Command:  npm.cmd run-script build
? Start Command: npm.cmd run-script start
? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use default

大体デフォルトです。
問題無くAmplifyの初期化が終われば、Amplifyをアプリケーションで利用する為にライブラリを入れておきます。

yarn add aws-amplify @aws-amplify/ui-react

GraphQL APIとデータベースの作成

準備

GraphQLのAPIを有効にするとAWS側でAppSyncの準備がなされます。
本来であればDynamoDBなどの設定も必要ですが、その辺を全てCloudFormationで処理してくれるので、基本的にウィザードに沿って進めるだけで大丈夫です。

amplify add api

APIを追加していきます。

? Please select from one of the below mentioned services: GraphQL
? Provide API name: nextamplified
? Choose the default authorization type for the API API key
? Enter a description for the API key:
? After how many days from now the API key should expire (1-365): 7
? Do you want to configure advanced settings for the GraphQL API Yes, I want to make some additional changes.
? Configure additional auth types? Yes
? Choose the additional authorization types you want to configure for the API Amazon Cognito User Pool
Cognito UserPool configuration
Use a Cognito user pool configured as a part of this project.
? Configure conflict detection? No
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)

The following types do not have '@auth' enabled. Consider using @auth with @model
         - Todo
Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/directives#auth


GraphQL schema compiled successfully.

Edit your schema at [プロジェクトパス]\amplify\backend\api\nextamplified\schema.graphql or place .graphql files in a directory at [プロジェクトパス]\amplify\backend\api\nextamplified\schema
? Do you want to edit the schema now? Yes
Please edit the file in your editor: [プロジェクトパス]\amplify\backend\api\nextamplified\schema.graphql
Successfully added resource nextamplified locally

基本的にはドキュメント通りやってますが、試しにやってみる分にはCognitoの認証などは不要だと思います。
とりあえずスキーマを見てみます。Choose a schema templateSingle object with fieldsを選択している場合はamplify/backend/api/nextamplified/schema.graphqlに下記の通りのファイルが生成されています。

type Todo @model {
  id: ID!
  name: String!
  description: String
}

はてなシンタックスにgraphql追加してくれ

このまま試しても良さそうですが、一応ドキュメントの通りに修正します。

type Post
@model
@auth(rules: [{ allow: owner }, { allow: public, operations: [read] }]) {
  id: ID!
  title: String!
  content: String!
}

@authディレクティブで認証処理を入れています。この辺の挙動はドキュメントを参照して下さい。
(個人的にこの辺の柔軟さはAppSyncを採用する理由になっても良いと思っています)
編集が完了したらAPIAWS上に生成します。

AWS上にバックエンドを生成(ローカルでモックを作る場合はとりあえず不要)

以降の操作は課金対象になる(DynamoDBやCongnito)と思いますので、ご留意下さい。ほぼ無料枠に収まると思いますが。
最初に現在の状況を確認しておきます。

amplify status

おそらく2個のリソース(AuthとApi)が表示されていると思います。
これらのリソースを下記の操作でAWSに生成します。

amplify push

AppSyncのGraphQLスキーマコンパイルがまず走ると思います。

? Do you want to generate code for your newly created GraphQL API Yes
? Choose the code generation language target typescript
? Enter the file name pattern of graphql queries, mutations and subscriptions src\graphql\**\*.ts
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
? Enter the file name for the generated code src\API.ts

とりあえず基本デフォルトです。
データ構造が複雑になった際にはmaximum statement depthあたりをもう少し深くしてもいいかもしれません。
このウィザードが完了するとリソースを生成します。少々時間がかかると思います。

完了すると、ターミナルにGraphQLのエンドポイントとAPIキーが表示されると思います。

GraphQL endpoint: https://
GraphQL API KEY: 

この状態まで行けばAWS上にはリソースが生成されています。
GraphQLのウェブコンソールを確認する場合は

amplify console api

で該当URLに飛ばされるようです。(AWSアカウントのログインが必要です)

ローカルでモックを生成する

AppSyncはローカルでモックを走らせて開発することができます。
下記のコマンドを打てばローカルでAppSyncのサーバーが起動します。

amplify mock api

料金が発生しないという安心感もありますが、何よりAWSにリソースを適応するのに結構時間がかかるので、基本こちらでの開発がメインになると思います。

GraphQLツールバーでデータを挿入する

前述のAWSリソースでもローカルモックでもいいのですが、とりあえずデータを入れて見ます。
(基本的にローカル環境での想定で話を進めます)
GraphQLのツールバー(ウェブコンソール)から下記のミューテーションを走らせます。

mutation CreatePost {
  createPost(input: {title: "Test Post", content: "post content"}) {
    id
    owner
    title
    updatedAt
    createdAt
    content
  }
}

たぶんなにがしかの文句を言われる筈です。
これは@authディレクティブがAPIキー認証はreadのみ許容するというスキーマな為です。
Use: API Keyという箇所をクリックしてUse: User Pool(Cognito認証)にし、Update Authをクリックして適当な認証トークンを設定します(基本は何も変更せずにGenerate Tokenで問題無いです)。
その後にもう一度上記のMutationを実行すると右側に適当なレスポンスが表示されると思います。

右側にレスポンスが表示されていれば大丈夫ですが、一応Queryも実行してみます。

query ListPosts {
  listPosts {
    items {
      content
      createdAt
      id
      owner
      title
    }
  }
}

問題無くPostのリスト(とはいえ1個ですが)が取得できていると思います。

SSRでのAPI利用

ようやっとコンポーネントを触ります。
とりあえずチュートリアルということで、src/pages/index.tsxに全て記載していきます。
index.tsxcssを参照しているので、csssrcディレクトリに移動しています。

これでトップページは表示されます。
AmplifyAuthenticatorといれるだけで、簡易的ではありますが認証保護+アカウント生成の機能までやってくれるのは嬉しいところです。
とりあえず起動してみます。

yarn dev

ローカルで開発するときはあわせて

amplify mock api

も実行しておきます。
問題無く表示されていればAmplifyAuthenticatorのところからユーザーを作成して適当に記事を投稿してみます。
たぶん404に飛ばされますが、これは作成後に記事のページに飛ぶ処理を書いておきながら飛んだ先のコンポーネントが無いためです。

SSGでのAPI利用

Next.jsの特徴としてSSRとSSGの両方を使い分けられます。
ここではSSGを利用して記事ページを作成します。src/pages/posts/[id].tsxに作成していきます。

上記のyarn devamplify mock apiで確認できると思います。

デプロイ

AWS上へのデプロイはServerless Frameworkを利用することができるようです。
ビルドしたデータをamplify publishする方法もありそうですが、Next.jsを利用するならServerless Frameworkを利用しておくのが無難だと思います。
ルートディレクトリにserverless.ymlを追加します。

# serverless.yml
nextamplified:
  component: "@sls-next/serverless-component@1.17.0"

ドキュメントではバージョンは1.16.0ですが、1.16.0だとThe parameter MinTTL is required.と怒られてしまいます。
あとこの辺で躓いたのですが、tsconfigでincrementalをtrueにしていると文句いわれるかもしれません。
とりあえずtsBuildInfoFileを書けば良さそうだったのでtsconfig.jsontsBuildInfoFile"./.tsbuildinfo"に設定する記述を追記しました。

たぶん以上の設定で準備は完了です。下記のコマンドでデプロイします。

npx serverless

ターミナル上にcloudfrontのURLなどの情報が出てきたら完了です。
ただし、上記の投稿した先のURL(ルートURL/posts/uuid)はSSGを利用しているので、ビルド時にデータが無ければ表示されないと思います。

Serverless Frameworkを利用してデプロイするのが非常に簡単ですが、CI/CDを考えるとAmplify Consoleを利用してGitリポジトリからデプロイされる方式を採る方がいいかもしれません。