PHPカンファレンス関西2024に参加して、オフラインカンファレンスの盛り上がりを体験してきた
Sunday, February 18, 2024 12:40:00 PM
大阪自体はそれほど久しぶりではないけど、東京以外のカンファレンスにリアル参加するのは久しぶりだった。 ブログを振り返ると、PHPカンファレンス沖縄2019で、 標準インターフェースを使ったアプリケーション開発について発表してきましたがコロナ前最後に参加した地域PHP conであったようだ。 大阪へは藤井風のパナスタライブ以来なので、1年半ぶりぐらい。
このところのホテル事情
昨年秋のシルバーウィークに九州まで車でスカイラインを巡る旅をしてきて、ホテルの混雑状況とか把握していたつもりでしたが、今回はやばかった。 ちょうど3連休開催ということで、ホテルの値段がやばい。大阪ではいつも宿泊する本町のホテルが早々に売り切れててどうしよう?となりましたが、 運よくリニューアルしたばかりの東横inn淀屋橋駅南が空いてて、普段の東横価格だったので安心できました。
前夜祭への参加
さらに前日入りをすることにしていたのですが、午前中に東京で用事があったので 【非公式!前夜祭】 PHPカンファレンス関西2024 へも新幹線に乗るタイミングで間に合いそうだったので参加表明するという慌ただしさ。
前夜祭で他の人の発表を聞いていて、自分も何か話したいなーという欲が出てきたので、その場でスライドをさくさくと作ってWebアクセシビリティの話をしました。 いろいろなところで4月から義務化?!とか言われてますが、実際のところどうなのよ?みたいなところを。 最新関係する仕事もしていてかなり調べたので、気になっている人もいるのでは?と思ったのです。
かつてはカンファレンスを開催していた大阪産業創造館という場所も懐かしかった。
前夜祭を楽しんだ後は、最近大阪に来たら必ずいく Bar で飲んでちゃんと終電ではホテルに戻りました。
カンファレンス当日
今回はあまり普段登壇で見かけない人の発表を聞く、久しぶりに会うコミュニティメンバーと会話する、という2つの目的で参加していました。 どちらも当初の見込みは達成できて、たくさんの刺激をもらいました。 午後は主にアンカンファレンスの会場にいて、枠も空いていたので前夜祭で話した内容をまたやってみたりと、聞くだけでなく積極的にイベントにも参加しました。 ちゃんとスポンサークイズにも応募したよ!(半分ぐらいは聴けてなかったので勘で回答しちゃいましたがw)
懇親会 -> 2次会 -> ホテルそばで1人3次会 をやって終了。 翌日の月曜日も3連休ということで休みでしたが、東京で推しのライブがあるのでお昼には新幹線に乗り込みました。 いつものネギ焼きは新幹線のフードコードで
いつもの(本店ではないが pic.twitter.com/YfGW0D6zAf
— しずひこ (@sizuhiko) February 12, 2024
あ、その前にもちろん聖地巡礼(阪急梅田のタイガースショップ)もして、グッズも買いました。
久しぶりの地域カンファレンスに参加してのまとめ
昨年のPHPカンファレンス福岡に始まり、地域カンファレンスの開催も戻ってきて、今回の大阪に久しぶりに参加しました。 大阪のPHPcon自体は PHPカンファレンス関西2018に参加してGAEに継続的デプロイする方法について発表してきました のとき以来で、今回はこのときの登壇者Tシャツを来て参加しました。
つまり関西では 6年ぶりということですね。 オフライン開催のPHP系カンファレンスに関しても昨年の福岡などより前となると、おそらく PHPerKaigi 2020で「E2Eテストに向き合う」ついて発表してきました このときの PHPerKaigi がコロナ前最後であったという記憶があります。
それでも4年。 つまり6年以上前からコミュニティに参加していた関西圏の人以外はほぼ初参加となるわけです。
今年は月刊PHPカンファレンスなんて言葉が出るぐらいですが、それも昨年の福岡に始まった地域カンファレンスの楽しさから触発されたもので、しばらく行われてこなかった反動だったり、この4から6年の間に新たにこの業界で働き始めた人たちの新しい交流の場なんだなというのを実感しました。
今回のPHPCon関西ではいくつもの素晴らしい取り組みがありました。
- 公式 note で発信
- PHPerシール
- お誘いチケット
- おすすめトーク診断
まず公式 note は X だけで発信していると流れてしまいそうな情報に簡単にアクセスできるのもあり、良いなーと思いました。 困ったら note 見る、みたいな動線がある。もちろん公式HPに載せるのもありなんで、そこは運用の手間がどちらが少ないかという判断もあるでしょう。
続いて PHPerシール。こちらは2020のPHPerKaigiで行われていたトレーディングカードにインスパイアされたものだと思いますが、積極的に交流できるようにするアイテムとしてとても良いと思いました。スピーカーにはレアカードがあったりしたのも良かったと思います。
お誘いチケットは有料イベントで参加を迷っている人を誘いやすい仕組みとして良いなと思いました。 PHPerシールとか当日の交流の仕組みがあっても、まず参加してくれないと届きませんね。
おすすめトーク診断も、誘ってもらったり紹介してもらったので参加するけど、カンファレンスの歩き方ってわからんな?という人も向けて楽しみながら参加できる仕掛けだったと思います。
つまりPHP関西自体に初参加、ましてやコロナで勉強会を含めオフラインのイベントそのものに初参加ということが6年というブランクから容易に想像できる環境での地域コミュニティの盛り上げ方に優れた戦略が練られていたことがわかります。
- お誘いチケットで誘って参加してもらい
- おすすめトーク診断で当日迷わないようにして
- PHPer シールで当日は交流してもらう
- なんなら X のアカウント持ってなかったけど、シール経由で作ってもらって今後の交流やPHP関西からの発信を受け取ってもらえるようにする
委員長の閉会の挨拶でもこれらを話されていましたが、関西でのPHPコミュニティを盛り上げたいという熱い想いを聞いて、また来年開催されたら参加したいな、発表もしてみたいなと思いました。
久しぶりということで運営の経験値とかもリセットされた中での開催だったと思うけど、そういうのを感じさせない良いカンファレンスでした。 参加のみなさま、久しぶりに再会したみなさま。そして何より運営のみなさまありがとうございました。
マルチプルレポをモノレポへコミットログを残しながら移行する
Wednesday, September 27, 2023 05:25:00 PM
背景
プロジェクトで複数のAPIサーバーや、マイクロサービスなどを展開するのに、OpenAPI の定義を置くリポジトリを個々に作っていたのですが、メンテナンス性を考えてマルチプルレポからモノレポへ移行することにしました。
基本的に OpenAPI の定義(yamlファイル)の内容と、デプロイ先(AWS S3のWebホスティング先バケット)が違うぐらいで、それ以外の内容はまったく一緒であるリポジトリが複数ある感じです。
- app-a-apidoc
- app-b-apidoc
- service-account-apidoc
- service-payment-apidoc
みたいなマルチプルレポを apidoc
モノレポへまとめていきます。
各 apidoc は swagger-ui-dist に yaml ファイルを入れて、Webホスティングしている S3 バケットにデプロイしています。 ビルドスクリプトは gulp で、デプロイは serverless framework に serverless-s3-sync プラグインを入れて実行しています。
リポジトリの移行の準備
リポジトリを移行するにあたり Keeping git history when converting multiple repos into a monorepo という記事がとても役にたったので、こちらの手順を参考にして紹介していきます。
ディレクトリ構造決定
まず最初にモノレポ移行後のディレクトリ構造を検討します。 よくある npm のパッケージをモノレポにしている場合だと
packages
+-- package-a
+-- package-b
みたいな階層にすることが多いんじゃないかな?と思います。
参考記事だと projects/*
のような感じですね。
aws-sdk v3 だと clients や lib, packages など目的別にいろいろ分けているようです。
そこで今回私たちは
apps
+-- a
+-- b
services
+-- account
+-- payment
みたいなディレクトリ構造にしました。これはそれぞれのプロジェクトや、まとめたいリポジトリにもよるので、個別に検討しましょう。
既存リポジトリのディレクトリ変更
ディレクトリ構造が決まったら、既存リポジトリをそのディレクトリに合わせて階層を変更します。
cd app-a-apidoc
mkdir -p apps/a
git mv -k * apps/a
git mv -k .* apps/a
git commit -m "chore: move all files into apps/a"
- 既存リポジトリをチェックアウトしたディレクトリに移動
- モノレポにしたときのディレクトリツリーを作成
- 2のディレクトリ下にすべてのファイルを移動。移動には
git mv
コマンドを使う - コミット
この作業を移行対象のすべての既存リポジトリで実施していきます。
モノレポの作成
GitHub上でリポジトリを作ってチェックアウトするか、 git init
コマンドでローカルにモノレポのフォルダを準備します。
続いて、モノレポリポジトリにワークスペースのルートディレクトリを作っておきます。
mkdir apps
mkdir services
git remote add
を使ってローカルディレクトリのリポジトリ(既存リポジトリのディレクトリ変更でディレクトリ変更してコミットしたもの)を追加します。
git remote add -f app-a-apidoc ../app-a-apidoc
git remote add -f app-b-apidoc ../app-b-apidoc
git remote add -f service-account-apidoc ../service-account-apidoc
git remote add -f service-payment-apidoc ../service-payment-apidoc
で、それらをモノレポの中にマージしていきます。マージするブランチが main
であると仮定します。
git merge app-a-apidoc/main --allow-unrelated-histories
git merge app-b-apidoc/main --allow-unrelated-histories
git merge service-account-apidoc/main --allow-unrelated-histories
git merge service-payment-apidoc/main --allow-unrelated-histories
最後にリモートを削除しましょう。
git remote remove app-a-apidoc
git remote remove app-b-apidoc
git remote remove service-account-apidoc
git remote remove service-payment-apidoc
モノレポの設定
ここまでで既存のリポジトリを1つのモノレポにコミットログ付きで合体できました。 続いて、モノレポで開発作業ができるように環境整備をしましょう。
ワークスペースを設定する
モノレポのルートディレクトリで npm init
コマンドを実行して package.json
を作ります。
作成した package.json
にワークスペースに関する設定を追加します。
"private": true,
"workspaces": [
"apps/*",
"services/*"
],
依存関係の設定
続いて、各リポジトリで使っていた devDependencies
や dependencies
の依存関係をモノレポのルートディレクトリにある package.json
に移動します。
通常は各リポジトリ共通のものだけですが、今回の apidoc ではすべて共通だったので、そのままコピペしました。
ワークスペース(apps や services)にある package.json
の devDependencies
や dependencies
を削除し、 package-lock.json
も削除します。
最後にルートディレクトリで npm i
を実行して依存関係をインストールします。
各 apidoc の整理
.npmrc
や .gitignore
, .editorconfig
など必要な設定ファイルをワークスペースからルートディレクトリに移動しておきます。
その他共通になったものはルートディレクトリ下に移動しておくと良いでしょう。
GitHub Actions の統合
ワークスペース(apps や services)にある .github
をどれかルートディレクトリに移動して、ワークスペース側からは削除します。
単に全部のワークスペースをビルドしたりデプロイするだけなら -ws
オプションを追加するとすべてのワークスペースに対してコマンドを実行するようになります。
steps:
- uses: actions/checkout@v3
- run: npm ci
- run: npm run -ws build
- run: npm run -ws deploy
まぁでも通常はそんなことなく、以下のパターンを考慮する必要があります。
- ルートディレクトリの package.json で定義している依存関係にアップデートがあった(dependabotなど)
- ワークスペースのファイルが修正された
前者はすべてのワークスペースに対して Action を実行したほうが良いのですが、後者は変更があったワークスペースだけの実行に絞り込みたいところです。
そこで利用できるのが Get changed workspaces action です。
jobs:
get-changed-workspaces:
outputs:
packages: ${{ steps.changed-packages.outputs.packages }}
empty: ${{ steps.changed-packages.outputs.empty }}
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Find changed workspaces
uses: AlexShukel/get-changed-workspaces-action@v2.0.0
id: changed-packages
deploy:
needs: [get-changed-workspaces]
if: ${{ !fromJson(needs.get-changed-workspaces.outputs.empty) }}
strategy:
matrix:
package: ${{ fromJson(needs.get-changed-workspaces.outputs.packages) }}
steps:
- uses: actions/checkout@v3
- run: npm ci
- run: npm run -w ${{ matrix.package.name }} build
- run: npm run -w ${{ matrix.package.name }} deploy
この Action を使うと変更があったワークスペースの名前を配列型式で取得できます。
ワークスペースに変更がないときは empty
でわかるので、 if
文で制御して何もしないように設定も可能です。
で、特定のワークスペースに対して npm コマンドを実行したい場合は -w ワークスペース名
オプションを指定します。
そこで、 .github/workflows
には以下のファイルを設置することにしました。
- build-all.yml
- build.yml
前者は ルートディレクトリの package.json で定義している依存関係にアップデートがあった(dependabotなど)
を想定していて、以下のような条件で起動したら、 -ws
オプションですべてのワークスペースで実行されるようにしています。
on:
workflow_dispatch:
push:
paths:
- package.json
- package-lock.json
branches:
- master
jobs:
deploy:
steps:
- uses: actions/checkout@v3
- run: npm ci
- run: npm run -ws build
- run: npm run -ws deploy
後者は Get changed workspaces action
を使って個別のワークスペースビルドされるように設定しました。
さいごに
マルチプルレポ、モノレポ、それぞれに良いところはあると思います。 必ずモノレポが良いというものでもないでしょう。 それぞれのプロジェクトやリポジトリの運用を見極めて選択していきたいですね。
マルチプルレポからモノレポへ移行するときに、本記事が参考になれば幸いです。
tsyringe を TypeScript 5 で使う方法
Tuesday, May 02, 2023 03:00:00 PM
tsyringe は、Microsoft のオーガナイゼーションにある、JavaScript/TypeScript用のDIコンテナです。
Microsoft は TypeScript の親だし、DIコンテナあるんだったら使うよなーというぐらいの理由で使っていましたが、ここ数年はアップデートのリリースがありません。 この記事を書いている時点での最新版は、2020/11/9 に出た v4.4.0 です。
TypeScript 5 でコンパイルエラーになる
tsyringe を TypeScript 5 で利用しようとすると、コンパイルエラーになります。 で、さすがに利用者が多いライブラリだけあって、すぐ issue TypeScript 5.0 Support of tighter parameter decorator checking が出ました。 しばらくしたら PR fix: allow propertyKey to be undefined も出ました。PRが 2023/3/26 に出て、マージされたのは 2023/4/17 です。
それから2週間ぐらい経過しましたが、リリースされる気配はありません….
でも TypeScript 5 を使いたいんや
まぁそう思いますよね。 僕らのプロジェクトでもそう思ったんで、パッチを作りました。
プロジェクトルート(package.json とか置いているディレクトリ)に tsyringe.d.ts
を置いて、型定義をオーバーライドする感じです。
例えば以下のような感じです。
import tsyringe = require('tsyringe/dist/typings/index');
declare namespace t {
function inject(
token: tsyringe.InjectionToken<any>
): (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) => any;
const injectable: typeof tsyringe.injectable;
const container: typeof tsyringe.container;
type DependencyContainer = typeof tsyringe.container;
}
export = t;
まずコンパイルエラーになるのは inject
関数なので、それをオーバーライドします。
次に、プロジェクトで import している関数や型があれば、それぞれ const
や type
で宣言して require した内容からそのまま export するようにしました。
これはマージされている PR が型定義ぐらいしか修正しておらず、実装に関しては何も修正されていなかったので、問題なしと判断して型定義だけをオーバーライドしたパッチを作ることにしました。
で、どうなの?
現時点動作に問題はなく、普通に TypeScript 5 で tsyringe が使えています。 PRがマージされて、すぐリリースされるんじゃないか?と思ったので、この内容を記事にする必要もないかな?と思っていたのですが、 リリースされる気配を感じないので、僕らのやっている方法が少しでも役に立てばと思い、記事にしました。 はやく TypeScript 5 対応が正式リリースされて欲しいですね。
LocalStack を使って aws-sdk の Integration Test を実行する
Wednesday, April 19, 2023 04:12:00 PM
AWS Lambda の Node.js 14 を 18 に移行する(aws-sdk v3 移行編) の中でも書いたように、aws-sdk v3 を使ったコードを UnitTest するには AWS SDK v3 Client mock を利用してモックした方が簡単です。
一方で少し IntegrationTest をしたいと思うこともあるでしょう。そうしたときは LocalStack の利用が便利です。 手元も環境なら Docker の Extension で動きます。 CI 環境、たとえば GitHub Actions ならサービスでコンテナ起動すれば大丈夫です。
インテグレーションテストでのエンドポイント
こんな感じでテストコードで endpoint を切り替えられるようにしておくとローカルとCI環境のどちらでもテストを実行しやすくなります。
const options = {
credentials: { accessKeyId: 'dummy', secretAccessKey: 'summy' },
endpoint: `http://${process.env.TEST_AWS_HOSTNAME ?? 'localhost'}:4566`,
region: 'ap-northeast-1',
};
const stepFunctions = new SFNClient(options);
手元では localhost で良いし、CI環境(たとえば GitHub Actions ) なら、以下のようにしておくと良いです。
container: node:18
services:
localstack:
image: localstack/localstack
env:
TEST_AWS_HOSTNAME: localstack
steps:
- run: npm t
LocalStack v2.0 以降での変更点
最近バージョンが 2.0 になった LocalStack ですが Lambda 関連で大きな変更がありました。 基本的に Lambda を利用しなければ問題はありませんが、特に問題なければ localstack サービスを以下のように設定しておくと安心です。
container: node:18
services:
localstack:
image: localstack/localstack
env:
LAMBDA_SYNCHRONOUS_CREATE: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Actions のホストコントローラの docker.sock をマウントすることで LocalStack の中で Lambda が起動できるようになります。
詳しくは公式の v2.0.0 リリースノート の Lambda
部分に書いてありますので、読んでみてください。
さいごに
単体テストで LocalStack 使うのはやりすぎだと思いますが、部分的にインテグレーションテストしたい、といった場合には有用な方法かな、と思いますので、用途に応じて使い分けられると良いですね。
AWS SDK v3 のモジュールと利用方法
Tuesday, April 18, 2023 12:21:00 PM
このところ何度か aws-sdk v3 について記事を書いてきましたが、こちらは現時点でのベストプラクティスというか、追記を含むまとめ記事になります。
ランタイムに含まれないモジュールがある?
aws-sdk を使って Lambda から Lambda を実行するときのコードは、公式のExampleコードを見ると以下のようになっています。
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
import { InvokeCommand, LambdaClient, LogType } from "@aws-sdk/client-lambda";
import { createClientForDefaultRegion } from "../../libs/utils/util-aws-sdk.js";
/** snippet-start:[javascript.v3.lambda.actions.Invoke] */
const invoke = async (funcName, payload) => {
const client = createClientForDefaultRegion(LambdaClient);
const command = new InvokeCommand({
FunctionName: funcName,
Payload: JSON.stringify(payload),
LogType: LogType.Tail,
});
const { Payload, LogResult } = await client.send(command);
const result = Buffer.from(Payload).toString();
const logs = Buffer.from(LogResult, "base64").toString();
return { logs, result };
};
/** snippet-end:[javascript.v3.lambda.actions.Invoke] */
export { invoke };
ここで注目して欲しいのは
Payload: JSON.stringify(payload),
の部分なのですが、これは TypeScript で記述すると型違反でエラーになります。
/**
* <p>The JSON that you want to provide to your Lambda function as input.</p>
* <p>You can enter the JSON directly. For example, <code>--payload '\{ "key": "value" \}'</code>. You can also
* specify a file path. For example, <code>--payload file://payload.json</code>.</p>
*/
Payload?: Uint8Array;
公式 Example のコードの意味とは… というところですが、
で、そういう issue やら SlackOverflow があって
https://github.com/aws/aws-sdk-js-v3/issues/4623
import { InvocationType, InvokeCommand, LambdaClient } from "@aws-sdk/client-lambda";
import { toUint8Array } from "@aws-sdk/util-utf8";
const lambda = new LambdaClient({});
const response = await lambda.send(
new InvokeCommand({
FunctionName: process.env.LAMBDA_ARN as string,
InvocationType: InvocationType.RequestResponse,
Payload: toUint8Array(payload),
}),
);
こんな感じで Uint8Array
に変換する必要があります。
そこで @aws-sdk/util-utf8
を使ったのですが、これが Node.js v18 の Lambda インスタンスだと見つからないとエラーになります。
執筆時点での Lambda インスタンスの sdk バージョンは 3.188.0
以下のページから現在のランタイムに入っている sdk バージョンがわかります。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html
執筆時点では 3.188.0 なので、 GitHub リポジトリでそのタグのコードを見てみると、確かにそんなパッケージはありません。
それどころか、 @aws-sdk/util-utf8-node
と @aws-sdk/util-utf8-browser
という2つのパッケージに分かれていました。
どうも、3.300.0 あたりでパッケージを統合したようです。
NPMのレジストリをみると、
https://www.npmjs.com/package/@aws-sdk/util-utf8-node
Deprecated package
This internal package is deprecated in favor of @aws-sdk/util-utf8.
のように書いてあります。
ちなみに、最新の GitHub リポジトリからは、 util-utf8-node
が完全に削除されています。
状況を整理し、これから発生することを整理
つまり、 3.188.0 で @aws-sdk/util-utf8-node
を使っていて、Lambda の zip に sdk を含めていない人は、ランタイムのアップデートで突然 Lambda が動かなくなる可能性があるということです。
これはセマンティックバージョニングとしては破壊的変更なのでメジャーバージョンアップ相当ですが、そもそも aws-sdk がセマンティックバージョニングされているかどうかはわかりません(たぶんされていない)。
僕は長い間、公式ドキュメント「.zip ファイルアーカイブで Node.js Lambda 関数をデプロイする」に書いてある
関数が標準ライブラリまたは AWS SDK ライブラリにのみ依存する場合は、これらのライブラリを .zip ファイルに含める必要はありません
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/nodejs-package.html
というポリシーを信じていました。 著名な Serverless Framework でもデフォルトの挙動では zip ファイルを作成するときに aws-sdk を除外するようになってます。
道を間違える前に AWS さんに確認してみた
僕の懸念は
- aws-sdk は zip に含めるべきか?
- 後方互換性がなくなる変更があるけど、アップデートの方針はどうなっているか?
というあたりです。
aws-sdk は zip に含めるべきか?
こちらは「はい」が正解ということです。
AWS Lambda 関数を使用するためのベストプラクティス に 関数のデプロイパッケージ内で依存関係を制御します
という部分があり、zip に含めた方が良いとなっています。
しかし aws-sdk のサイズはモジュール化されているとはいえ、Lambdaの上限サイズを考えるとかなりの割合を占めてしまうので、できればランタイムを使いたいとことです。
後方互換性がなくなる変更があるけど、アップデートの方針はどうなっているか?
こちらの回答をふりかえる前に、aws-sdk v3 のモジュール構造について補足しておきます。 GitHub のリポジトリにある README Generated Code] によると以下のとおりです。ざっくり要約しました。
v3 コードベースは、AWSサービスが公開しているモデルから生成されています。 smithy-typescript で
/clients
サブディレクトリ内のコードを生成し、これらのパッケージは @aws-sdk/client-XXXX のような名前になります。クライアントは、
/packages
にあるユーティリティコードに依存します。これらのコードは手動で記述されていて、通常あまり役に立ちません。
/lib
には高レベルのライブラリがあります。 client をラップして操作しやすくするライブラリです。よくある例は@aws-sdk/lib-dynamodb
で Amazon DynamoDB のアイテムの操作を簡素化するものや、@aws-sdk/lib-storage
で S3 の multipartUpload での並列アップロードを簡素化するものです。
続けて、以下のようにも書いてあります。
- /packages 手動でコード更新が行われる場所で、 NPM に @aws-sdk/XXXX で公開されています。特別なプレフィックスはありません。
- /clients このディレクトリのコードは自動生成され、 /packages に依存します。AWS のサービスと 1 対 1 です。通常、手動編集はここでは行わないでください。@aws-sdk/client-XXXX で NPM に公開されます。
- /lib このディレクトリは、 /clients に依存します。既存の AWS サービスと操作をラップして、Javascript での作業を容易にします。@aws-sdk/lib-XXXX で NPM に公開されています。
上記以外にも private というのもあったりしますが、これは名前からも明らかに非公開のモジュールだとわかります。 NPM 公開されていて、僕らが利用することができるものが client / packages / lib にあるといった感じでしょうか。
上記3つのディレクトリについての AWS アップデートポリシーは以下のようなものになるそうです。
- client ユーザーが利用する想定のモジュールであり、破壊的変更は行われない
- lib ユーザーが利用する想定のモジュールであり、破壊的変更は行われない
- package client からの利用を想定している内部モジュールなので破壊的変更の可能性がある(ただしドキュメントに明示されていない)
package に入っているもので、README に利用方法が解説されているもの、たとえば S3 の署名付きURLを発行するためのライブラリ @aws-sdk/s3-request-presigner はユーザーからの利用が想定されていて、破壊的変更は行われないようです。 しかし、README にAPIの解説がないものについては内部利用を想定しているため、破壊的変更もありえると。
後者は private ディレクトリに入れた方が良いのでは?と思わなくはないですが、何か理由があるんでしょうかね。
今回のようにドキュメントに記述がない @aws-sdk/util-utf8-node
を使いたい場合は zip に必ず含むようにしましょう。
それ以外は zip の容量が厳しければ v2 のときと同じようにランタイムに依存する方が良いと思います。aws-sdk の更新頻度がかなり多いので、どれがセキュリティパッチかわからないし、できればランタイムでの更新に期待したいという思いもあります。
さいごに
これまでの aws-sdk v3 / Node.js v18 への移行記事を一覧にしてみます。
- AWS Lambda の Node.js 14 を 18 に移行する(CI/CD環境移行編)
- AWS Lambda の Node.js 14 を 18 に移行する(aws-sdk v3 移行編)
- aws-sdk v3 で TS2345 が出てコンパイルエラーになる
- aws-sdk v3 でコンパイルエラーになる - その2
- Node.js v18 / aws-sdk v3 の Lambda アプリが突然動かなくなる
- aws-sdk v3 を使うライブラリを作ったときは、なるべく peerDependencies に設定しよう
- 本記事
私の思う現時点でのベストプラクティス
- CIのイメージは公式の Lambda Docker イメージが便利
- aws-sdk v3 のユニットテストには aws-sdk-client-mock が良い
- aws-sdk の各モジュールのバージョンは揃えて、なるべく最新を使おう
- aws-sdk 関数/クラス以外、たとえば enum の値などは基本的に利用しない
- peerDependencies に書いてあるモジュールもバージョンを揃えてインストールしよう
- packages にあるドキュメントなしのモジュールを使う場合は、zip に含める
- zip の容量に余裕があれば aws-sdk はすべて含めた方が良い
現時点はかなりクセがあるというか、ノウハウが必要であるというのが現実だと思います。 とくに AWS Lambda + aws-sdk v3 + TypeScript の場合にはですね。
ぶっちゃけ TypeScript でなければコンパイルエラーや型違反についての問題もないし、しいていえば zip に含めるかどうか?ぐらいです。 とはいえ、みんなもう Node.js ランタイム選ぶなら TypeScript 使うだろうと思うので、これまでの記事のノウハウが役に立てば幸いです。
Recent Articles
- PHPカンファレンス関西2024に参加して、オフラインカンファレンスの盛り上がりを体験してきた 2024/02/18
- マルチプルレポをモノレポへコミットログを残しながら移行する 2023/09/27
- tsyringe を TypeScript 5 で使う方法 2023/05/02
- LocalStack を使って aws-sdk の Integration Test を実行する 2023/04/19
- AWS SDK v3 のモジュールと利用方法 2023/04/18
- ts-jest が esbuild/swc をトランスフォーマーに使って高速化していた 2023/04/13
- aws-sdk v3 を使うライブラリを作ったときは、なるべく peerDependencies に設定しよう 2023/04/11
- aws-sdk v2 が 2023 年中にメンテナンスモードになる 2023/04/06
- Node.js v18 / aws-sdk v3 の Lambda アプリが突然動かなくなる 2023/04/05
- aws-sdk v3 でコンパイルエラーになる - その2 2023/04/04