TypeScriptとJestサポートの操作:AWSSAMチュートリアル

公開: 2022-03-11

サーバーレスアプリケーションを構築するための強力なツールであるAWSサーバーレスアプリケーションモデル(SAM)は、JavaScriptと頻繁にペアになります。中規模および大規模企業の開発者の62%が、サーバーレスコードにJavaScriptを選択しています。 ただし、TypeScriptの人気は急上昇しており、開発者の3番目に愛されている言語としてJavaScriptをはるかに上回っています。

JavaScriptの定型文を見つけるのは難しいことではありませんが、TypeScriptを使用してAWSSAMプロジェクトを開始することはより複雑です。 次のチュートリアルでは、AWS SAM TypeScriptプロジェクトを最初から作成する方法と、さまざまな部分がどのように連携するかを示します。 読者は、AWSLambda関数にある程度精通している必要があります。

AWSSAMTypeScriptプロジェクトの開始

サーバーレスアプリケーションの基盤には、さまざまなコンポーネントが含まれています。 まず、AWS環境、npmパッケージ、およびWebpack機能を構成します。次に、Lambda関数を作成、呼び出し、テストして、アプリケーションの動作を確認します。

環境を整える

AWS環境をセットアップするには、以下をインストールする必要があります。

  1. AWSCLI
  2. AWS SAM CLI
  3. Node.jsとnpm

このチュートリアルでは、アプリケーションをローカルでテストするために、上記の手順2でDockerをインストールする必要があることに注意してください。

空のプロジェクトを初期化する

プロジェクトディレクトリ、 aws-sam-typescript-boilerplate 、およびコードを保持するsrcサブフォルダーを作成しましょう。 プロジェクトディレクトリから、新しいnpmパッケージを設定します。

 npm init -y # -y option skips over project questionnaire

このコマンドは、プロジェクト内にpackage.jsonファイルを作成します。

Webpack構成を追加する

Webpackは、主にJavaScriptアプリケーションに使用されるモジュールバンドラーです。 TypeScriptはプレーンなJavaScriptにコンパイルされるため、WebpackはWebブラウザー用にコードを効果的に準備します。 2つのライブラリとカスタムローダーをインストールします。

  • webpack:コアライブラリ
  • webpack-cli:Webpackのコマンドラインユーティリティ
  • ts-loader:Webpack用のTypeScriptローダー
npm i --save-dev webpack webpack-cli ts-loader

AWS SAMCLI sam buildコマンドであるsambuildは、関数ごとにnpm installを実行しようとするため、開発プロセスが遅くなり、重複が発生します。 aws-sam-webpack-pluginライブラリの代替ビルドコマンドを使用して、環境を高速化します。

 npm i --save-dev aws-sam-webpack-plugin

デフォルトでは、Webpackは構成ファイルを提供しません。 ルートフォルダにwebpack.config.jsという名前のカスタム設定ファイルを作成しましょう。

 /* eslint-disable @typescript-eslint/no-var-requires */ const path = require('path'); const AwsSamPlugin = require('aws-sam-webpack-plugin'); const awsSamPlugin = new AwsSamPlugin(); module.exports = { entry: () => awsSamPlugin.entry(), output: { filename: (chunkData) => awsSamPlugin.filename(chunkData), libraryTarget: 'commonjs2', path: path.resolve('.') }, devtool: 'source-map', resolve: { extensions: ['.ts', '.js'] }, target: 'node', mode: process.env.NODE_ENV || 'development', module: { rules: [{ test: /\.tsx?$/, loader: 'ts-loader' }] }, plugins: [awsSamPlugin] };

それでは、さまざまな部分を調べてみましょう。

  • entry :これは、 AWS::Serverless::Functionリソースからエントリーオブジェクト(Webpackがバンドルの構築を開始する場所)をロードします。
  • output :これは、ビルド出力の宛先(この場合は.aws-sam/build )を指します。 ここでは、ターゲットライブラリをcommonjs2として指定します。これにより、エントリポイントの戻り値がmodule.exportsに割り当てられます。 このエントリポイントは、Node.js環境のデフォルトです。
  • devtool :これにより、ビルド出力先にソースマップapp.js.mapが作成されます。 元のコードをWebブラウザーで実行されているコードにマップし、環境変数NODE_OPTIONSをLambda --enable-source-mapsに設定するとデバッグに役立ちます。
  • resolve :これは、JavaScriptファイルの前にTypeScriptファイルを処理するようにWebpackに指示します。
  • target :これはWebpackにNode.jsを環境としてターゲットにするように指示します。 これは、Webpackがコンパイル時にチャンクをロードするためにrequire関数を使用することを意味します。
  • module :これは、 test条件を満たすすべてのファイルにTypeScriptローダーを適用します。 つまり、拡張子が.tsまたは.tsxのすべてのファイルがローダーによって処理されるようになります。
  • plugins :これは、Webpackがaws-sam-webpack-plugin識別して使用するのに役立ちます。

