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

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

Software development is passion and explosion!

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