AWS SDK v3をシンプルに使う開発環境

# 概要

小さなWebアプリを作るときにフレームワークを使わずにシンプルに開発環境を作るメモです(いつもJavaScriptのプロジェクトの開始方法を忘れてしまうので)。ドキュメントによると`Amazon Web Services バージョン 3 (V3) はブラウザビルダーをサポートは終了しました`ということで、バンドルが必須になってしまったので、できるだけ簡単に構築してみます。

サンプルとしてAWS SDK v3を使ってS3のオブジェクトを取得するスクリプトを作成します。

## 前提とする環境
Rocky Linux 9.4でmise-en-place環境下のnode.js 22を使いました。

ここでは以下の環境がセットアップされていることを前提とします。

- mise-en-place -- https://mise.jdx.dev/
    - プロジェクト毎の仮想環境を簡単に構築できるプログラムです

使わない場合はnode.js(とgit)があれば使用可能だと思います。

大きな流れとしては以下です。

1. mise環境ファイルを設定
1. esbuildとaws-sdkの必要なものをnpmでインストール
1. HTMLとJSを作成してビルド

# 環境構築
## プロジェクトディレクトリの作成とmise環境の設定

プロジェクトディレクトリを作成し、`.mise.toml`を作成します。

```bash
$ mkdir test-project
$ cd test-project
$ vi .mise.toml
```

```toml:.mise.toml
[tools]
node = "22"
```

## モジュールのインストール

必要なモジュールをインストールします。

```bash
$ npm install esbuild @aws-sdk/client-s3
```

## JavaScriptを書く

ここではAWS SDKで示されている例をそのままファイルにします。

- Amazon S3の例 -- https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html

この例で認証情報にIAMユーザーのアクセスキー情報を入れてあります。通常は`fromCognitoIdentityPool`などを使うべきでしょう。

```javascript:s3test.js
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  credentials: {
    accessKeyId:     "AKEXAMPLEACCESSKEYID",
    secretAccessKey: "ExampleSecretAccessKey0123456789NOTVALID",
  },
  region: "ap-northeast-1",
});

export const getS3Object = async () => {
  const command = new GetObjectCommand({
    Bucket: "mybucket",
    Key:    "test.txt",
  });

  try {
    const response = await client.send(command);
    // The Body object also has 'transformToByteArray' and 'transformToWebStream' methods.
    const str = await response.Body.transformToString();
    console.log(str);
    return str;
  } catch (err) {
    console.error(err);
  }
};
```

## ビルドスクリプトを書く

esbuildを使ってビルドします。以下の例では、即時実行関数式(IIFE)およびESモジュール(ESM)の形式でビルドし、`htdocs`ディレクトリに出力します。IIFEの場合は、通常の`<script src="..."></script>`でファイルを読み込み、`globalName`(ここでは`S3Test`)を介して`export`されたオブジェクトにアクセスします。一方、ESMでは`<script type="module">`を使い、`import { getS3Object } from "./s3test.esm-browser.js";`という形式でインポートします。

```javascript:build.js
const esbuild = require("esbuild");

esbuild.build({
  entryPoints: ["s3test.js"],
  bundle: true,
  outfile: "htdocs/s3test.js",
  platform: "browser",
  format: "iife",       // IIFE形式でバンドル
  globalName: "S3Test", // グローバルオブジェクトに公開
  minify: true,
}).catch(() => process.exit(1));

esbuild.build({
  entryPoints: ["s3test.js"],
  bundle: true,
  outfile: "htdocs/s3test.esm-browser.js",
  platform: "browser",
  format: "esm",        // ESモジュール形式で出力
  minify: true,
}).catch(() => process.exit(1));
```

以下のように実行します。

```bash
$ node build.js
```

これで`htdocs/s3test.js`(IIFE)および`htdocs/s3test.esm-browser.js`(ESM)が出力されます。

## HTML

HTMLからビルドされたファイルを読み込み、使ってみます。

```html:htdocs/index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>AWS SDK v3 Test</title>
</head>
<body>
  <pre id="txtIIFE"></pre>
  <hr>
  <pre id="txtESM"></pre>

  <!-- IIFE形式ファイルを使う -->
  <script src="s3test.js"></script>
  <script>
  (async () => {
    document.querySelector("#txtIIFE").textContent = await S3Test.getS3Object();
  })();
  </script>

  <!-- ESM形式ファイルを使う -->
  <script type="module">
  import { getS3Object } from "./s3test.esm-browser.js";
  (async () => {
    document.querySelector("#txtESM").textContent = await getS3Object();
  })();
  </script>
</body>
</html>
```

## esbuildで開発用Webサーバー

開発用Webサーバーを`package.json`に追加します。

```json:package.json
{
  "scripts": {
    "dev":   "esbuild --servedir=htdocs --serve=0.0.0.0:8000"
  },
  "dependencies": {
    "@aws-sdk/client-s3": "^3.662.0",
    "esbuild": "^0.24.0"
  }
}
```

これでシンプルな開発環境ができました。

# 参考

- AWS SDK v3 デベロッパーガイド
    - JavaScript (v3) に を使用する Amazon S3 の例 SDK
        - https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html
    - ブラウザでの開始方法
        - https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/getting-started-browser.html
- mise-en-place
    - https://mise.jdx.dev/
    - 検索で見つけにくいです。普段は`mise.toml`などで検索するとよいです