【AWS】【Amplify】Can't resolve '@aws-amplify/core/internals/utils

念のため以下コマンド実行

npm install @aws-amplify/ui-react aws-amplify

以下コマンドでcoreを入れる

npm install @aws-amplify/core --save --legacy-peer-deps

→すでにcoreフォルダがあるとのエラー発生 →対象のcoreフォルダを削除して再度実行→インストール成功

さらに以下コマンドを実行し、package.jsonの内容をpackage-lock.jsonに反映させる

npm install

エラーがなくなったことを確認し、起動

npm start

→成功 !!!

【AWS】【Amplify】Downloading release from https://package.cli.amplify.aws/12.10.3/amplify-pkg-win-x64.tgz Error fetching release: Request failed with status code 407

amplifyの最新バージョンをインストールしようと以下コマンドを実行した。

npm install -g @aws-amplify/cli

さっそく「amplify init」を実行してみると以下のようなエラーが。。

Downloading release from https://package.cli.amplify.aws/12.10.3/amplify-pkg-win-x64.tgz
Error fetching release: Request failed with status code 407

たぶん会社のプロキシが原因だとは思うけど、ブラウザからURLをたたくとちゃんとtgzファイルがダウンロードできる。

環境変数を設定しなおしたりあれこれやったけどうまくいかず、結局ブラウザでダウンロードしたtgzファイルを適当なフォルダに解凍してそのファイルを直接実行するやり方で回避した。

C:/amplify/amplify-pkg-win-x64.exe init

※「C:/amplify/amplify-pkg-win-x64.exe」がamplifyの実行ファイルのため、このコマンドで「amplify init」と同じ挙動になる

同じ問題に直面したけどちゃんと解決する時間がない方向けに取り急ぎの解消方法でした。

Proxy環境下でnpmが使えない

会社のProxy環境下でnpmをinstallを実行しようとしたところ、407エラーが出て実行できない。認証情報(ユーザID、パスワード)含めて、ちゃんと以下のコマンドで登録したのになぜだろう。

export http_proxy=http://username:password@10.x.x.x:15080
export https-proxy=http://username:password@10.x.x.x:15080

色々調べてみると、どうやら「http_proxy」「https_proxy」は大文字でないとダメなよう。以下にて登録し直す。

export HTTP_PROXY=http://username:password@10.x.x.x:15080
export HTTPS_PROXY=http://username:password@10.x.x.x:15080

いけました。これくらいうまいことやってくれるのかと思い込んでましたが、こういうこともあるんですね。。

【AWS】DynamoDB CapacityUnitの計算式

AWS Developer Associateの試験で必ず出題されるとDynamoDBのCapacityUnitの計算問題。その計算方法について文章で説明する記事は多くても、その計算式について意外とどこにも掲載されてないので、自分で見出した式をメモ。

RCU(Read Unit Capacity)計算式

◎強力な整合性の場合
(レコードサイズ(KB) ÷ 4(KB: RCUの基準値) x 1(強力な整合性の基準値)) x (レコード数 ÷ 読込時間(秒))

(例)1つあたりのサイズが5KBのレコードを、強力な整合性で1秒間に100個読み込む場合のRCU
(5(KB) ÷ 4(KB) x 1) x (100 ÷ 1(秒))= 200 RCU

◎結果整合性の場合
(レコードサイズ(KB) ÷ 4(KB: RCUの基準値) x 0.5(結果整合性の基準値)) x (レコード数 ÷ 読込時間(秒))

(例)1つあたりのサイズが10KBのレコードを、結果整合性で10分間に6000個読み込む場合のRCU
(10(KB) ÷ 4(KB) x 0.5) x (6000 ÷ 600(秒))= 15 RCU

WCU(Write Unit Capacity)計算式

◎Transactionなしの場合
(レコードサイズ(KB) ÷ 1(KB: WCUの基準値) x 1(Transactionなしの場合の基準値)) x (レコード数 ÷ 読込時間(秒))

(例)1つあたりのサイズが5KBのレコードを、強力な整合性で1秒間に100個書き込む場合のWCU
(5(KB) ÷ 1(KB) x 1) x (100 ÷ 1(秒))= 500 WCU

◎Transactionありの場合
(レコードサイズ(KB) ÷ 1(KB: WCUの基準値) x 2(Transactionありの場合の基準値)) x (レコード数 ÷ 読込時間(秒))

(例)1つあたりのサイズが10KBのレコードを、結果整合性で10分間に6000個書き込む場合のWCU
(10(KB) ÷ 1(KB) x 2) x (6000 ÷ 600(秒))= 200 WCU

【AWS Amplify】amplify add auth -> amplify push | The runtime parameter of nodejs12.x is no longer supported

amplify add authの後、amplify pushをすると何度やってもLambda作成のところで以下のようなエラーが発生。

Resource handler returned message: "The runtime parameter of nodejs12.x is no longer supported for creating or updating AWS Lambda functions. We recommend you use the new runtime (nodejs18.x) while creating or updating functions. (Service: Lambda, S tatus Code: 400

