Software development of explosion! -夢の破片(カケラ)たちの日々-

ソフトウェア開発を中心としたコンピューター関連のネタを扱ったブログです

Software development is passion and explosion!

CDK for Terraform で Azure StaticSiteApps のアプリをデプロイした際のハマりどころメモ

純正 Provider の有無は CDKTF のプロバイダーから検索

https://github.com/orgs/cdktf/repositories?q=cdktf-provider-

下記ページのまんま(リンク抜粋してるだけだし)

Providers - CDK for Terraform | Terraform | HashiCorp Developer

各プロバイダーの API は HCL と同じ

どんな設定ができるか?だとか、HCLと VSCode の「定義へ移動」(F12) を使って調べればわかる。

Input Variables の使い方が謎

cdktf cli では、現時点では環境変数でしか指定できない。 というのは良いのだが、cdktf synth なり cdktf deploy なりする際に HCL 生成時にランダムで発行される XXXX が付いてしまう。 回避方法が不明なため、1 回はコケさせて XXXX を確認しないとダメそう。(それってどうなの?という感じがするのだが。。。)

サービスプリンシパルは Azure AD アプリ

そのまんま。アプリの登録から登録する。

サービスプリンシパル (アプリ) に ロールを割り当てる

learn.microsoft.com

これをしないと、

Cannnot register providers: Microsoft.TimeSeriesInsights. Errors were: Cannot register provider Microsoft.TimeSeriesInsights with Azure Resource Manager: resources.ProvidersClient#Register: Failure responding to request: StatusCode=403

やら

Unable to list provider registration status, it is possible that this is due to invalid credentials or the service principal does not have permission to use the Resource Manager API, Azure error: resources.ProvidersClient#List: Failure sending request: StatusCode=0

やら、ログ取り忘れたけど ResourceGroup 作成や ResourceManager API のアクセス権限が無いと怒られる。(与えてないから当然なのだが)

GitHub Actions から OIDC を使うための Azure の設定

learn.microsoft.com

単純に、どこだっけ?となるのでメモ。

stdin が無いと怒られたりするので CDKTF Action を使いましょう

https://github.com/hashicorp/terraform-cdk-action

こんなエラーが出る。

Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.
Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported

tfstate の管理

Terraform Cloud を使うなり、AWS S3 なり外部に保存しておいて、毎回、落としてきて使う。変更があったら更新する。をしないとダメそう。(Terraform の宿命だろうけど)

作ったもの

https://github.com/poad/azure-examples

Ubuntu (ARM64) on Intel Mac

参考記事

www.mztn.org

手順

  1. qemu のインストール
  2. Ubuntu Server のイメージファイルのダウンロード
  3. qemu を使って Kernel (vmlinuz)、initram (initrd.img) を取り出す
  4. qemu を使って起動
qemu-system-aarch64 -m 1024 -cpu cortex-a57 -nographic -machine virt \
 -kernel vmlinuz-5.4.0-91-generic \
 -append 'root=/dev/vda1 rw rootwait mem=1024M console=ttyS0 \
  console=ttyAMA0,38400n8 init=/usr/lib/cloud-init/uncloud-init \
  ds=nocloud ubuntu-user=ubuntu ubuntu-pass=upass' \
 -drive if=none,id=image,file=focal-server-cloudimg-arm64.img \
 -initrd initrd.img-5.4.0-91-generic \
 -device virtio-blk-device,drive=image \
 -netdev user,id=net0,hostfwd=tcp::2222-:22 \
 -device virtio-net-pci,netdev=net0

ArchLinux で error: required key missing from keyring が出た場合の keyring の更新方法

ArchLinux を長い間起動せずにおくと、pacman で使用する証明書が失効してしまって、 pacman -Syu

:: Import PGP key 3B94A80E50A477C7, "Jan Alexander Steffens (heftig) <heftig@archlinux.org>"? [Y/n] 
error: key "3B94A80E50A477C7" could not be looked up remotely
error: required key missing from keyring
error: failed to commit transaction (unexpected error)
Errors occurred, no packages were upgraded.

といったエラーで pacman -Syu が失敗する。

archlinux-keyring パッケージを更新して、 pacman -Syu が期待通りに動作するようにする対策手順を記載する。

sudo -s
pacman-key --init 
pacman-key --populate
pacman-key --refresh-keys
pacman -Sy archlinux-keyring

pacman-key --refresh-keys でエラーが出ても、 pacman -Sy archlinux-keyring が成功すれば、その後は pacman -Syu が期待通りに動作するようになる。

bbs.archlinux.org

bash 風 zsh (prezto) prompt

それらしく動くようになったので残しておく。

# VCSの情報を取得するzshの便利関数 vcs_infoを使う
autoload -Uz vcs_info

# 表示フォーマットの指定
# %b ブランチ情報
# %a アクション名(mergeなど)
zstyle ':vcs_info:*' formats '[%b]'
zstyle ':vcs_info:*' actionformats '[%b|%a]'
precmd () {
  psvar=()
  LANG=en_US.UTF-8 vcs_info
  [[ -n "$vcs_info_msg_0_" ]] && psvar[1]="$vcs_info_msg_0_"
}

local demi='$'
test "${USER}" = "root" && demi='#'

# バージョン管理されているディレクトリにいれば表示,そうでなければ非表示
#RPROMPT="%1(v|%F{green}%1v%f|)"
PROMPT="%F{green}%B%n@%m%b%f:%~%1(v|%F{blue}%1v%f|)${demi} "

参考

gihyo.jp

Docker のコンテナーランタイムを Kata containers と Firecracker に切り替える

blog.inductor.me この記事に触発されて、www.pearllinux.com に入れてみました。 上記では、GitHubのリリースからダウンロードされているが、今回はkata-containers のインストールを docker から kata-deploy を使用するようにしてみた。

手順

  1. kata-deploy の install 手順通りに docker run -v /opt/kata:/opt/kata -v /var/run/dbus:/var/run/dbus -v /run/systemd:/run/systemd -v /etc/docker:/etc/docker -it katadocker/kata-deploy kata-deploy-docker install を行う。
$ docker run -v /opt/kata:/opt/kata -v /var/run/dbus:/var/run/dbus -v /run/systemd:/run/systemd -v /etc/docker:/etc/docker -it katadocker/kata-deploy kata-deploy-docker install
Unable to find image 'katadocker/kata-deploy:latest' locally
latest: Pulling from katadocker/kata-deploy
a02a4930cb5d: Pull complete 
c702ea4a22bc: Pull complete 
97ec70278314: Pull complete 
56283ea9568d: Pull complete 
3be7ca42e1f8: Pull complete 
ece4a4e81262: Pull complete 
7051f8fda3fc: Pull complete 
Digest: sha256:3c3a0307572a0903e1f0877ac01e782c5f366fe2b0b0a62eb87da579020929e2
Status: Downloaded newer image for katadocker/kata-deploy:latest
copying kata artifacts onto host
configuring docker
{
  "runtimes": {
    "kata-qemu": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-qemu.toml" ]
    },
    "kata-qemu-virtiofs": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-qemu-virtiofs.toml" ]
    },
     "kata-fc": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-fc.toml" ]
    },
     "kata-clh": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-clh.toml" ]
    }
  }
}
  1. コンソールログ出力された内容を /etc/docker/daemon.json として保存する。
  2. system に反映
sudo systemctl daemon-reload
sudo systemctl restart docker
  1. 動作確認
$ docker run --rm --runtime=kata-fc -itd --name alpine alpine ash
cc5556f76661f4b3ab58dba7c64a1f70c21b53ed85a1d7889a98863f37c06612
docker: Error response from daemon: OCI runtime create failed: rpc error: code = Unknown desc = rootfs (/run/kata-containers/shared/containers/cc5556f76661f4b3ab58dba7c64a1f70c21b53ed85a1d7889a98863f37c06612/rootfs) does not exist: unknown.

コケた…理由は簡単 5. /etc/docker/daemon.json を修正 "storage-driver": "devicemapper" の設定を追加する。 6. ふたたび動作確認

$ docker run --rm --runtime=kata-fc -itd --name alpine alpine ash
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
df20fa9351a1: Pull complete 
Digest: sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321
Status: Downloaded newer image for alpine:latest
4642bdf55730e00b14c76e7295ff147a1c835bda4a2ac060eeadbbc25d1461c4
vagrant@vagrant-virtualbox:~$ ps -ae | grep -E "kata|fire"
   6608 ?        00:00:07 firecracker
   6616 pts/1    00:00:00 kata-shim

はい!通りました。

結果

docker run -v /opt/kata:/opt/kata -v /var/run/dbus:/var/run/dbus -v /run/systemd:/run/systemd -v /etc/docker:/etc/docker -it katadocker/kata-deploy kata-deploy-docker install && ¥
sudo modprobe vhost_vsock && ¥
cat <<EOF | sudo tee  /etc/docker/daemon.json 
{
  "default-runtime": "kata-fc",
  "runtimes": {
    "kata-qemu": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-qemu.toml" ]
    },
    "kata-qemu-virtiofs": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-qemu-virtiofs.toml" ]
    },
     "kata-fc": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-fc.toml" ]
    },
     "kata-clh": {
      "path": "/opt/kata/bin/kata-runtime",
      "runtimeArgs": [ "--kata-config", "/opt/kata/share/defaults/kata-containers/configuration-clh.toml" ]
    }
  },
  "storage-driver": "devicemapper"
}
EOF
sudo systemctl daemon-reload && ¥
sudo systemctl restart docker && ¥
docker run --rm -itd --name alpine alpine ash && ¥
ps -ae | grep -E "kata|fire" && ¥
docker stop alpine

