Arbeiten mit TypeScript und Jest Support: Ein AWS SAM-Tutorial
Veröffentlicht: 2022-03-11Das AWS Serverless Application Model (SAM) ist ein leistungsstarkes Tool zum Erstellen serverloser Anwendungen und wird häufig mit JavaScript kombiniert: 62 % der Entwickler in mittleren und großen Unternehmen wählen JavaScript für ihren serverlosen Code. TypeScript wird jedoch immer beliebter und übertrifft JavaScript als drittbeliebteste Programmiersprache bei weitem.
Während JavaScript-Boilerplates nicht schwer zu finden sind, ist das Starten von AWS SAM-Projekten mit TypeScript komplexer. Das folgende Tutorial zeigt, wie Sie ein AWS SAM TypeScript-Projekt von Grund auf neu erstellen und wie die verschiedenen Teile zusammenarbeiten. Die Leser müssen nur etwas mit den AWS Lambda-Funktionen vertraut sein, um ihnen folgen zu können.
Starten unseres AWS SAM TypeScript-Projekts
Das Fundament unserer serverlosen Anwendung umfasst verschiedene Komponenten. Wir werden zuerst die AWS-Umgebung, unser npm-Paket und die Webpack-Funktionalität konfigurieren – dann können wir unsere Lambda-Funktion erstellen, aufrufen und testen, um unsere Anwendung in Aktion zu sehen.
Bereiten Sie die Umgebung vor
Um die AWS-Umgebung einzurichten, müssen wir Folgendes installieren:
- AWS-CLI
- AWS-SAM-CLI
- Node.js und npm
Beachten Sie, dass dieses Tutorial die Installation von Docker in Schritt 2 oben erfordert, um unsere Anwendung lokal zu testen.
Initialisieren Sie ein leeres Projekt
Lassen Sie uns das Projektverzeichnis aws-sam-typescript-boilerplate und einen src -Unterordner für Code erstellen. Aus dem Projektverzeichnis richten wir ein neues npm-Paket ein:
npm init -y # -y option skips over project questionnaire Dieser Befehl erstellt eine package.json -Datei in unserem Projekt.
Fügen Sie die Webpack-Konfiguration hinzu
Webpack ist ein Modul-Bundler, der hauptsächlich für JavaScript-Anwendungen verwendet wird. Da TypeScript zu einfachem JavaScript kompiliert wird, bereitet Webpack unseren Code effektiv für den Webbrowser vor. Wir werden zwei Bibliotheken und einen benutzerdefinierten Loader installieren:
- webpack: Core-Bibliothek
- webpack-cli: Befehlszeilenprogramme für Webpack
- ts-loader: TypeScript-Loader für Webpack
npm i --save-dev webpack webpack-cli ts-loader Der AWS SAM CLI-Build-Befehl sam build verlangsamt den Entwicklungsprozess, da er versucht, npm install für jede Funktion auszuführen, was zu Duplikaten führt. Wir werden einen alternativen Build-Befehl aus der aws-sam-webpack-plugin-Bibliothek verwenden, um unsere Umgebung zu beschleunigen.
npm i --save-dev aws-sam-webpack-plugin Standardmäßig stellt Webpack keine Konfigurationsdatei bereit. Lassen Sie uns eine benutzerdefinierte Konfigurationsdatei namens webpack.config.js im Stammordner erstellen:
/* 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] };Lassen Sie uns nun die verschiedenen Teile untersuchen:
-
entry: Dies lädt das Entry-Objekt (wo Webpack mit dem Erstellen des Bundles beginnt) aus derAWS::Serverless::FunctionRessource. -
output: Dies zeigt auf das Ziel der Build-Ausgabe (in diesem Fall.aws-sam/build). Auch hier geben wir alscommonjs2an, die module.exports den Rückgabewert des Einstiegspunktsmodule.exports. Dieser Einstiegspunkt ist der Standard für Node.js-Umgebungen. -
devtool: Dies erstellt eine Quellzuordnung,app.js.map, in unserem Build-Ausgabeziel. Es ordnet unseren ursprünglichen Code dem im Webbrowser ausgeführten Code zu und hilft beim Debuggen, wenn wir die UmgebungsvariableNODE_OPTIONSfür unser Lambda auf--enable-source-maps. -
resolve: Dies weist Webpack an, TypeScript-Dateien vor JavaScript-Dateien zu verarbeiten. -
target: Dies weist Webpack an, Node.js als unsere Umgebung anzuvisieren. Das bedeutet, dass Webpack die Node.jsrequire-Funktion zum Laden von Chunks beim Kompilieren verwendet. -
module: Dies wendet den TypeScript-Loader auf alle Dateien an, die dietesterfüllen. Mit anderen Worten, es stellt sicher, dass alle Dateien mit der Erweiterung.tsoder.tsxvom Loader verarbeitet werden. -
plugins: Dies hilft Webpack, unseraws-sam-webpack-pluginzu identifizieren und zu verwenden.
In der ersten Zeile haben wir eine bestimmte ESLint-Regel für diese Datei deaktiviert. Die standardmäßigen ESLint-Regeln, die wir später konfigurieren werden, entmutigen die Verwendung der require -Anweisung. Wir ziehen es vor, in require zu import , also machen wir eine Ausnahme.
Richten Sie die TypeScript-Unterstützung ein
Das Hinzufügen von TypeScript-Unterstützung verbessert die Entwicklererfahrung durch:
- Warnmeldungen über fehlende Typdeklarationen verhindern.
- Typvalidierung bereitstellen.
- Bietet Autovervollständigung innerhalb der IDE.
Zuerst installieren wir TypeScript für unser Projekt lokal (überspringen Sie diesen Schritt, wenn Sie TypeScript global installiert haben):
npm i --save-dev typescriptWir werden die Typen für die von uns verwendeten Bibliotheken einschließen:
npm i --save-dev @types/node @types/webpack @types/aws-lambda Jetzt erstellen wir die TypeScript-Konfigurationsdatei tsconfig.json im Projektstammverzeichnis:
{ "compilerOptions": { "target": "ES2015", "module": "commonjs", "sourceMap": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, }, "include": ["src/**/*.ts", "src/**/*.js"], "exclude": ["node_modules"] } Hier folgen wir der von der TypeScript-Community empfohlenen Standardkonfiguration. Wir haben „ include “ hinzugefügt, um die Dateien im Ordner „ src “ an das Programm anzuhängen, und „ exclude “, um die TypeScript-Kompilierung für den Ordner „ node_modules “ zu vermeiden – wir werden diesen Code nicht direkt berühren.
Erstellen Sie eine Lambda-Funktion
Wir haben bis jetzt keinen Lambda-Code für unsere serverlose Anwendung geschrieben, also fangen wir an. In dem zuvor erstellten src -Ordner erstellen wir einen test-lambda Unterordner, der eine app.ts -Datei mit dieser Lambda-Funktion enthält:
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; };Diese einfache Platzhalterfunktion gibt eine 200-Antwort mit einem Text zurück. Nach einem weiteren Schritt können wir den Code ausführen.
Schließen Sie die AWS-Vorlagendatei ein
AWS SAM benötigt eine Vorlagendatei, um unseren Code zu transpilieren und in der Cloud bereitzustellen. Erstellen Sie die Datei template.yaml im Stammordner:
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 Diese Vorlagendatei generiert eine Lambda-Funktion, auf die über eine HTTP-GET-API zugegriffen werden kann. Beachten Sie, dass die Version, auf die in der Runtime: verwiesen wird, möglicherweise angepasst werden muss.
Führen Sie die Anwendung aus
Um die Anwendung auszuführen, müssen wir ein neues Skript in der Datei „ package.json “ hinzufügen, um das Projekt mit Webpack zu erstellen. Die Datei enthält möglicherweise vorhandene Skripts, z. B. ein leeres Testskript. Wir können das Build-Skript wie folgt hinzufügen:
"scripts": { "build": "webpack-cli" } Wenn Sie npm run build im Stammverzeichnis des Projekts ausführen, sollte der erstellte Build-Ordner .aws-sam werden. Diejenigen von uns in einer Mac-Umgebung müssen möglicherweise versteckte Dateien sichtbar machen, indem sie Befehlstaste + Umschalttaste + drücken. um den Ordner zu sehen.
Wir werden nun einen lokalen HTTP-Server starten, um unsere Funktion zu testen:
sam local start-apiWenn wir den Testendpunkt in einem Webbrowser besuchen, sollte eine Erfolgsmeldung angezeigt werden.
Die Konsole sollte anzeigen, dass die Funktion in einem Docker-Container gemountet wird, bevor sie ausgeführt wird, weshalb wir Docker früher installiert haben:
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 containerVerbesserung unseres Entwicklungsworkflows für ein professionelles Umfeld
Unser Projekt ist in vollem Gange. Ein paar letzte Handgriffe sorgen für ein außergewöhnliches Entwicklererlebnis, das die Produktivität und Zusammenarbeit steigern wird.