これの解決方法はすでに色んなサイトで回答されていて、amplify cliを以下コマンドにて最新バージョンにすることでnodejs18.x以上のバージョンでLambdaを作成しようとしてくれて、問題なく作成される。

npm install -g @aws-amplify/cli

ところが自分の場合は会社のプロキシ設定の関係で、amplifyを最新バージョンにあげると、amplifyコマンドで以下エラーが発生し、何もできなくなる。

Downloading release from https://package.cli.amplify.aws/12.10.3/amplify-pkg-win-x64.tgz
Error fetching release: Request failed with status code 407

こんなポストも見つけたので、

大文字で環境変数登録してみたけど効果なし。

set HTTP_PROXY=http://username:password@10.0.0.1:8888
set HTTPS_PROXY=http://username:password@10.0.0.1:8888

仕方なく古いバージョンを指定してinstallし直す。

npm uninstall -g @aws-amplify/cli
npm install -g @aws-amplify/cli@7.6.24

するともちろん同じエラーが発生。

Resource handler returned message: "The runtime parameter of nodejs12.x is no longer supported for creating or updating AWS Lambda functions. We recommend you use the new runtime (nodejs18.x) while creating or updating functions. (Service: Lambda, S tatus Code: 400

この環境で解決するしかなので、原因を考えてみる。まず「amplify push」は「amplify add auth」で生成されたCloudFormationのテンプレートをクラウド側で実行する動きをする認識。なので、CloudFormation内のLambda関数部分で「nodejs12」を指定しているところがあるはず。 あった!ここが原因なので、ここを「nodejs18.x」に修正してやるとこのエラーは解消した。

普通はamplify cliのバージョンを最新にするだけで解消するのであまりないケースだとは思いますが、もし同じような境遇の方がいれば参考になれば幸いです。

【AWS】Cloud9からECS ExecでFargateのコンテナにアクセスする

Cloud9からSSM経由でECS上のFargateのコンテナにECS Execを使ってアクセスしたので手順をメモ

Cloud9に「session-manager-plugin」をインストール

デフォルトではこれはインストールされていないので、まずは「session-manager-plugin」をインストールします。Cloud9のOSによってコマンドが違うので、まずはベースとなっているプラットフォームを確認する

確認出来たら以下のリンクから自分のプラットフォームが該当するリンクを押下。今回の自分のケースだと赤枠のリンクになるのでそちらへ移動。

docs.aws.amazon.com

すると「session-manager-plugin」のインストールコマンドがあるので、コピーボタンを押してクリップボードにコピーし、Cloud9のターミナルに貼りつけて実行します。ちなみにAmazon Linux2以降でないと機能しないみたいなので注意。

するとダーっと流れてすぐにインストールが完了。

ECS Execが実行できるようにサービス/タスクの権限/設定を更新

ECSのタスク定義から、「タスクロール」を開きます。※ちなみに「タスク実行ロール」というのはタスクを起動するときに必要な権限を持たせるロールで、「タスクロール」はタスク自体が実行に必要な権限を持たせるロール、という役割の違いがある

「ポリシーを追加」で「AmazonSSMFullAccess」を検索し追加します。

その後Cloud9のターミナルで以下のコマンドを実行して、ECS execを有効化してやる

aws ecs update-service --region ap-northeast-1 --cluster [クラスター名] --service [サービス名] --enable-execute-command

タスクの再起動

ECS execの有効化は既存のタスクには適用されず、設定後新たに起動したタスクでのみ適用されるため、タスクを再起動します。ECSのサービスの画面から「サービスを更新」ボタンを押下し、「新しいデプロイの強制」にチェックを入れて更新します。

タスクが再起動されたらようやく準備完了です。

ECS execでコンテナに入る

まずはアクセスしたいタスクのタスクIDをクリップボードにコピーします。

それからCloud9のターミナルで以下のコマンドを実行([ ]内は自身の環境に合わせて適宜置き換え)。コンテナ名は↑のタスクIDのリンクを押下した先の最下部に書いてます。

aws ecs execute-command --region ap-northeast-1 --cluster [クラスター名] --task [タスク ID] --container [コンテナ名] --interactive --command "/bin/sh"

接続できると以下のようなセッションIDが表示されます。

無事接続できましたでしょうか、お疲れ様でした!

【React】マイ・ベストプラクティス

(2024年2月現在) Reactの記述方法ってこれがベストプラクティス!みたいなのに結構揺れがある言語(ライブラリ)だと思っていて、いろんなところで意見が分かれる議論が交わされてますよね。まだReact歴も浅くちゃんと最初にベストプラクティスを学びたかったのですが、結局こう!というものがないので、自分で考えて選択するしかない、ということで考察してみました。

【React】 vs 【React + Typescript】