ちなみに Nested Virtualization が有効でないと動きません。 f:id:poad1010:20200731084236p:plain f:id:poad1010:20200731084308p:plain

AWS Cloud 9 上だと、おそらくそれが原因で動かない…

SpringBoot 2.3.x の 「OCI images using Cloud Native Buildpacks」を試してみた

背景

TwitterでSpringBoot2.3.xでは Cloud Native Buildpacks によって jib プラグインを使わずに DockerfileレスでDockerイメージをビルド出来ると教えていただきました。

な、なんだってーー!!

ということで、試さないかもと言っておきながら、早速試してみました。

環境

Java

  • Librca JDK 11.0.7
  • Spring Boot 2.3.1.RELEASE
  • Gradle 6.5
  • Jib Gradle Plugin 2.4.0 (比較用)
  • Docker Desktop for Mac 2.3.0.3 (45519)
    • docker-ce 19.03.8

ざっくりとしたまとめ

評価項目 Cloud Native Buildpacks Jib Gradle Plugin
手軽さ
スピード ×
機能性 ×
イメージサイズ
シンプルさ ×

詳細

手軽さ

jib と比べた場合、spring-boot-gradle-plugin(Maven の場合は spring-boot-maven-plugin)のみで完結するため、わざわざjib pluginのようなサードパーティプラグインを導入せずに使える。 とはいえ、jib plugin の導入自体も難しいものではないため、Dockerfileを書かずにコンテナー化するための敷居が下がった程度と言えよう。

スピード

きちんと時間計測はしていないが、jib pluginでビルドした方がビルド時間は短い。

機能性

Twitterでご指摘いただきました。とても有益な情報をありがとうございます!

Memory Calculator、Link-Local DNS、JVMKill Agent (個人的には特に前者2つ)はとても魅力的。 jib でやるには、事前にベースイメージとして、これらをインストールしたものを使うほか無いだろう。

生成するDockerイメージ名を変更出来る程度で、Dockerfileの FROM で指定するような内容は設定できそうに無い。(jibなら出来る) ベースイメージの変更は、おそらくbuilderのrun imageを差し替えることになる。 ただ、そうすると自前でbuilderを用意しないとならなさそう(Dockerfile3つとTOMLでいけるだろうけど)なので、jibよりはハードルが高そう。 (何となくだが、AWS CodeBuildのbuildspec.ymlとビルド環境として指定するイメージがひとまとめになったものがbuilderというイメージ。高機能故に少し複雑)

イメージのタイムスタンプをDockerの形式(?)に合わせることができなさそう(jibなら出来る)

Spring Boot Gradle Plugin Reference Guide

イメージサイズ

同じアプリをビルドして docker images で表示されるサイズを比較してみた。

Cloud Native Buildpacks でビルドした場合417MB。 jibでビルドした場合(jib.from.imageをデフォルトから変更しない場合です)366MB。

→ Memory Calculator、Link-Local DNS、JVMKill Agent が入っていること、layer数が多いことを考えると、左程の差ではなさそう。(ベースイメージのサイズが支配的になるお話。jibで mcr.microsoft.com/java/jdk:11-zulu-alpine を指定したら600MB超えたから充分、許容範囲内だろう。それでもデカいというならGraalVM使うしかない気がする)

シンプルさ

Cloud Native Buildpacks はとても高機能だが、その反面、jibほどシンプルでは無い(Builder/Stack/Run Imageが存在するので、それを理解しないとどのようにすればベースイメージを変えられるのか?がわからないなど)。 ということで、シンプルさはjibにあると思う。(シンプルが必ずしも良いとは言わないし、高機能も同じく。この辺はGo言語とRustのどちらの方がいいのか?という不毛な議論と同じようなお話だろう。手軽さ・使い勝手が大事なのだと思うんだけど…)

結論

現状では jib plugin を使用した方が ベースイメージ(DockerfileのFROMに指定するイメージ)を指定できたり、 タイムスタンプ形式の変更、外部ファイルの追加、 ビルドスピードといった面で優位である。 しかしながら、Memory Calculator、Link-Local DNS、JVMKill Agent といったミドルウェアの存在を考えると、Cloud Native Buildpacks の方が運用していく上で欲しいものが最初から付いてくるので良い。 また、毎回、[start.spring.io:title] で作ったプロジェクトに jib plugin を導入する手間を考えると、自動生成されたプロジェクトに設定済みのプラグインだけで完結するというのは嬉しい限り。 run image (ベースイメージ) を build.gradle で指定出来るようになってくれると嬉しいかも。(今はjibと比べるとちょっと敷居高い)

検証コード

jib

examples/java-example/morphological-analyis/kuromoji at 54e1698f705884a5a47a4c642a9cf67b7526f64d · poad/examples · GitHub

Cloud Native Buildpacks

Remove jib by poad · Pull Request #34 · poad/examples · GitHub

おまけ

ビルドコマンド (Gradle)

jib

./gradlew jibDockerBuild

Cloud Native Buildpacks

./gradlew bootBuildImage

AWS Amplify と AWS Cognito と TypeScript で作る ユーザー認証機能付き Next.js アプリ

AWS Amplify とは?

aws.amazon.com

モバイルアプリケーションやウェブアプリケーションを構築するための JavaScript フレームワークです。 これを使うことで、後述する AWS Cognito を簡単に使用できます。

AWS Cognito とは?

f:id:poad1010:20200222171716p:plain ユーザー管理を一括で行ってくれるユーザー認証サービスです。 Auth0 の AWS版といったところでしょうか。

f:id:poad1010:20200222171341p:plain f:id:poad1010:20200222171452p:plain f:id:poad1010:20200222171513p:plain

この様に色々と設定できます。

Next.js とは?

React.js でサーバーサイドレンダリングするためのフレームワークです。 Vue.js の Nuxt.js のようなものですね。

やってみよう!

1. Next.js with TypeScript な環境を作る

https://nextjs.org のサイトの手順を参考に、TypeScript に対応した Next.js アプリが実行できる環境を構築します。 ちなみに、筆者はyarn を使うことが多いですが、公式ドキュメントは npm ベースです。npm を使われる方は適宜、置き換えてお読みください。