最初の行では、このファイルの特定のESLintルールを無効にしています。 後で構成する標準のESLintルールは、 requireステートメントを使用しないようにします。 例外を作成するために、Webpackにimport requireがあります。

TypeScriptサポートを設定する

TypeScriptサポートを追加すると、次の方法で開発者のエクスペリエンスが向上します。

  • 型宣言の欠落に関する警告メッセージの防止。
  • タイプ検証を提供します。
  • IDE内でオートコンプリートを提供します。

まず、プロジェクトのTypeScriptをローカルにインストールします(TypeScriptをグローバルにインストールしている場合は、この手順をスキップしてください)。

 npm i --save-dev typescript

使用しているライブラリのタイプを含めます。

 npm i --save-dev @types/node @types/webpack @types/aws-lambda

次に、プロジェクトルートにTypeScript構成ファイルtsconfig.jsonを作成します。

 { "compilerOptions": { "target": "ES2015", "module": "commonjs", "sourceMap": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, }, "include": ["src/**/*.ts", "src/**/*.js"], "exclude": ["node_modules"] }

ここでは、TypeScriptコミュニティが推奨するデフォルトの構成に従います。 srcフォルダーの下のファイルをプログラムに追加するためのincludeを追加し、 node_modulesフォルダーのTypeScriptコンパイルを回避するためにexcludeを追加しました。このコードには直接触れません。

ラムダ関数を作成する

これまでサーバーレスアプリケーション用のLambdaコードを記述していないので、ジャンプしてみましょう。前に作成したsrcフォルダーに、このLambda関数を使用してapp.tsファイルを含むtest-lambdaサブフォルダーを作成します。

 import { APIGatewayEvent } from 'aws-lambda'; export const handler = async (event: APIGatewayEvent) => { console.log('incoming event is', JSON.stringify(event)); const response = { statusCode: 200, body: JSON.stringify({ message: 'Request was successful.' }) }; return response; };

この単純なプレースホルダー関数は、本文を含む200応答を返します。 もう1つの手順を実行すると、コードを実行できるようになります。

AWSテンプレートファイルを含める

AWS SAMには、コードをトランスパイルしてクラウドにデプロイするためのテンプレートファイルが必要です。 ルートフォルダにファイルtemplate.yamlを作成します。

 AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: AWS SAM Boilerplate Using TypeScript Globals: Function: Runtime: nodejs14.x # modify the version according to your need Timeout: 30 Resources: TestLambda: Type: AWS::Serverless::Function Properties: Handler: app.handler FunctionName: "Test-Lambda" CodeUri: src/test-lambda/ Events: ApiEvent: Type: Api Properties: Path: /test Method: get

このテンプレートファイルは、HTTPGETAPIからアクセス可能なLambda関数を生成します。 Runtime:行で参照されているバージョンはカスタマイズが必要な場合があることに注意してください。

アプリケーションを実行する

アプリケーションを実行するには、Webpackを使用してプロジェクトをビルドするための新しいスクリプトをpackage.jsonファイルに追加する必要があります。 ファイルには、空のテストスクリプトなどの既存のスクリプトが含まれている場合があります。 次のようなビルドスクリプトを追加できます。

 "scripts": { "build": "webpack-cli" }

プロジェクトのルートからnpmrunbuildをnpm run buildと、ビルドフォルダー.aws-samが作成されていることがわかります。 Mac環境にいる私たちの場合、 Command +Shift+を押して隠しファイルを表示する必要があるかもしれません。 フォルダを表示します。

次に、ローカルHTTPサーバーを起動して、機能をテストします。

 sam local start-api

Webブラウザーでテストエンドポイントにアクセスすると、成功メッセージが表示されます。