上流から行きましょう。まずはJavascriptのまま書くのか、Typescriptで書くのか。これは最近ではもう「ReactはTypescriptで書く方がよい」というのはだいぶ一般化しているのではないでしょうか。理由は言うまでもなくプログラム自体を堅牢に組み立てられるという、Typescriptのメリットそのままですね。なので以後はReact + Typescriptを前提に話を進めていきます。

【Classコンポーネント】vs【Functionコンポーネント

これももうすでに決着がついている議論かもしれませんが、FunctionコンポーネントでHooksがサポートがされてからはClassコンポーネントを利用する必要性がなくなり、公式もFunctionコンポーネントを推奨しているので、Functionコンポーネント一択で良いかと思います。

【普通function】 vs 【アローfunction】

// 普通function
function Hoge () {
  ...
}

// アローfunction
const Hoge = () => {
  ...
}

(この呼び方どうなのってとこは置いておいて)ここからですよね。これ、もう早く誰か結論出してよ!っていうくらい意見が分かれてて、色んな記事読みました。結構国内では比較的モダンで記述が少なくて済むアローfunctionの書き方の方がメジャーなのかなという印象ですが、決定打となるようなプロコンが双方になく、もう「決め」の問題でしかないので、以下の理由からこれに関しては私は「普通function」にします!

正確にはReactのファイルの中で、exportするようなモジュール扱いにする関数は普通functionで定義して、その関数内で使用する単発の関数はアローfunctionで記述する、というルールにします。

理由

    • どの言語を背景に持つ人でも一発で関数とわかる
    • 公式ドキュメントでは軒並み普通functionの表記方法で書かれている
    • exportする関数を普通function、その関数の中で使用する単発の関数をアローfunctionで記述することにより役割分担や「this」の対象を明確にできる

【interface】 vs 【type】

// interface
interface Person {
  name: string;
  age: number;
}

// type
type Person = {
  name: string;
  age: number;
};

これもよく議論が分かれます。よく見るのがinterfaceの方は継承可能で、知らないところで定義が書き変わってしまうリスクがある、またtypeの方がunionやtupleなど扱える型が多いのでとりあえずtypeにしとけ、という意見でしょうか。

これに関しては以下の記事がわかりやすく参考にさせてもらいました。

qiita.com

特にこの部分ですね。

type  :既存の型を用いてオブジェクトの型を定義したい時に使う。  interface  :あるモジュール/まとまった処理に対してIFだけ定義したい場合に使う。   実装は継承クラスに任せる。(Javaの使い方と同じイメージ)

結論としてはひとつ前の関数定義のやり方に付随してくるのですが、exportする関数のPropsの型定義はinterfaceを使用し、それ以外はtypeで定義する、というルールにしたいと思います。

Propsの型定義はexportする関数の外側で宣言すると思いますが、function自体も「=」での代入なしの記述で、Propsの型定義をそれと同じ仕様のinterfaceにすることで、そのファイル直下の定義方法に一貫性を持たせられる。また継承に関しては、同じ機能でフォルダでまとめた範囲なら、同じ型を定義することもある、かつ影響も限定できると思うので、namingなどに注意を払いながらうまく利用すれば、有効的に活用できると思っています。

【React.FC】vs【React.VFC】vs【記述ナシ】

// React.FC
const MyComponent: React.FC<Props> = ({ children, prop1, prop2 }) => {
  return (
    <div>
      {children}
      {/* Component content */}
    </div>
  );
};

// React.VFC
const MyComponent: React.VFC<Props> = ({ prop1, prop2 }) => {
  return (
    <div>
      {/* Component content */}
    </div>
  );
};

// 記述ナシ
const MyComponent = ({ prop1, prop2 }) => {
  return (
    <div>
      {/* Component content */}
    </div>
  );
};

FCでchildrenがデフォルトで渡ってしまうので、childrenを明示的に扱うためVFCが推奨されました => コード修正。FCからchildrenを無くしたのでVFCと同じになりました、なのでVFCはやめてFCを推奨します => コード修正。やってられるかいな!次にどんな気まぐれが降りかかるかわからないので必要に迫られるまでは記述ナシでいきます。

【Props: destructuring(分割代入)しない】or【Props: destructuring(分割代入)する】

// destructing(分割代入)しない
function Listing(props: PropsType) { 
  console.log(props.id);
  console.log(props.name);
  console.log(props.value);
}

// destructuring(分割代入)する
function Listing({ id, name, value }: PropsType) { 
  console.log(id);
  console.log(name);
  console.log(value);
}

これはpropsの中身が多かったりすると特にdestructuringしない方が確かにPropsを受け取る部分はスッキリはするんですが、使われていないpropsがあるかなど、何が渡されているのかやはり明示的にわかった方がよいと言うことで、ここは「destructuring(分割代入)する」でいきたいと思います。


以上、最終的に「時と場合による」という結論付けになることが多いReact設定の争点において、自分はこうする!という意思表示をしてみました。そもそも議論が分かれる議題ではあるので、もしご指摘などあれば頂けると勉強の機会になるので嬉しいです。

Happy Coding!