$ mkdir next-amplify-example
[ken-yo@MacBook-Pro-2019-15inch ~]$ cd next-amplify-example 
[ken-yo@MacBook-Pro-2019-15inch next-amplify-example]$ yarn init -y
yarn init v1.22.0
warning The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.
success Saved package.json
✨  Done in 0.02s.
[ken-yo@MacBook-Pro-2019-15inch next-amplify-example]$ yarn add --save react react-dom next
yarn add v1.22.0
info No lockfile found.
[1/4] 🔍  Resolving packages...
warning next > @babel/runtime-corejs2 > core-js@2.6.11: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
warning next > styled-jsx > babel-types > babel-runtime > core-js@2.6.11: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "next > styled-jsx@3.2.4" has unmet peer dependency "react@15.x.x || 16.x.x".
warning "next > use-subscription@1.1.1" has unmet peer dependency "react@^16.8.0".
warning " > react-dom@16.12.0" has unmet peer dependency "react@^16.0.0".
warning " > next@9.2.2" has unmet peer dependency "react@^16.6.0".
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 578 new dependencies.
info Direct dependencies
├─ next@9.2.2
└─ react-dom@16.12.0
info All dependencies
├─ @ampproject/toolbox-optimizer@2.0.0
├─ @ampproject/toolbox-runtime-version@2.0.0
├─ @ampproject/toolbox-script-csp@2.0.0
├─ @ampproject/toolbox-validator-rules@2.0.0
├─ @babel/core@7.7.2
├─ @babel/generator@7.8.4
├─ @babel/helper-builder-binary-assignment-operator-visitor@7.8.3
├─ @babel/helper-builder-react-jsx@7.8.3
├─ @babel/helper-call-delegate@7.8.3
├─ @babel/helper-create-class-features-plugin@7.8.3
├─ @babel/helper-define-map@7.8.3
├─ @babel/helper-explode-assignable-expression@7.8.3
├─ @babel/helper-wrap-function@7.8.3
├─ @babel/helpers@7.8.4
├─ @babel/highlight@7.8.3
├─ @babel/parser@7.8.4
├─ @babel/plugin-proposal-async-generator-functions@7.8.3
├─ @babel/plugin-proposal-class-properties@7.7.0
├─ @babel/plugin-proposal-dynamic-import@7.8.3
├─ @babel/plugin-proposal-json-strings@7.8.3
├─ @babel/plugin-proposal-nullish-coalescing-operator@7.7.4
├─ @babel/plugin-proposal-object-rest-spread@7.6.2
├─ @babel/plugin-proposal-optional-catch-binding@7.8.3
├─ @babel/plugin-proposal-optional-chaining@7.7.4
├─ @babel/plugin-proposal-unicode-property-regex@7.8.3
├─ @babel/plugin-syntax-async-generators@7.8.4
├─ @babel/plugin-syntax-bigint@7.8.3
├─ @babel/plugin-syntax-dynamic-import@7.8.3
├─ @babel/plugin-syntax-json-strings@7.8.3
├─ @babel/plugin-syntax-nullish-coalescing-operator@7.8.3
├─ @babel/plugin-syntax-object-rest-spread@7.8.3
├─ @babel/plugin-syntax-optional-catch-binding@7.8.3
├─ @babel/plugin-syntax-optional-chaining@7.8.3
├─ @babel/plugin-syntax-top-level-await@7.8.3
├─ @babel/plugin-syntax-typescript@7.8.3
├─ @babel/plugin-transform-arrow-functions@7.8.3
├─ @babel/plugin-transform-async-to-generator@7.8.3
├─ @babel/plugin-transform-block-scoped-functions@7.8.3
├─ @babel/plugin-transform-block-scoping@7.8.3
├─ @babel/plugin-transform-classes@7.8.3
├─ @babel/plugin-transform-computed-properties@7.8.3
├─ @babel/plugin-transform-destructuring@7.8.3
├─ @babel/plugin-transform-dotall-regex@7.8.3
├─ @babel/plugin-transform-duplicate-keys@7.8.3
├─ @babel/plugin-transform-exponentiation-operator@7.8.3
├─ @babel/plugin-transform-for-of@7.8.4
├─ @babel/plugin-transform-function-name@7.8.3
├─ @babel/plugin-transform-literals@7.8.3
├─ @babel/plugin-transform-member-expression-literals@7.8.3
├─ @babel/plugin-transform-modules-amd@7.8.3
├─ @babel/plugin-transform-modules-commonjs@7.7.0
├─ @babel/plugin-transform-modules-systemjs@7.8.3
├─ @babel/plugin-transform-modules-umd@7.8.3
├─ @babel/plugin-transform-named-capturing-groups-regex@7.8.3
├─ @babel/plugin-transform-new-target@7.8.3
├─ @babel/plugin-transform-object-super@7.8.3
├─ @babel/plugin-transform-parameters@7.8.4
├─ @babel/plugin-transform-property-literals@7.8.3
├─ @babel/plugin-transform-react-display-name@7.8.3
├─ @babel/plugin-transform-react-jsx-self@7.8.3
├─ @babel/plugin-transform-react-jsx-source@7.8.3
├─ @babel/plugin-transform-react-jsx@7.8.3
├─ @babel/plugin-transform-regenerator@7.8.3
├─ @babel/plugin-transform-reserved-words@7.8.3
├─ @babel/plugin-transform-runtime@7.6.2
├─ @babel/plugin-transform-shorthand-properties@7.8.3
├─ @babel/plugin-transform-spread@7.8.3
├─ @babel/plugin-transform-sticky-regex@7.8.3
├─ @babel/plugin-transform-template-literals@7.8.3
├─ @babel/plugin-transform-typeof-symbol@7.8.4
├─ @babel/plugin-transform-typescript@7.8.3
├─ @babel/plugin-transform-unicode-regex@7.8.3
├─ @babel/preset-env@7.7.1
├─ @babel/preset-modules@0.1.1
├─ @babel/preset-react@7.7.0
├─ @babel/preset-typescript@7.7.2
├─ @babel/runtime-corejs2@7.7.2
├─ @babel/runtime@7.7.2
├─ @next/polyfill-nomodule@9.2.2
├─ @webassemblyjs/floating-point-hex-parser@1.8.5
├─ @webassemblyjs/helper-code-frame@1.8.5
├─ @webassemblyjs/helper-fsm@1.8.5
├─ @webassemblyjs/helper-wasm-section@1.8.5
├─ @webassemblyjs/wasm-edit@1.8.5
├─ @webassemblyjs/wasm-opt@1.8.5
├─ @xtuc/ieee754@1.2.0
├─ abbrev@1.1.1
├─ accepts@1.3.7
├─ acorn@6.4.0
├─ adjust-sourcemap-loader@2.0.0
├─ ajv-errors@1.0.1
├─ ajv-keywords@3.4.1
├─ ajv@6.11.0
├─ amphtml-validator@1.0.23
├─ ansi-colors@3.2.4
├─ ansi-html@0.0.7
├─ ansi-styles@3.2.1
├─ anymatch@3.1.1
├─ aproba@1.2.0
├─ are-we-there-yet@1.1.5
├─ argparse@1.0.10
├─ arity-n@1.0.4
├─ arr-flatten@1.1.0
├─ array-union@1.0.2
├─ array-uniq@1.0.3
├─ asap@2.0.6
├─ asn1.js@4.10.1
├─ assert@1.4.1
├─ assign-symbols@1.0.0
├─ ast-types@0.13.2
├─ async-each@1.0.3
├─ async-retry@1.2.3
├─ async-sema@3.0.0
├─ atob@2.1.2
├─ autodll-webpack-plugin@0.4.2
├─ autoprefixer@9.7.4
├─ babel-code-frame@6.26.0
├─ babel-core@7.0.0-bridge.0
├─ babel-loader@8.0.6
├─ babel-plugin-transform-define@2.0.0
├─ babel-plugin-transform-react-remove-prop-types@0.4.24
├─ babel-runtime@6.26.0
├─ babel-types@6.26.0
├─ base@0.11.2
├─ base64-js@1.3.1
├─ binary-extensions@2.0.0
├─ bindings@1.5.0
├─ bluebird@3.7.2
├─ brace-expansion@1.1.11
├─ braces@2.3.2
├─ browserify-aes@1.2.0
├─ browserify-cipher@1.0.1
├─ browserify-des@1.0.2
├─ browserify-sign@4.0.4
├─ browserify-zlib@0.2.0
├─ buffer-equal-constant-time@1.0.1
├─ buffer-json@2.0.0
├─ buffer-xor@1.0.3
├─ buffer@4.9.2
├─ builtin-status-codes@3.0.0
├─ bytes@3.0.0
├─ cacache@12.0.3
├─ cache-base@1.0.1
├─ cache-loader@4.1.0
├─ caller-callsite@2.0.0
├─ caller-path@2.0.0
├─ callsites@2.0.0
├─ camelcase@5.3.1
├─ caniuse-lite@1.0.30001028
├─ chalk@2.4.2
├─ chokidar@3.3.1
├─ chownr@1.1.4
├─ chrome-trace-event@1.0.2
├─ ci-info@2.0.0
├─ class-utils@0.3.6
├─ cli-cursor@2.1.0
├─ cli-spinners@2.2.0
├─ clone-deep@4.0.1
├─ clone@1.0.4
├─ code-point-at@1.1.0
├─ collection-visit@1.0.0
├─ color-convert@1.9.3
├─ color-name@1.1.3
├─ colors@1.1.2
├─ compose-function@3.0.3
├─ compressible@2.0.18
├─ compression@1.7.4
├─ concat-map@0.0.1
├─ concat-stream@1.6.2
├─ conf@5.0.0
├─ console-browserify@1.2.0
├─ console-control-strings@1.1.0
├─ constants-browserify@1.0.0
├─ content-type@1.0.4
├─ cookie@0.4.0
├─ copy-concurrently@1.0.5
├─ copy-descriptor@0.1.1
├─ core-js-compat@3.6.4
├─ core-js@2.6.11
├─ core-util-is@1.0.2
├─ cosmiconfig@5.2.1
├─ create-ecdh@4.0.3
├─ create-hmac@1.1.7
├─ crypto-browserify@3.12.0
├─ css-blank-pseudo@0.1.4
├─ css-has-pseudo@0.10.0
├─ css-loader@3.3.0
├─ css-prefers-color-scheme@3.1.1
├─ css@2.2.4
├─ cssdb@4.4.0
├─ cssnano-preset-simple@1.0.3
├─ cssnano-simple@1.0.0
├─ cyclist@1.0.1
├─ d@1.0.1
├─ debug@2.6.9
├─ decode-uri-component@0.2.0
├─ deep-extend@0.6.0
├─ defaults@1.0.3
├─ define-properties@1.1.3
├─ del@3.0.0
├─ delegates@1.0.0
├─ des.js@1.0.1
├─ destroy@1.0.4
├─ detect-libc@1.0.3
├─ devalue@2.0.1
├─ diffie-hellman@5.0.3
├─ dom-serializer@0.2.2
├─ domain-browser@1.2.0
├─ domutils@2.0.0
├─ dot-prop@5.2.0
├─ duplexer@0.1.1
├─ duplexify@3.7.1
├─ ecdsa-sig-formatter@1.0.11
├─ ee-first@1.1.1
├─ electron-to-chromium@1.3.358
├─ emojis-list@3.0.0
├─ encodeurl@1.0.2
├─ enhanced-resolve@4.1.1
├─ env-paths@2.2.0
├─ errno@0.1.7
├─ error-ex@1.3.2
├─ es5-ext@0.10.53
├─ es6-iterator@2.0.3
├─ es6-symbol@3.1.3
├─ escape-html@1.0.3
├─ escape-string-regexp@1.0.5
├─ eslint-scope@4.0.3
├─ esprima@4.0.1
├─ esrecurse@4.2.1
├─ estraverse@4.3.0
├─ esutils@2.0.3
├─ etag@1.8.1
├─ eventemitter3@4.0.0
├─ events@3.1.0
├─ evp_bytestokey@1.0.3
├─ expand-brackets@2.1.4
├─ ext@1.4.0
├─ extglob@2.0.4
├─ fast-deep-equal@3.1.1
├─ fast-json-stable-stringify@2.1.0
├─ file-loader@4.2.0
├─ file-uri-to-path@1.0.0
├─ fill-range@4.0.0
├─ finally-polyfill@0.1.0
├─ find-cache-dir@2.1.0
├─ flatten@1.0.3
├─ flush-write-stream@1.1.1
├─ follow-redirects@1.10.0
├─ for-in@1.0.2
├─ fork-ts-checker-webpack-plugin@3.1.1
├─ from2@2.3.0
├─ fs-minipass@1.2.7
├─ fs.realpath@1.0.0
├─ fsevents@2.1.2
├─ gauge@2.7.4
├─ get-value@2.0.6
├─ glob-parent@5.1.0
├─ glob-to-regexp@0.4.1
├─ glob@7.1.6
├─ globby@6.1.0
├─ graceful-readlink@1.0.1
├─ gzip-size@5.1.1
├─ has-ansi@2.0.0
├─ has-symbols@1.0.1
├─ has-unicode@2.0.1
├─ has-value@1.0.0
├─ has@1.0.3
├─ hash.js@1.1.7
├─ hmac-drbg@1.0.1
├─ hosted-git-info@2.8.5
├─ html-entities@1.2.1
├─ htmlparser2@4.0.0
├─ http-errors@1.7.2
├─ http-proxy@1.18.0
├─ https-browserify@1.0.0
├─ iconv-lite@0.4.24
├─ icss-utils@4.1.1
├─ ieee754@1.1.13
├─ ignore-loader@0.1.2
├─ ignore-walk@3.0.3
├─ import-cwd@2.1.0
├─ import-fresh@2.0.0
├─ import-from@2.1.0
├─ infer-owner@1.0.4
├─ inflight@1.0.6
├─ ini@1.3.5
├─ invariant@2.2.4
├─ is-accessor-descriptor@1.0.0
├─ is-arrayish@0.2.1
├─ is-binary-path@2.1.0
├─ is-data-descriptor@1.0.0
├─ is-descriptor@1.0.2
├─ is-directory@0.3.1
├─ is-docker@2.0.0
├─ is-extglob@2.1.1
├─ is-fullwidth-code-point@1.0.0
├─ is-glob@4.0.1
├─ is-obj@2.0.0
├─ is-path-cwd@1.0.0
├─ is-path-in-cwd@1.0.1
├─ is-path-inside@1.0.1
├─ is-plain-obj@1.1.0
├─ is-plain-object@2.0.4
├─ is-windows@1.0.2
├─ is-wsl@2.1.1
├─ isarray@1.0.0
├─ jest-worker@24.9.0
├─ js-levenshtein@1.1.6
├─ js-tokens@4.0.0
├─ js-yaml@3.13.1
├─ jsesc@2.5.2
├─ json-parse-better-errors@1.0.2
├─ json-schema-traverse@0.4.1
├─ json-schema-typed@7.0.3
├─ jsonwebtoken@8.5.1
├─ jwa@1.4.1
├─ jws@3.2.2
├─ launch-editor@2.2.1
├─ load-json-file@2.0.0
├─ loader-runner@2.4.0
├─ lodash.curry@4.1.1
├─ lodash.includes@4.3.0
├─ lodash.isboolean@3.0.3
├─ lodash.isinteger@4.0.4
├─ lodash.isnumber@3.0.3
├─ lodash.isplainobject@4.0.6
├─ lodash.isstring@4.0.1
├─ lodash.once@4.1.1
├─ lodash.template@4.5.0
├─ lodash.templatesettings@4.2.0
├─ log-symbols@2.2.0
├─ loose-envify@1.4.0
├─ lru-cache@5.1.1
├─ mamacro@0.0.3
├─ map-visit@1.0.0
├─ merge-stream@2.0.0
├─ microevent.ts@0.1.1
├─ miller-rabin@4.0.1
├─ mime-db@1.43.0
├─ mime-types@2.1.26
├─ mime@1.6.0
├─ mimic-fn@1.2.0
├─ mini-css-extract-plugin@0.8.0
├─ minimalistic-crypto-utils@1.0.1
├─ minimatch@3.0.4
├─ minimist@1.2.0
├─ minipass@2.9.0
├─ minizlib@1.3.3
├─ mississippi@3.0.0
├─ mixin-deep@1.3.2
├─ move-concurrently@1.0.1
├─ nan@2.14.0
├─ nanomatch@1.2.13
├─ needle@2.3.2
├─ negotiator@0.6.2
├─ next-tick@1.0.0
├─ next@9.2.2
├─ node-libs-browser@2.2.1
├─ node-pre-gyp@0.14.0
├─ node-releases@1.1.50
├─ nopt@4.0.1
├─ normalize-html-whitespace@1.0.0
├─ normalize-package-data@2.5.0
├─ normalize-range@0.1.2
├─ normalize-url@1.9.1
├─ npm-bundled@1.1.1
├─ npm-packlist@1.4.8
├─ npmlog@4.1.2
├─ num2fraction@1.2.2
├─ number-is-nan@1.0.1
├─ object-assign@4.1.1
├─ object-copy@0.1.0
├─ object-keys@1.1.1
├─ object-path@0.11.4
├─ on-finished@2.3.0
├─ on-headers@1.0.2
├─ onetime@2.0.1
├─ ora@3.4.0
├─ os-browserify@0.3.0
├─ os-homedir@1.0.2
├─ os-tmpdir@1.0.2
├─ osenv@0.1.5
├─ p-limit@2.2.2
├─ p-locate@4.1.0
├─ p-map@1.2.0
├─ p-try@2.2.0
├─ pako@1.0.11
├─ parallel-transform@1.2.0
├─ parse-json@2.2.0
├─ pascalcase@0.1.1
├─ path-browserify@0.0.1
├─ path-dirname@1.0.2
├─ path-is-inside@1.0.2
├─ path-parse@1.0.6
├─ path-to-regexp@6.1.0
├─ path-type@2.0.0
├─ picomatch@2.2.1
├─ pinkie-promise@2.0.1
├─ pinkie@2.0.4
├─ pkg-dir@3.0.0
├─ pkg-up@3.1.0
├─ pnp-webpack-plugin@1.5.0
├─ posix-character-classes@0.1.1
├─ postcss-attribute-case-insensitive@4.0.2
├─ postcss-color-functional-notation@2.0.1
├─ postcss-color-gray@5.0.0
├─ postcss-color-hex-alpha@5.0.3
├─ postcss-color-mod-function@3.0.3
├─ postcss-color-rebeccapurple@4.0.1
├─ postcss-custom-media@7.0.8
├─ postcss-custom-properties@8.0.11
├─ postcss-custom-selectors@5.1.2
├─ postcss-dir-pseudo-class@5.0.0
├─ postcss-double-position-gradients@1.0.0
├─ postcss-env-function@2.0.2
├─ postcss-flexbugs-fixes@4.1.0
├─ postcss-focus-visible@4.0.0
├─ postcss-focus-within@3.0.0
├─ postcss-font-variant@4.0.0
├─ postcss-gap-properties@2.0.0
├─ postcss-image-set-function@3.0.1
├─ postcss-initial@3.0.2
├─ postcss-lab-function@2.0.1
├─ postcss-load-config@2.1.0
├─ postcss-loader@3.0.0
├─ postcss-logical@3.0.0
├─ postcss-media-minmax@4.0.0
├─ postcss-modules-extract-imports@2.0.0
├─ postcss-modules-local-by-default@3.0.2
├─ postcss-modules-scope@2.1.1
├─ postcss-modules-values@3.0.0
├─ postcss-nesting@7.0.1
├─ postcss-overflow-shorthand@2.0.0
├─ postcss-page-break@2.0.0
├─ postcss-place@4.0.1
├─ postcss-preset-env@6.7.0
├─ postcss-pseudo-class-any-link@6.0.0
├─ postcss-replace-overflow-wrap@3.0.0
├─ postcss-selector-matches@4.0.0
├─ postcss-selector-not@4.0.0
├─ prepend-http@1.0.4
├─ private@0.1.8
├─ process-nextick-args@2.0.1
├─ process@0.11.10
├─ promise-inflight@1.0.1
├─ promise@7.1.1
├─ prop-types-exact@1.2.0
├─ prop-types@15.7.2
├─ prr@1.0.1
├─ public-encrypt@4.0.3
├─ pump@3.0.0
├─ pumpify@1.5.1
├─ punycode@1.3.2
├─ query-string@4.3.4
├─ querystring-es3@0.2.1
├─ querystring@0.2.0
├─ randomfill@1.0.4
├─ range-parser@1.2.1
├─ raw-body@2.4.0
├─ rc@1.2.8
├─ react-dom@16.12.0
├─ react-error-overlay@5.1.6
├─ react-is@16.8.6
├─ read-pkg@2.0.0
├─ readable-stream@2.3.7
├─ readdirp@3.3.0
├─ recast@0.18.5
├─ reflect.ownkeys@0.2.0
├─ regenerate-unicode-properties@8.1.0
├─ regenerator-transform@0.14.1
├─ regex-parser@2.2.10
├─ regexpu-core@4.6.0
├─ regjsgen@0.5.1
├─ regjsparser@0.6.3
├─ remove-trailing-separator@1.1.0
├─ repeat-element@1.1.3
├─ requires-port@1.0.0
├─ resolve-url-loader@3.1.1
├─ resolve-url@0.2.1
├─ resolve@1.15.1
├─ restore-cursor@2.0.0
├─ ret@0.1.15
├─ retry@0.12.0
├─ rework-visit@1.0.0
├─ rework@1.0.1
├─ run-queue@1.0.3
├─ safer-buffer@2.1.2
├─ sass-loader@8.0.2
├─ sax@1.2.4
├─ scheduler@0.18.0
├─ schema-utils@2.6.4
├─ semver@5.7.1
├─ send@0.17.1
├─ serialize-javascript@2.1.2
├─ set-blocking@2.0.0
├─ set-value@2.0.1
├─ setimmediate@1.0.5
├─ shallow-clone@3.0.1
├─ shell-quote@1.7.2
├─ signal-exit@3.0.2
├─ snapdragon-node@2.1.1
├─ snapdragon-util@3.0.1
├─ sort-keys@1.1.2
├─ source-list-map@2.0.1
├─ source-map-resolve@0.5.3
├─ source-map-url@0.4.0
├─ spdx-correct@3.1.0
├─ spdx-exceptions@2.2.0
├─ split-string@3.1.0
├─ sprintf-js@1.0.3
├─ ssri@6.0.1
├─ static-extend@0.1.2
├─ stream-browserify@2.0.2
├─ stream-each@1.2.3
├─ stream-http@2.8.3
├─ strict-uri-encode@1.1.0
├─ string_decoder@1.1.1
├─ string-width@1.0.2
├─ strip-ansi@3.0.1
├─ strip-bom@3.0.0
├─ strip-json-comments@2.0.1
├─ style-loader@1.0.0
├─ styled-jsx@3.2.4
├─ stylis-rule-sheet@0.0.10
├─ stylis@3.5.4
├─ tar@4.4.13
├─ terser-webpack-plugin@1.4.3
├─ terser@4.6.3
├─ thread-loader@2.1.3
├─ through2@2.0.5
├─ timers-browserify@2.0.11
├─ to-arraybuffer@1.0.1
├─ to-fast-properties@1.0.3
├─ to-object-path@0.3.0
├─ to-regex-range@2.1.1
├─ traverse@0.6.6
├─ ts-pnp@1.1.6
├─ tslib@1.11.0
├─ tty-browserify@0.0.0
├─ type@1.2.0
├─ typedarray-to-buffer@3.1.5
├─ typedarray@0.0.6
├─ unfetch@4.1.0
├─ unicode-canonical-property-names-ecmascript@1.0.4
├─ unicode-match-property-ecmascript@1.0.4
├─ unicode-match-property-value-ecmascript@1.1.0
├─ unicode-property-aliases-ecmascript@1.0.5
├─ union-value@1.0.1
├─ unique-filename@1.1.1
├─ unique-slug@2.0.2
├─ unpipe@1.0.0
├─ unset-value@1.0.0
├─ upath@1.2.0
├─ uri-js@4.2.2
├─ url-polyfill@1.1.7
├─ url@0.11.0
├─ use-subscription@1.1.1
├─ use@3.1.1
├─ util-deprecate@1.0.2
├─ uuid@3.4.0
├─ validate-npm-package-license@3.0.4
├─ vary@1.1.2
├─ vm-browserify@1.1.2
├─ watchpack@2.0.0-beta.5
├─ wcwidth@1.0.1
├─ webpack-dev-middleware@3.7.0
├─ webpack-hot-middleware@2.25.0
├─ webpack-log@2.0.0
├─ webpack-merge@4.2.2
├─ webpack-sources@1.4.3
├─ webpack@4.41.2
├─ wide-align@1.1.3
├─ worker-farm@1.7.0
├─ worker-rpc@0.1.1
├─ write-file-atomic@3.0.1
├─ xtend@4.0.2
├─ y18n@4.0.0
└─ yallist@3.1.1
✨  Done in 10.63s.