Webブラウザのアドレスバーに「127.0.0.1:3000/test」というリンクが表示されます。アドレスバーの下では、'{"message":"リクエストが成功しました。"}というメッセージを除いて、ウェブページは空白になっています。

コンソールは、関数が実行される前にDockerコンテナーにマウントされていることを示す必要があります。そのため、以前にDockerをインストールしました。

 Invoking app.handler (nodejs14.x) Skip pulling image and use local one: public.ecr.aws/sam/emulation-nodejs14.x:rapid-1.37.0-x86_64. Mounting /Users/mohammadfaisal/Documents/learning/aws-sam-typescript-boilerplate/.aws-sam/build/TestLambda as /var/task:ro, delegated inside runtime container

プロフェッショナルな設定のための開発ワークフローの強化

私たちのプロジェクトは稼働中であり、いくつかの仕上げを追加することで、生産性とコラボレーションを向上させる優れた開発者エクスペリエンスが保証されます。

ホットリロードでビルドを最適化する

コードを変更するたびにビルドコマンドを実行するのは面倒です。 ホットリロードはこの問題を修正します。 package.jsonに別のスクリプトを追加して、ファイルの変更を監視できます。

 "watch": "webpack-cli -w"

別のターミナルを開き、 npm run watchます。 これで、コードを変更するとプロジェクトが自動的にコンパイルされます。 コードのメッセージを変更し、Webページを更新して、更新された結果を確認します。

ESLintとPrettierでコード品質を向上させる

TypeScriptまたはJavaScriptプロジェクトは、ESLintとPrettierなしでは完成しません。 これらのツールは、プロジェクトのコード品質と一貫性を維持します。

最初にコア依存関係をインストールしましょう:

 npm i --save-dev eslint prettier

ESLintとPrettierがTypeScriptプロジェクトで連携できるように、いくつかのヘルパー依存関係を追加します。

 npm i --save-dev \ eslint-config-prettier \ eslint-plugin-prettier \ @typescript-eslint/parser \ @typescript-eslint/eslint-plugin

次に、プロジェクトルート内にESLint構成ファイル.eslintrcを作成して、リンターを追加します。

 { "root": true, "env": { "es2020": true, "node": true, "jest": true }, "parser": "@typescript-eslint/parser", "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended" ], "ignorePatterns": ["src/**/*.test.ts", "dist/", "coverage/", "test/"], "parserOptions": { "ecmaVersion": 2018, "sourceType": "module", "ecmaFeatures": { "impliedStrict": true } }, "rules": { "quotes": ["error", "single", { "allowTemplateLiterals": true }], "default-case": "warn", "no-param-reassign": "warn", "no-await-in-loop": "warn", "@typescript-eslint/no-unused-vars": [ "error", { "vars": "all", "args": "none" } ] }, "settings": { "import/resolver": { "node": { "extensions": [".js", ".jsx", ".ts", ".tsx"] } } } }

PrettierエラーをESLintエラーとしてエディターに表示するには、ファイルのextendsセクションでPrettierプラグイン構成を最後の行として保持する必要があることに注意してください。 TypeScriptのESLint推奨設定に従い、 rulesセクションにいくつかのカスタム設定を追加します。 利用可能なルールを参照して、設定をさらにカスタマイズしてください。 以下を含めることにしました。

  • 一重引用符で囲まれた文字列を使用しない場合のエラー。
  • switchステートメントにdefaultのケースを指定しない場合の警告。
  • 関数のパラメータを再割り当てした場合の警告。
  • ループ内でawaitステートメントを呼び出した場合の警告。
  • 未使用の変数のエラー。コードが読み取れなくなり、時間の経過とともにバグが発生しやすくなります。

Prettierフォーマットで動作するようにESLint構成をすでにセットアップしました。 (詳細については、 eslint-config-prettier GitHubプロジェクトを参照してください。)これで、Prettier構成ファイル.prettierrcを作成できます。

 { "trailingComma": "none", "tabWidth": 4, "semi": true, "singleQuote": true }

これらの設定は、Prettierの公式ドキュメントからのものです。 必要に応じて変更できます。 次のプロパティを更新しました。

  • trailingComma :末尾のコンマを避けるために、これをes5からnoneに変更しました。
  • semi :各行の最後にセミコロンを付けることを好むため、これをfalseからtrueに変更しました。