Optimieren Sie den Build mit Hot Reloading
Es ist mühsam, den Build-Befehl nach jeder Codeänderung auszuführen. Heißes Neuladen behebt dieses Problem. Wir können ein weiteres Skript in unserer package.json , um auf Dateiänderungen zu achten:
"watch": "webpack-cli -w" Öffnen Sie ein separates Terminal und führen npm run watch . Jetzt wird Ihr Projekt automatisch kompiliert, wenn Sie Code ändern. Ändern Sie die Nachricht des Codes, aktualisieren Sie Ihre Webseite und sehen Sie sich das aktualisierte Ergebnis an.
Verbessern Sie die Codequalität mit ESLint und Prettier
Kein TypeScript- oder JavaScript-Projekt ist vollständig ohne ESLint und Prettier. Diese Tools erhalten die Codequalität und -konsistenz Ihres Projekts.
Lassen Sie uns zuerst die Kernabhängigkeiten installieren:
npm i --save-dev eslint prettierWir werden einige Hilfsabhängigkeiten hinzufügen, damit ESLint und Prettier in unserem TypeScript-Projekt zusammenarbeiten können:
npm i --save-dev \ eslint-config-prettier \ eslint-plugin-prettier \ @typescript-eslint/parser \ @typescript-eslint/eslint-plugin Als Nächstes fügen wir unseren Linter hinzu, indem wir eine ESLint-Konfigurationsdatei, .eslintrc , im Projektstammverzeichnis erstellen:
{ "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"] } } } } Beachten Sie, dass der Abschnitt „extended“ unserer Datei die extends -Plug-in-Konfiguration als letzte Zeile beibehalten muss, um Prettier-Fehler als ESLint-Fehler anzuzeigen, die in unserem Editor sichtbar sind. Wir folgen den von ESLint empfohlenen Einstellungen für TypeScript, wobei einige benutzerdefinierte Einstellungen im rules hinzugefügt wurden. Fühlen Sie sich frei, verfügbare Regeln zu durchsuchen und Ihre Einstellungen weiter anzupassen. Wir haben uns für Folgendes entschieden:
- Ein Fehler, wenn wir keine Zeichenfolgen in einfachen Anführungszeichen verwenden.
- Eine Warnung, wenn wir in
switchAnweisungen keinendefaultangeben. - Eine Warnung, wenn wir einen Parameter einer Funktion neu zuweisen.
- Eine Warnung, wenn wir eine
await-Anweisung innerhalb einer Schleife aufrufen. - Ein Fehler für ungenutzte Variablen, die den Code mit der Zeit unlesbar und fehleranfällig machen.
Wir haben unsere ESLint-Konfiguration bereits so eingerichtet, dass sie mit Prettier-Formatierung funktioniert. (Weitere Informationen finden Sie im GitHub-Projekt eslint-config-prettier .) Jetzt können wir die Prettier-Konfigurationsdatei .prettierrc :
{ "trailingComma": "none", "tabWidth": 4, "semi": true, "singleQuote": true }Diese Einstellungen stammen aus der offiziellen Dokumentation von Prettier; Sie können sie nach Belieben ändern. Wir haben die folgenden Eigenschaften aktualisiert:
-
trailingComma: Wir haben dies vones5aufnonegeändert, um nachgestellte Kommas zu vermeiden. -
semi: Wir haben dies vonfalseauftruegeändert, weil wir es vorziehen, ein Semikolon am Ende jeder Zeile zu haben.
Endlich ist es an der Zeit, ESLint und Prettier in Aktion zu sehen. In unserer Datei app.ts ändern wir den Typ der response von const in let . Die Verwendung let ist in diesem Fall nicht empfehlenswert, da wir den Wert von response nicht ändern. Der Editor sollte einen Fehler, die fehlerhafte Regel und Vorschläge zur Behebung des Codes anzeigen. Vergessen Sie nicht, ESLint und Prettier in Ihrem Editor zu aktivieren, wenn sie nicht bereits eingerichtet sind.
Pflegen Sie Code mit Jest Testing
Viele Bibliotheken stehen zum Testen zur Verfügung, z. B. Jest, Mocha und Storybook. Wir werden Jest in unserem Projekt aus mehreren Gründen verwenden:
- Es ist schnell zu lernen.
- Es erfordert eine minimale Einrichtung.
- Es bietet benutzerfreundliche Snapshot-Tests.
Lassen Sie uns die erforderlichen Abhängigkeiten installieren:
npm i --save-dev jest ts-jest @types/jest Als Nächstes erstellen wir eine Jest-Konfigurationsdatei, jest.config.js , im Projektstammverzeichnis:
module.exports = { roots: ['src'], testMatch: ['**/__tests__/**/*.+(ts|tsx|js)'], transform: { '^.+\\.(ts|tsx)$': 'ts-jest' } };Wir passen drei Optionen in unserer Datei an:
-
roots: Dieses Array enthält die Ordner, die nach Testdateien durchsucht werden – es prüft nur unterhalb unseressrc-Unterordners. -
testMatch: Dieses Array von Glob-Mustern enthält die Dateierweiterungen, die als Jest-Dateien betrachtet werden. -
transform: Mit dieser Option können wir unsere Tests in TypeScript schreiben, indem wir dasts-jestPaket verwenden.
Lassen Sie uns einen neuen Ordner __tests__ in src/test-lambda erstellen. Darin fügen wir die Datei handler.test.ts , in der wir unseren ersten Test erstellen:
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); }); }); Wir kehren zu unserer Datei package.json und aktualisieren sie mit dem Testskript:
"test": "jest" Wenn wir zum Terminal gehen und npm run test , sollten wir mit einem bestandenen Test begrüßt werden:
Behandeln Sie die Quellcodeverwaltung mit .gitignore
Wir sollten Git so konfigurieren, dass bestimmte Dateien von der Quellcodeverwaltung ausgeschlossen werden. Wir können eine .gitignore -Datei mit gitignore.io erstellen, um nicht benötigte Dateien zu überspringen:
# 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 .eslintcacheAuf die Plätze, fertig, bauen: Unser Erfolgsrezept
Wir haben jetzt ein vollständiges AWS SAM-Boilerplate-Projekt mit TypeScript. Wir haben uns darauf konzentriert, die Grundlagen richtig zu machen und eine hohe Codequalität mit ESLint-, Prettier- und Jest-Support aufrechtzuerhalten. Das Beispiel aus diesem AWS SAM-Tutorial kann als Blaupause dienen, um Ihr nächstes großes Projekt von Anfang an auf Kurs zu bringen.
Der Toptal Engineering Blog dankt Christian Loef für die Durchsicht der in diesem Artikel vorgestellten Codebeispiele.