$ mkdir -p src/pages
$ yarn add --save-dev typescript @types/react @types/node
yarn add v1.22.0
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > next@9.2.2" has unmet peer dependency "react@^16.6.0".
warning "next > styled-jsx@3.2.4" has unmet peer dependency "react@15.x.x || 16.x.x".
warning "next > use-subscription@1.1.1" has unmet peer dependency "react@^16.8.0".
warning " > react-dom@16.12.0" has unmet peer dependency "react@^16.0.0".
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 4 new dependencies.
info Direct dependencies
├─ @types/node@13.7.4
└─ @types/react@16.9.22
info All dependencies
├─ @types/node@13.7.4
├─ @types/prop-types@15.7.3
├─ @types/react@16.9.22
└─ csstype@2.6.9
✨  Done in 2.02s.

$ yarn add react       
yarn add v1.22.0
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ react@16.12.0
info All dependencies
└─ react@16.12.0
✨  Done in 1.73s.

$ yarn run dev
yarn run v1.22.0
$ next
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
It looks like you're trying to use TypeScript but do not have the required package(s) installed.

Please install typescript by running:

    yarn add --dev typescript

If you are not trying to use TypeScript, please remove the tsconfig.json file from your package root (and any TypeScript files).

error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

$ yarn add --dev typescript
yarn add v1.22.0
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ typescript@3.8.2
info All dependencies
└─ typescript@3.8.2
✨  Done in 2.02s.