最後に、ESLintとPrettierの動作を確認します。 app.tsファイルで、 response変数の型をconstからletに変更します。 この場合、 responseの値を変更しないため、 letを使用することはお勧めできません。 エディターは、エラー、違反したルール、およびコードを修正するための提案を表示する必要があります。 ESLintとPrettierがまだ設定されていない場合は、それらをエディターで有効にすることを忘れないでください。

エディターは、変数「letresponse」に値を割り当てるコード行を表示します。この線の横には黄色の電球が表示され、「応答」という単語には赤い下線とその上にエラーポップアップが表示されます。エラーポップアップは、最初に変数「response」を定義し、「let response:{statusCode:number; body:string;}」と表示します。定義の下に、「'response'は再割り当てされません。代わりに'const'を使用してください。eslint(prefer-const)」というエラーメッセージが表示されます。エラーメッセージの下に、「問題の表示」または「クイック修正」の2つのオプションが表示されます。

Jestテストでコードを維持する

Jest、Mocha、Storybookなど、多くのライブラリをテストできます。 いくつかの理由で、プロジェクトでJestを使用します。

  • 学ぶのは速いです。
  • 最小限のセットアップで済みます。
  • 使いやすいスナップショットテストを提供します。

必要な依存関係をインストールしましょう:

 npm i --save-dev jest ts-jest @types/jest

次に、プロジェクトルート内にJest構成ファイルjest.config.jsを作成します。

 module.exports = { roots: ['src'], testMatch: ['**/__tests__/**/*.+(ts|tsx|js)'], transform: { '^.+\\.(ts|tsx)$': 'ts-jest' } };

ファイル内の3つのオプションをカスタマイズしています。

  • roots :この配列には、テストファイルを検索するフォルダーが含まれていますsrcサブフォルダーの下でのみチェックされます。
  • testMatch :このグロブパターンの配列には、Jestファイルと見なされるファイル拡張子が含まれています。
  • transform :このオプションを使用すると、 ts-jestパッケージを使用してTypeScriptでテストを記述できます。

src/test-lambda内に新しい__tests__フォルダーを作成しましょう。 その中に、ファイルhandler.test.tsを追加します。ここで、最初のテストを作成します。

 import { handler } from '../app'; const event: any = { body: JSON.stringify({}), headers: {} }; describe('Demo test', () => { test('This is the proof of concept that the test works.', async () => { const res = await handler(event); expect(res.statusCode).toBe(200); }); });

package.jsonファイルに戻り、テストスクリプトで更新します。

 "test": "jest"

ターミナルに移動してnpm run testと、合格したテストが表示されます。

コンソールの上部には、緑色の「合格」インジケータとテストファイル名「src / test-lambda / __ tests __/handler.test.ts」が表示されます。次の行は「デモテスト」です。次の行には、緑色のチェックマークが表示され、その後に「これは、テストが機能するという概念実証です。(1ミリ秒)」が続きます。空白行の後、最初の行には「テストスイート:1つ合格、合計1つ」と表示されます。 2番目の読み取り:「テスト:1合格、合計1」。 3番目の読み取り:「スナップショット:合計0」。 4番目の読み取り:「時間:0.959秒」。最後の行には、「すべてのテストスイートを実行しました」と書かれています。

.gitignoreソース管理を処理する

特定のファイルをソース管理から除外するようにGitを構成する必要があります。 gitignore.ioを使用して.gitignoreファイルを作成し、不要なファイルをスキップできます。

 # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* .pnpm-debug.log* # Runtime data pids *.pid *.seed *.pid.lock npm-debug.log package.lock.json /node_modules .aws-sam .vscode # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional ESLint cache .eslintcache

準備、設定、構築:成功のための青写真

これで、TypeScriptを使用した完全なAWSSAMボイラープレートプロジェクトができました。 私たちは、ESLint、Prettier、およびJestのサポートにより、基本を正しく理解し、高いコード品質を維持することに重点を置いてきました。 このAWSSAMチュートリアルの例は、最初から次の大きなプロジェクトを軌道に乗せるための青写真として役立ちます。

Toptal Engineering Blogは、この記事で紹介されているコードサンプルをレビューしてくれたChristianLoefに感謝の意を表します。

「PARTNER」という単語とその下に「AdvancedTierServices」というテキストが付いたAWSロゴ。
アマゾンパートナーネットワーク(APN)の高度なコンサルティングパートナーとして、Toptalは、世界中のどこからでも、オンデマンドでAWS認定のエキスパートへのアクセスを企業に提供します。