tsconfig.json や、 next.config.js 、public/sw.js などは各自調べて追加してください。(ぉぃ

f:id:poad1010:20200222201750p:plain

地味に大変なので、テンプレートリポジトリー化しています。

github.com

2. amplify の導入

オフィシャルドキュメント https://aws-amplify.github.io/docs/ のとおり、CLIインストールと設定を行います。

npm install -g @aws-amplify/cli
amplify configure

AWS 管理コンソールが起動して、使うリージョンだとか、amplify を管理するための(?) IAM ユーザーの作成などをターミナルに表示されたメッセージに従って行います。

3. アプリケーションへの適用

3.1. nom モジュールのインストール

amplify には色々な AWS サービスを使うための npm モジュールがあるようですが、今回は以下の 3つを使用します。

  • aws-amplify
  • @aws-amplify/auth
  • aws-amplify-react
yarn add aws-amplify @aws-amplify/auth aws-amplify-react

3.2. amplify アプリの初期化

3.2.1. amplify init
amplify init

を実行すると、プロジェクト名や使用するエディター、環境名などの選択や入力を求められます。 指示に従って進めると、バックエンドコードが出力されます。

これは、後ほど amplify コマンドで使うことになる CloudFormation テンプレートや CloudFormation Stack などです。

$ amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project next-amplify-example
? Enter a name for the environment dev
? Choose your default editor: Visual Studio Code
? 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:  yarn build
? Start Command: yarn start
Using default provider  awscloudformation

For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html

? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use amplify
Adding backend environment dev to AWS Amplify Console app: d1ntmmvoqyxue2
⠏ Initializing project in the cloud...

CREATE_IN_PROGRESS DeploymentBucket                        AWS::S3::Bucket            Sat Feb 22 2020 19:27:48 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UnauthRole                              AWS::IAM::Role             Sat Feb 22 2020 19:27:47 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS AuthRole                                AWS::IAM::Role             Sat Feb 22 2020 19:27:47 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UnauthRole                              AWS::IAM::Role             Sat Feb 22 2020 19:27:46 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS DeploymentBucket                        AWS::S3::Bucket            Sat Feb 22 2020 19:27:46 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS AuthRole                                AWS::IAM::Role             Sat Feb 22 2020 19:27:46 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 19:27:43 GMT+0900 (日本標準時) User Initiated             
⠼ Initializing project in the cloud...

CREATE_COMPLETE UnauthRole AWS::IAM::Role Sat Feb 22 2020 19:28:01 GMT+0900 (日本標準時) 
CREATE_COMPLETE AuthRole   AWS::IAM::Role Sat Feb 22 2020 19:28:01 GMT+0900 (日本標準時) 
⠼ Initializing project in the cloud...

CREATE_COMPLETE DeploymentBucket AWS::S3::Bucket Sat Feb 22 2020 19:28:08 GMT+0900 (日本標準時) 
⠦ Initializing project in the cloud...

CREATE_COMPLETE amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 19:28:11 GMT+0900 (日本標準時) 
✔ Successfully created initial AWS cloud resources for deployments.
✔ Initialized provider successfully.
Initialized your environment successfully.

Your project has been successfully initialized and connected to the cloud!

Some next steps:
"amplify status" will show you what you've added already and if it's locally configured or deployed
"amplify add <category>" will allow you to add features like user login or a backend API
"amplify push" will build all your local backend resources and provision it in the cloud
“amplify console” to open the Amplify Console and view your project status
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

Pro tip:
Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything
import React from 'react'

class Home extends React.Component {
  render() {
    return (
      <div>

        <div className="hero">
          <h1 className="title">Welcome to Next.js!</h1>
          <p className="description">
            To get started, edit <code>pages/index.js</code> and save to reload.
          </p>

          <div className="row">
            <a href="https://nextjs.org/docs" className="card">
              <h3>Documentation &rarr;</h3>
              <p>Learn more about Next.js in the documentation.</p>
            </a>
            <a href="https://nextjs.org/learn" className="card">
              <h3>Next.js Learn &rarr;</h3>
              <p>Learn about Next.js by following an interactive tutorial!</p>
            </a>
            <a
              href="https://github.com/zeit/next.js/tree/master/examples"
              className="card"
            >
              <h3>Examples &rarr;</h3>
              <p>Find other example boilerplates on the Next.js GitHub.</p>
            </a>
          </div>
        </div>

        <style jsx>{`
          .hero {
            width: 100%;
            color: #333;
          }
          .title {
            margin: 0;
            width: 100%;
            padding-top: 80px;
            line-height: 1.15;
            font-size: 48px;
          }
          .title,
          .description {
            text-align: center;
          }
          .row {
            max-width: 880px;
            margin: 80px auto 40px;
            display: flex;
            flex-direction: row;
            justify-content: space-around;
          }
          .card {
            padding: 18px 18px 24px;
            width: 220px;
            text-align: left;
            text-decoration: none;
            color: #434343;
            border: 1px solid #9b9b9b;
          }
          .card:hover {
            border-color: #067df7;
          }
          .card h3 {
            margin: 0;
            color: #067df7;
            font-size: 18px;
          }
          .card p {
            margin: 0;
            padding: 12px 0 0;
            font-size: 13px;
            color: #333;
          }
        `}</style>
      </div>
    )
  }
}

export default Home

f:id:poad1010:20200222190051p:plain

3.2.2. amplify add auth

amplify から Cognito を使用して認証するため、 amplify add auth を行います。 多分、Cognito 以外も使えそうですが、今回は Cognito を使うために追加するとお考えください。

amplify add auth

こんな感じです。今回はザルセキュリティで良い(あくまでもサンプルなので)ので、ユーザー名とパスワードでのみの認証とします。 (本来なら、メールアドレス他、色々と設定すべきでしょう)

$ amplify add auth
Using service: Cognito, provided by: awscloudformation
 
 The current configured provider is Amazon Cognito. 
 
 Do you want to use the default authentication and security configuration? Default configuration
 Warning: you will not be able to edit these selections. 
 How do you want users to be able to sign in? Username
 Do you want to configure advanced settings? No, I am done.
Successfully added resource nextamplifyexample6c8f8585 locally

Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

3.3. amplify バックグラウンド(AWS側のリソース)の構築

"amplify push" will build all your local backend resources and provision it in the cloud とあるように、AWS側のリソースを構築する必要があります。

amplify push

を実行すると、CloudFormation スタックが更新されて ネステッドスタックとなります。 また、Cognito のリソースが作られます。

$ amplify push    
✔ Successfully pulled backend environment dev from the cloud.

Current Environment: dev

| Category | Resource name              | Operation | Provider plugin   |
| -------- | -------------------------- | --------- | ----------------- |
| Auth     | nextamplifyexample0dde88af | Create    | awscloudformation |
? Are you sure you want to continue? Yes
⠏ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS authnextamplifyexample0dde88af          AWS::CloudFormation::Stack Sat Feb 22 2020 19:37:35 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS authnextamplifyexample0dde88af          AWS::CloudFormation::Stack Sat Feb 22 2020 19:37:34 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS UpdateRolesWithIDPFunctionRole          AWS::IAM::Role             Sat Feb 22 2020 19:37:34 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UpdateRolesWithIDPFunctionRole          AWS::IAM::Role             Sat Feb 22 2020 19:37:33 GMT+0900 (日本標準時)                            
UPDATE_IN_PROGRESS amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 19:37:29 GMT+0900 (日本標準時) User Initiated             
⠴ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS amplify-next-amplify-example-dev-192739-authnextamplifyexample0dde88af-1PWQ9Y8ZW1F9F AWS::CloudFormation::Stack Sat Feb 22 2020 19:37:35 GMT+0900 (日本標準時) User Initiated
⠇ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS SNSRole AWS::IAM::Role Sat Feb 22 2020 19:37:40 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS SNSRole AWS::IAM::Role Sat Feb 22 2020 19:37:40 GMT+0900 (日本標準時)                            
⠴ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE UpdateRolesWithIDPFunctionRole AWS::IAM::Role Sat Feb 22 2020 19:37:48 GMT+0900 (日本標準時) 
⠹ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE SNSRole AWS::IAM::Role Sat Feb 22 2020 19:37:55 GMT+0900 (日本標準時) 
⠼ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UserPool AWS::Cognito::UserPool Sat Feb 22 2020 19:37:58 GMT+0900 (日本標準時) 
⠸ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE    UserPool AWS::Cognito::UserPool Sat Feb 22 2020 19:38:01 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS UserPool AWS::Cognito::UserPool Sat Feb 22 2020 19:38:01 GMT+0900 (日本標準時) Resource creation Initiated
⠴ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE    UserPoolClient    AWS::Cognito::UserPoolClient Sat Feb 22 2020 19:38:06 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS UserPoolClient    AWS::Cognito::UserPoolClient Sat Feb 22 2020 19:38:05 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_COMPLETE    UserPoolClientWeb AWS::Cognito::UserPoolClient Sat Feb 22 2020 19:38:05 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS UserPoolClientWeb AWS::Cognito::UserPoolClient Sat Feb 22 2020 19:38:05 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UserPoolClient    AWS::Cognito::UserPoolClient Sat Feb 22 2020 19:38:04 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS UserPoolClientWeb AWS::Cognito::UserPoolClient Sat Feb 22 2020 19:38:04 GMT+0900 (日本標準時)                            
⠇ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UserPoolClientRole AWS::IAM::Role Sat Feb 22 2020 19:38:10 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UserPoolClientRole AWS::IAM::Role Sat Feb 22 2020 19:38:09 GMT+0900 (日本標準時)                            
⠸ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE UserPoolClientRole AWS::IAM::Role Sat Feb 22 2020 19:38:24 GMT+0900 (日本標準時) 
⠸ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE    UserPoolClientLambda AWS::Lambda::Function Sat Feb 22 2020 19:38:28 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS UserPoolClientLambda AWS::Lambda::Function Sat Feb 22 2020 19:38:27 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UserPoolClientLambda AWS::Lambda::Function Sat Feb 22 2020 19:38:27 GMT+0900 (日本標準時)                            
⠹ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UserPoolClientLambdaPolicy AWS::IAM::Policy Sat Feb 22 2020 19:38:31 GMT+0900 (日本標準時) 
⠼ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UserPoolClientLambdaPolicy AWS::IAM::Policy Sat Feb 22 2020 19:38:32 GMT+0900 (日本標準時) Resource creation Initiated
⠇ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE UserPoolClientLambdaPolicy AWS::IAM::Policy Sat Feb 22 2020 19:38:45 GMT+0900 (日本標準時) 
⠧ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UserPoolClientLogPolicy AWS::IAM::Policy Sat Feb 22 2020 19:38:49 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UserPoolClientLogPolicy AWS::IAM::Policy Sat Feb 22 2020 19:38:48 GMT+0900 (日本標準時)                            
⠹ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UserPoolClientInputs    Custom::LambdaCallout Sat Feb 22 2020 19:39:05 GMT+0900 (日本標準時) 
CREATE_COMPLETE    UserPoolClientLogPolicy AWS::IAM::Policy      Sat Feb 22 2020 19:39:03 GMT+0900 (日本標準時) 
⠹ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE    UserPoolClientInputs Custom::LambdaCallout Sat Feb 22 2020 19:39:09 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS UserPoolClientInputs Custom::LambdaCallout Sat Feb 22 2020 19:39:09 GMT+0900 (日本標準時) Resource creation Initiated
⠦ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE    IdentityPool AWS::Cognito::IdentityPool Sat Feb 22 2020 19:39:14 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS IdentityPool AWS::Cognito::IdentityPool Sat Feb 22 2020 19:39:13 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS IdentityPool AWS::Cognito::IdentityPool Sat Feb 22 2020 19:39:12 GMT+0900 (日本標準時)                            
⠦ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE    IdentityPoolRoleMap AWS::Cognito::IdentityPoolRoleAttachment Sat Feb 22 2020 19:39:20 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS IdentityPoolRoleMap AWS::Cognito::IdentityPoolRoleAttachment Sat Feb 22 2020 19:39:20 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS IdentityPoolRoleMap AWS::Cognito::IdentityPoolRoleAttachment Sat Feb 22 2020 19:39:18 GMT+0900 (日本標準時)                            
⠙ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE amplify-next-amplify-example-dev-192739-authnextamplifyexample0dde88af-1PWQ9Y8ZW1F9F AWS::CloudFormation::Stack Sat Feb 22 2020 19:39:22 GMT+0900 (日本標準時) 
⠋ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE authnextamplifyexample0dde88af AWS::CloudFormation::Stack Sat Feb 22 2020 19:39:29 GMT+0900 (日本標準時) 
⠏ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UpdateRolesWithIDPFunction AWS::Lambda::Function Sat Feb 22 2020 19:39:31 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS UpdateRolesWithIDPFunction AWS::Lambda::Function Sat Feb 22 2020 19:39:30 GMT+0900 (日本標準時)                            
⠹ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS UpdateRolesWithIDPFunctionOutputs Custom::LambdaCallout Sat Feb 22 2020 19:39:33 GMT+0900 (日本標準時) 
CREATE_COMPLETE    UpdateRolesWithIDPFunction        AWS::Lambda::Function Sat Feb 22 2020 19:39:31 GMT+0900 (日本標準時) 
⠼ Updating resources in the cloud. This may take a few minutes...

UPDATE_COMPLETE                     amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 19:39:39 GMT+0900 (日本標準時)                            
UPDATE_COMPLETE_CLEANUP_IN_PROGRESS amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 19:39:39 GMT+0900 (日本標準時)                            
CREATE_COMPLETE                     UpdateRolesWithIDPFunctionOutputs       Custom::LambdaCallout      Sat Feb 22 2020 19:39:37 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS                  UpdateRolesWithIDPFunctionOutputs       Custom::LambdaCallout      Sat Feb 22 2020 19:39:36 GMT+0900 (日本標準時) Resource creation Initiated
✔ All resources are updated in the cloud

ここまでで、Cognito を呼び出す下地は出来ました。

あとは、アプリのコードから amplify を使って Cognito を呼び出すだけです!

3.4. アプリへの組み込み

React & React Native

に従って組み込んでみましょう!

因みに、今回は pages/index.tsx へ組み込みました。 Layout など、components 配下のコンポーネントを必ず組み込むようにする場合は、そちらに記述した方が良いかもしれません。

import Amplify from 'aws-amplify';
import config from '../aws-exports';

Amplify.configure(config);

class Home extends React.Component {

  render() {
    return (
      <div>

// 以下略

続いて pages/_app.tsx

import * as React from 'react';
import App from 'next/app';
import { withAuthenticator } from 'aws-amplify-react';

class MyApp extends App {
    render() {
        const { Component, pageProps } = this.props;
        return (<Component {...pageProps} />)
    }
}

export default withAuthenticator(MyApp)

さぁ!これで yarn run dev すっぞ!

$ yarn run dev
yarn run v1.22.0
$ next
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
[ error ] ./node_modules/@aws-amplify/ui/dist/style.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Location: node_modules/aws-amplify-react/lib-esm/Amplify-UI/Amplify-UI-Components-React.js

はい。。。コケました。

Next.js project fails to build, Unexpected token : at dist/style.css · Issue #3854 · aws-amplify/amplify-js · GitHub が原因のようですね。

@zeit/next-css を追加して、 next.config.js を修正すれば良いようです。

$ yarn add -D @zeit/next-css
yarn add v1.22.0
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "aws-amplify > @aws-amplify/api@2.1.5" has incorrect peer dependency "@aws-amplify/pubsub@^1.2.4".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/analytics@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/api@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/auth@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/core@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/interactions@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/storage@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/ui@^2.0.0".
warning "@zeit/next-css > css-loader@1.0.0" has unmet peer dependency "webpack@^4.0.0".
warning "@zeit/next-css > mini-css-extract-plugin@0.4.3" has unmet peer dependency "webpack@^4.4.0".
[4/4] 🔨  Building fresh packages...
warning "@zeit/next-css" is already in "dependencies". Please remove existing entry first before adding it to "devDependencies".
success Saved 1 new dependency.
info Direct dependencies
└─ @zeit/next-css@1.0.1
info All dependencies
└─ @zeit/next-css@1.0.1
✨  Done in 1.85s.
const withCSS = require("@zeit/next-css");
if (typeof require !== "undefined") {
  require.extensions[".less"] = () => {};
  require.extensions[".css"] = (file) => {};
}

const config = {
  target: process.env.NODE_ENV !== 'production' ? 'server' : 'serverless',
  dontAutoRegisterSw: false,
  generateSw: false,
  devSwSrc: 'src/public/sw.js',
  workboxOpts: {
    swSrc: 'src/public/sw.js',
    swDest: 'src/public/service-worker.js'
  }
}

module.exports = withCSS(config)

としました。

$ yarn run dev                                      
yarn run v1.22.0
$ next
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
[ info ]  bundled successfully, waiting for typecheck results...
[ wait ]  compiling ...
[ info ]  bundled successfully, waiting for typecheck results...
[ ready ] compiled successfully - ready on http://localhost:3000
[ event ] build page: /next/dist/pages/_error
[ wait ]  compiling ...
[ info ]  bundled successfully, waiting for typecheck results...
[ ready ] compiled successfully - ready on http://localhost:3000
[ event ] build page: /
[ wait ]  compiling ...
[ info ]  bundled successfully, waiting for typecheck results...
[ ready ] compiled successfully - ready on http://localhost:3000
[ info ]  bundled successfully, waiting for typecheck results...
[ ready ] compiled successfully - ready on http://localhost:3000

エラーがなくなりました。

http://localhost:3000 へアクセスしましょう。

f:id:poad1010:20200222205857p:plain

きたー!

f:id:poad1010:20200222205857p:plain

ユーザー登録(Create account をクリック)時に入力したメールアドレスに以下のようなワンタイムトークンが送られてくるため、 f:id:poad1010:20200222211622p:plain 遷移した画面で入力します。

すると。。。

f:id:poad1010:20200222205857p:plain

に戻ります。

ここで、登録したユーザー名とパスワードを入力して SIGN IN をクリックするとログイン出来ます。

4. サインアウト機能

さて、ここまでで Amplify と Cognitoを使用して、ローカルでサインイン出来るようになりました。

でも、サインアウト出来るようにしておかないとダメですよね?(滅多に使わないから期間過ぎたら自動的にサインアウトするように Cognito を設定しておけばよくね?というツッコミは無しで)

テキストリンクでも良いのですが、ボタンを配置してみましょう。

Material UI コンポーネントを追加します。

yarn add @material-ui/core @material-ui/icons
$ yarn add @material-ui/core @material-ui/icons   
yarn add v1.22.0
[1/4] 🔍  Resolving packages...
warning @material-ui/core > popper.js@1.16.1: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "@zeit/next-css > css-loader@1.0.0" has unmet peer dependency "webpack@^4.0.0".
warning "@zeit/next-css > mini-css-extract-plugin@0.4.3" has unmet peer dependency "webpack@^4.4.0".
warning "aws-amplify > @aws-amplify/api@2.1.5" has incorrect peer dependency "@aws-amplify/pubsub@^1.2.4".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/analytics@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/api@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/auth@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/core@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/interactions@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/storage@^2.0.0".
warning " > aws-amplify-react@3.1.6" has unmet peer dependency "@aws-amplify/ui@^2.0.0".
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 21 new dependencies.
info Direct dependencies
├─ @material-ui/core@4.9.3
└─ @material-ui/icons@4.9.1
info All dependencies
├─ @emotion/hash@0.7.4
├─ @material-ui/core@4.9.3
├─ @material-ui/icons@4.9.1
├─ @material-ui/styles@4.9.0
├─ @material-ui/system@4.9.3
├─ @types/react-transition-group@4.2.3
├─ convert-css-length@2.0.1
├─ css-vendor@2.0.7
├─ dom-helpers@5.1.3
├─ hoist-non-react-statics@3.3.2
├─ hyphenate-style-name@1.0.3
├─ is-in-browser@1.1.3
├─ jss-plugin-camel-case@10.0.4
├─ jss-plugin-default-unit@10.0.4
├─ jss-plugin-global@10.0.4
├─ jss-plugin-nested@10.0.4
├─ jss-plugin-props-sort@10.0.4
├─ jss-plugin-rule-value-function@10.0.4
├─ jss-plugin-vendor-prefixer@10.0.4
├─ popper.js@1.16.1
└─ react-transition-group@4.3.0
✨  Done in 5.88s.

index.tsx には以下のように追加します。

Authentication

に記載されている通り、 Auth モジュールの signOut() を呼び出せば良いだけですね。

import React from 'react'
import Amplify, { Auth } from 'aws-amplify';
import config from '../aws-exports';
import Button from '@material-ui/core/Button';
import ExitToAppIcon from '@material-ui/icons/ExitToApp';

Amplify.configure(config);

class Home extends React.Component {

  logout() {
    Auth.signOut()
    .then(data => console.log(data))
    .catch(err => console.log(err));
  }

  render() {
    return (
      <div>
        <Button
          onClick={this.logout}
          variant="contained"
          color="primary"
          startIcon={<ExitToAppIcon />}
        >
          SIGN OUT
        </Button>

// (以下略)

f:id:poad1010:20200222213531p:plain

はい、出来ました。

5. amplify アプリの publish までの道のり

実は未だ、amplify アプリの publish は出来ません。

$ amplify publish

Please add hosting to your project before publishing your project
Command: amplify hosting add

5.1. amplify hosting add

amplify hosting add を行うと、以下のように聞かれます。

$ amplify hosting add
? Select the environment setup: (Use arrow keys)
❯ DEV (S3 only with HTTP) 
  PROD (S3 with CloudFront using HTTPS) 

とりえず、DEV を選択してCloudFront経由にしないようにして進めます。

$ amplify publish
✔ Successfully pulled backend environment dev from the cloud.

Current Environment: dev

| Category | Resource name              | Operation | Provider plugin   |
| -------- | -------------------------- | --------- | ----------------- |
| Hosting  | S3AndCloudFront            | Create    | awscloudformation |
| Auth     | nextamplifyexample0dde88af | No Change | awscloudformation |
? Are you sure you want to continue? (Y/n) 

何か、CloudFront の文字が見えるような… まぁ、無料枠ならお金かからないから良いや。

$ amplify publish
✔ Successfully pulled backend environment dev from the cloud.

Current Environment: dev

| Category | Resource name              | Operation | Provider plugin   |
| -------- | -------------------------- | --------- | ----------------- |
| Hosting  | S3AndCloudFront            | Create    | awscloudformation |
| Auth     | nextamplifyexample0dde88af | No Change | awscloudformation |
? Are you sure you want to continue? Yes
⠹ Updating resources in the cloud. This may take a few minutes...

UPDATE_COMPLETE    authnextamplifyexample0dde88af          AWS::CloudFormation::Stack Sat Feb 22 2020 21:46:27 GMT+0900 (日本標準時)                            
UPDATE_IN_PROGRESS authnextamplifyexample0dde88af          AWS::CloudFormation::Stack Sat Feb 22 2020 21:46:26 GMT+0900 (日本標準時)                            
CREATE_IN_PROGRESS hostingS3AndCloudFront                  AWS::CloudFormation::Stack Sat Feb 22 2020 21:46:26 GMT+0900 (日本標準時) Resource creation Initiated
CREATE_IN_PROGRESS hostingS3AndCloudFront                  AWS::CloudFormation::Stack Sat Feb 22 2020 21:46:25 GMT+0900 (日本標準時)                            
UPDATE_IN_PROGRESS amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 21:46:22 GMT+0900 (日本標準時) User Initiated             
⠇ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS amplify-next-amplify-example-dev-192739-hostingS3AndCloudFront-153OK6UCXJPBA AWS::CloudFormation::Stack Sat Feb 22 2020 21:46:26 GMT+0900 (日本標準時) User Initiated
⠋ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS S3Bucket AWS::S3::Bucket Sat Feb 22 2020 21:46:29 GMT+0900 (日本標準時) 
⠋ Updating resources in the cloud. This may take a few minutes...

CREATE_IN_PROGRESS S3Bucket AWS::S3::Bucket Sat Feb 22 2020 21:46:30 GMT+0900 (日本標準時) Resource creation Initiated
⠙ Updating resources in the cloud. This may take a few minutes...

CREATE_COMPLETE amplify-next-amplify-example-dev-192739-hostingS3AndCloudFront-153OK6UCXJPBA AWS::CloudFormation::Stack Sat Feb 22 2020 21:46:53 GMT+0900 (日本標準時) 
CREATE_COMPLETE S3Bucket                                                                     AWS::S3::Bucket            Sat Feb 22 2020 21:46:52 GMT+0900 (日本標準時) 
⠹ Updating resources in the cloud. This may take a few minutes...

UPDATE_COMPLETE_CLEANUP_IN_PROGRESS amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 21:47:02 GMT+0900 (日本標準時) 
CREATE_COMPLETE                     hostingS3AndCloudFront                  AWS::CloudFormation::Stack Sat Feb 22 2020 21:47:00 GMT+0900 (日本標準時) 
⠋ Updating resources in the cloud. This may take a few minutes...

UPDATE_COMPLETE amplify-next-amplify-example-dev-192739 AWS::CloudFormation::Stack Sat Feb 22 2020 21:47:03 GMT+0900 (日本標準時) 
UPDATE_COMPLETE authnextamplifyexample0dde88af          AWS::CloudFormation::Stack Sat Feb 22 2020 21:47:03 GMT+0900 (日本標準時) 
✔ All resources are updated in the cloud

Hosting endpoint: http://next-amplify-example-20200222214113-hostingbucket-dev.s3-website-us-west-2.amazonaws.com

yarn run v1.22.0
$ next build
Creating an optimized production build  

Compiled with warnings.

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/require.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/require.js
Critical dependency: the request of a dependency is an expression

Automatically optimizing pages  

Page                                                           Size     First Load
┌ ○ /                                                          256 kB       608 kB
└   /_app                                                      46.4 kB      315 kB
+ shared by all                                                315 kB
  ├ static/_buildManifest.js                                   189 B
  ├ static/pages/_app.js                                       46.4 kB
  ├ chunks/242e76a06b3fa367d89c78b62af50ae3b459294c.a43009.js  11.7 kB
  ├ chunks/29107295.d41bbf.js                                  24.5 kB
  ├ chunks/c277677ab6f8ae068064b60157bc6d3cd2fd2c95.ea5b2a.js  173 kB
  ├ chunks/commons.af9b44.js                                   13 kB
  ├ chunks/framework.74d547.js                                 40.8 kB
  ├ chunks/styles.15b445.js                                    87 B
  ├ runtime/main.e744f1.js                                     4.74 kB
  └ runtime/webpack.4b444d.js                                  746 B

λ  (Lambda)  server-side renders at runtime (uses getInitialProps or getServerProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

✨  Done in 15.16s.
frontend build command exited with code 0

Cannot find the distribution folder.
Distribution folder is currently set as:
  /Users/ken-yo/next-amplify-example/build

Cannot find the distribution folder.
Error: Cannot find the distribution folder.
    at Object.scan (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-hosting/lib/S3AndCloudFront/helpers/file-scanner.js:38:11)
    at Object.run (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-hosting/lib/S3AndCloudFront/helpers/file-uploader.js:16:32)
    at Object.publish (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-hosting/lib/S3AndCloudFront/index.js:116:6)
    at Object.runServiceAction (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-hosting/lib/category-manager.js:63:31)
    at Object.publish (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-hosting/index.js:69:30)
    at publishToHostingBucket (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-frontend-javascript/lib/publisher.js:22:30)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

コケて上手く行きません…

build ディレクトリーが無いと言われてますね。

以下のように修正しました。

{
  "name": "next-amplify-example",
  "version": "1.0.0",
  "private": true,
  "license": "MIT",
  "scripts": {
    "test": "jest --passWithNoTests",
    "dev": "next",
    "build": "next build && next export && rm -rf build && mv out build",
    "start": "next start",
    "lint": "eslint --ext .ts,.js,.tsx,.jsx src"
  },
  "lint-staged": {
    "src/*.{ts,js,tsx,jsx}": "eslint"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "dependencies": {
    "@material-ui/core": "^4.9.3",
    "@material-ui/icons": "^4.9.1",
    "@types/node": "^13.7.4",
    "@types/react": "^16.9.22",
    "@zeit/next-css": "^1.0.1",
    "aws-amplify": "^2.2.5",
    "aws-amplify-react": "^3.1.6",
    "next": "^9.2.2",
    "react": "^16.12.0",
    "react-dom": "^16.12.0"
  },
  "devDependencies": {
    "typescript": "^3.8.2"
  }
}

"build": "next build && next export && rm -rf build && mv out build" がポイントですね。

$ amplify publish
✔ Successfully pulled backend environment dev from the cloud.

Current Environment: dev

| Category | Resource name              | Operation | Provider plugin   |
| -------- | -------------------------- | --------- | ----------------- |
| Auth     | nextamplifyexample0dde88af | No Change | awscloudformation |
| Hosting  | S3AndCloudFront            | No Change | awscloudformation |

No changes detected
yarn run v1.22.0
$ next build && next export && mv out build
Creating an optimized production build  

Compiled with warnings.

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/load-components.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/require.js
Critical dependency: the request of a dependency is an expression

./node_modules/next/dist/next-server/server/require.js
Critical dependency: the request of a dependency is an expression

Automatically optimizing pages  

Page                                                           Size     First Load
┌ ○ /                                                          256 kB       608 kB
└   /_app                                                      46.4 kB      315 kB
+ shared by all                                                315 kB
  ├ static/_buildManifest.js                                   189 B
  ├ static/pages/_app.js                                       46.4 kB
  ├ chunks/29107295.6cce3a.js                                  24.5 kB
  ├ chunks/5d3dd53bfefaaba7d132131a0ba097ceb6bf38d5.961381.js  11.7 kB
  ├ chunks/79d124448b8210c46ac0124c1c9c03bef3930399.ea5b2a.js  173 kB
  ├ chunks/commons.af9b44.js                                   13 kB
  ├ chunks/framework.74d547.js                                 40.8 kB
  ├ chunks/styles.15b445.js                                    87 B
  ├ runtime/main.d64045.js                                     4.74 kB
  └ runtime/webpack.4b444d.js                                  746 B

λ  (Lambda)  server-side renders at runtime (uses getInitialProps or getServerProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

> using build directory: /Users/ken-yo/next-amplify-example/.next
  copying "static build" directory
> No "exportPathMap" found in "next.config.js". Generating map from "./pages"
  launching 15 workers
Exporting (5/5)

Export successful
✨  Done in 11.93s.
frontend build command exited with code 0
✔ Uploaded files successfully.
Your app is published successfully.
http://next-amplify-example-20200222214113-hostingbucket-dev.s3-website-us-west-2.amazonaws.com

f:id:poad1010:20200222225034p:plain

出来ました!

ただ、 GitHub - poad/next-ts-template のブランチを元に作成した場合、next.config.js を次のように修正しないと、 aws-amplify-react の Global Stylesheet 関連の処理やら styled-jsx やらとの兼ね合いでコケました。(styled-jsx は結果的に使っていないので yarn remove しました)

因みに、 yarn run dev ではコケずに yarn build でだけコケるとかあったのでご注意を!

const withCSS = require('@zeit/next-css')
if (typeof require !== "undefined") {
  require.extensions[".less"] = () => { };
  require.extensions[".css"] = (file) => { };
}

const resolve = require('resolve')
global.navigator = () => null
const config = {
  webpack(config, options) {
    const { dir, isServer } = options
    config.externals = []
    if (isServer) {
      config.externals.push((context, request, callback) => {
        resolve(request, { basedir: dir, preserveSymlinks: true }, (err, res) => {
          if (err) {
            return callback()
          }
          if (
            res.match(/node_modules[/\\].*\.css/)
            && !res.match(/node_modules[/\\]webpack/)
            && !res.match(/node_modules[/\\]@aws-amplify/)
          ) {
            return callback(null, `css ${request}`)
          }

          callback()
        })
      })
    }

    return config
  }
}

module.exports = withCSS(config)

と、なかなかハマりどころ多いですが、Nuxt.js(Vue.js) + TypeScript + amplify よりは簡単そうです。

next.config.js の修正が不味いケース

その1

$ yarn build
yarn run v1.22.0
$ next build
Creating an optimized production build  

Compiled successfully.

Automatically optimizing pages ..Service Worker Loaded...
> Build error occurred
ReferenceError: self is not defined
    at Object.C+qz (/Users/ken-yo/git/es-examples/next-examples/next-amplify-example/.next/server/static/23FhuuakIG-ehoL-uwoCM/pages/sw.js:108:1)
    at __webpack_require__ (/Users/ken-yo/git/es-examples/next-examples/next-amplify-example/.next/server/static/23FhuuakIG-ehoL-uwoCM/pages/sw.js:23:31)
    at Object.3 (/Users/ken-yo/git/es-examples/next-examples/next-amplify-example/.next/server/static/23FhuuakIG-ehoL-uwoCM/pages/sw.js:99:18)
    at __webpack_require__ (/Users/ken-yo/git/es-examples/next-examples/next-amplify-example/.next/server/static/23FhuuakIG-ehoL-uwoCM/pages/sw.js:23:31)
    at /Users/ken-yo/git/es-examples/next-examples/next-amplify-example/.next/server/static/23FhuuakIG-ehoL-uwoCM/pages/sw.js:91:18
    at Object.<anonymous> (/Users/ken-yo/git/es-examples/next-examples/next-amplify-example/.next/server/static/23FhuuakIG-ehoL-uwoCM/pages/sw.js:94:10)
    at Module._compile (internal/modules/cjs/loader.js:1151:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1171:10)
    at Module.load (internal/modules/cjs/loader.js:1000:32)
    at Function.Module._load (internal/modules/cjs/loader.js:899:14) {
  type: 'ReferenceError'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

とりあえず、next.config.js の中の記述で service worker周りの設定を削って、上述の一番最後に書いた next.config.js へ置き換えてみてください。

その2

$ yarn run dev
yarn run v1.22.0
$ next
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
> Using external babel configuration
> Location: "/Users/ken-yo/git/es-examples/next-examples/next-amplify-example/.babelrc"
[ error ] ./node_modules/@aws-amplify/ui/dist/style.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Location: node_modules/aws-amplify-react/lib-esm/Amplify-UI/Amplify-UI-Components-React.js

Next.js 公式では非推奨の @zeit/next-css を追加して…という上述の記事に記載している next.config.js を設定してください。

今回作成したサンプルコード

github.com

テンプレートリポジトリーをベースにしたもの

github.com