Utilisation de TypeScript et de la prise en charge de Jest : un didacticiel AWS SAM
Publié: 2022-03-11Outil puissant pour créer des applications sans serveur, le modèle d'application sans serveur AWS (SAM) s'associe fréquemment à JavaScript : 62 % des développeurs de moyennes et grandes entreprises choisissent JavaScript pour leur code sans serveur. Cependant, TypeScript gagne en popularité et dépasse de loin JavaScript en tant que troisième langage le plus apprécié des développeurs.
Bien que le passe-partout JavaScript ne soit pas difficile à trouver, le démarrage de projets AWS SAM avec TypeScript est plus complexe. Le didacticiel suivant montre comment créer un projet AWS SAM TypeScript à partir de zéro, ainsi que la façon dont les différentes parties fonctionnent ensemble. Les lecteurs n'ont besoin que d'une certaine familiarité avec les fonctions AWS Lambda pour suivre.
Démarrage de notre projet AWS SAM TypeScript
Le travail de base de notre application sans serveur comprend divers composants. Nous allons d'abord configurer l'environnement AWS, notre package npm et la fonctionnalité Webpack, puis nous pourrons créer, invoquer et tester notre fonction Lambda pour voir notre application en action.
Préparer l'environnement
Pour configurer l'environnement AWS, nous devons installer les éléments suivants :
- CLI AWS
- CLI AWS SAM
- Node.js et npm
Notez que ce tutoriel nécessite l'installation de Docker lors de l'étape 2 ci-dessus pour tester notre application localement.
Initialiser un projet vide
Créons le répertoire du projet, aws-sam-typescript-boilerplate et un sous-dossier src pour contenir le code. Depuis le répertoire du projet, nous allons configurer un nouveau package npm :
npm init -y # -y option skips over project questionnaire Cette commande créera un fichier package.json dans notre projet.
Ajouter la configuration Webpack
Webpack est un bundler de modules principalement utilisé pour les applications JavaScript. Étant donné que TypeScript compile en JavaScript brut, Webpack préparera efficacement notre code pour le navigateur Web. Nous allons installer deux bibliothèques et un chargeur personnalisé :
- webpack : bibliothèque de base
- webpack-cli : utilitaires de ligne de commande pour Webpack
- ts-loader : chargeur TypeScript pour Webpack
npm i --save-dev webpack webpack-cli ts-loader La commande de génération de l'AWS SAM CLI, sam build , ralentit le processus de développement car elle tente d'exécuter npm install pour chaque fonction, ce qui entraîne une duplication. Nous utiliserons une commande build alternative de la bibliothèque aws-sam-webpack-plugin pour accélérer notre environnement.
npm i --save-dev aws-sam-webpack-plugin Par défaut, Webpack ne fournit pas de fichier de configuration. Créons un fichier de configuration personnalisé nommé webpack.config.js dans le dossier racine :
/* 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] };Examinons maintenant les différentes parties :
-
entry: cela charge l'objet d'entrée (où Webpack commence à créer le bundle) à partir de la ressourceAWS::Serverless::Function. -
output: cela pointe vers la destination de la sortie de génération (dans ce cas,.aws-sam/build). Ici, nous spécifions également la bibliothèque cible en tant quecommonjs2, qui attribue la valeur de retour du point d'entrée àmodule.exports. Ce point d'entrée est le point par défaut pour les environnements Node.js. -
devtool: cela crée une carte source,app.js.map, dans notre destination de sortie de construction. Il mappe notre code d'origine sur le code exécuté dans le navigateur Web et facilitera le débogage si nous définissons la variable d'environnementNODE_OPTIONSsur--enable-source-mapspour notre Lambda. -
resolve: cela indique à Webpack de traiter les fichiers TypeScript avant les fichiers JavaScript. -
target: Cela indique à Webpack de cibler Node.js comme notre environnement. Cela signifie que Webpack utilisera la fonction Node.jsrequirepour charger les morceaux lors de la compilation. -
module: cela applique le chargeur TypeScript à tous les fichiers qui répondent à la condition detest. En d'autres termes, il garantit que tous les fichiers avec une extension.tsou.tsxseront gérés par le chargeur. -
plugins: cela aide Webpack à identifier et à utiliser notreaws-sam-webpack-plugin.
Dans la première ligne, nous avons désactivé une règle ESLint particulière pour ce fichier. Les règles ESLint standard que nous configurerons plus tard découragent l'utilisation de l'instruction require . Nous préférons require d' import dans Webpack, nous ferons donc une exception.
Configurer la prise en charge de TypeScript
L'ajout de la prise en charge de TypeScript améliorera l'expérience du développeur en :
- Empêcher les messages d'avertissement concernant les déclarations de type manquantes.
- Fournir une validation de type.
- Offrant l'auto-complétion à l'intérieur de l'IDE.
Tout d'abord, nous allons installer TypeScript pour notre projet localement (ignorez cette étape si TypeScript est installé globalement) :
npm i --save-dev typescriptNous inclurons les types des bibliothèques que nous utilisons :
npm i --save-dev @types/node @types/webpack @types/aws-lambda Nous allons maintenant créer le fichier de configuration TypeScript, tsconfig.json , à la racine du projet :
{ "compilerOptions": { "target": "ES2015", "module": "commonjs", "sourceMap": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, }, "include": ["src/**/*.ts", "src/**/*.js"], "exclude": ["node_modules"] } Ici, nous suivons la configuration par défaut recommandée par la communauté TypeScript. Nous avons ajouté include pour ajouter les fichiers sous le dossier src au programme et exclude pour éviter la compilation TypeScript pour le dossier node_modules - nous ne toucherons pas directement à ce code.
Créer une fonction Lambda
Nous n'avons pas écrit de code Lambda pour notre application sans serveur jusqu'à présent, alors allons-y. Dans le dossier src que nous avons créé précédemment, nous allons créer un sous-dossier test-lambda contenant un fichier app.ts avec cette fonction 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; };Cette simple fonction d'espace réservé renvoie une réponse 200 avec un corps. Nous pourrons exécuter le code après une étape supplémentaire.
Inclure le fichier de modèle AWS
AWS SAM nécessite un fichier de modèle pour transpiler notre code et le déployer dans le cloud. Créez le fichier template.yaml dans le dossier racine :
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 Ce fichier de modèle génère une fonction Lambda accessible à partir d'une API HTTP GET. Notez que la version référencée sur la ligne Runtime: peut nécessiter une personnalisation.
Exécutez l'application
Pour exécuter l'application, nous devons ajouter un nouveau script dans le fichier package.json pour construire le projet avec Webpack. Le fichier peut contenir des scripts existants, comme un script de test vide. Nous pouvons ajouter le script de construction comme ceci :
"scripts": { "build": "webpack-cli" } Si vous exécutez npm run build à partir de la racine du projet, vous devriez voir le dossier build, .aws-sam , créé. Ceux d'entre nous dans un environnement Mac peuvent avoir besoin de rendre les fichiers cachés visibles en appuyant sur Commande + Maj + . pour voir le dossier.
Nous allons maintenant démarrer un serveur HTTP local pour tester notre fonction :
sam local start-apiLorsque nous visitons le point de terminaison de test dans un navigateur Web, nous devrions voir un message de réussite.
La console doit indiquer que la fonction est montée dans un conteneur Docker avant son exécution, c'est pourquoi nous avons installé Docker plus tôt :
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 containerAméliorer notre flux de travail de développement pour un environnement professionnel
Notre projet est opérationnel, l'ajout de quelques touches de finition assurera une expérience de développeur exceptionnelle qui stimulera la productivité et la collaboration.

Optimisez la construction avec le rechargement à chaud
Il est fastidieux d'exécuter la commande build après chaque changement de code. Le rechargement à chaud résoudra ce problème. Nous pouvons ajouter un autre script dans notre package.json pour surveiller les modifications de fichiers :
"watch": "webpack-cli -w" Ouvrez un terminal séparé et exécutez npm run watch . Désormais, votre projet se compilera automatiquement lorsque vous modifierez un code. Modifiez le message du code, actualisez votre page Web et consultez le résultat mis à jour.
Améliorez la qualité du code avec ESLint et Prettier
Aucun projet TypeScript ou JavaScript n'est complet sans ESLint et Prettier. Ces outils maintiendront la qualité et la cohérence du code de votre projet.
Commençons par installer les dépendances principales :
npm i --save-dev eslint prettierNous ajouterons quelques dépendances d'assistance afin qu'ESLint et Prettier puissent travailler ensemble dans notre projet TypeScript :
npm i --save-dev \ eslint-config-prettier \ eslint-plugin-prettier \ @typescript-eslint/parser \ @typescript-eslint/eslint-plugin Ensuite, nous ajouterons notre linter en créant un fichier de configuration ESLint, .eslintrc , à l'intérieur de la racine du projet :
{ "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"] } } } } Notez que la section extends de notre fichier doit conserver la configuration du plugin Prettier comme dernière ligne afin d'afficher les erreurs Prettier comme des erreurs ESLint visibles dans notre éditeur. Nous suivons les paramètres recommandés par ESLint pour TypeScript, avec quelques préférences personnalisées ajoutées dans la section des rules . N'hésitez pas à parcourir les règles disponibles et à personnaliser davantage vos paramètres. Nous avons choisi d'inclure :
- Une erreur si nous n'utilisons pas de chaînes entre guillemets simples.
- Un avertissement lorsque nous ne fournissons aucun cas
defaultdans les instructionsswitch. - Un avertissement si nous réassignons un paramètre d'une fonction.
- Un avertissement si nous appelons une instruction
awaitdans une boucle. - Une erreur pour les variables inutilisées, qui rendent le code illisible et sujet aux bogues au fil du temps.
Nous avons déjà configuré notre configuration ESLint pour fonctionner avec le formatage Prettier. (Plus d'informations sont disponibles dans le projet GitHub eslint-config-prettier .) Maintenant, nous pouvons créer le fichier de configuration Prettier, .prettierrc :
{ "trailingComma": "none", "tabWidth": 4, "semi": true, "singleQuote": true }Ces paramètres proviennent de la documentation officielle de Prettier ; vous pouvez les modifier à votre guise. Nous avons mis à jour les propriétés suivantes :
-
trailingComma: nous avons changé cela dees5ànonepour éviter les virgules de fin. -
semi: Nous avons changé cela defalseàtruecar nous préférons avoir un point-virgule à la fin de chaque ligne.
Enfin, il est temps de voir ESLint et Prettier en action. Dans notre fichier app.ts , nous allons changer le type de variable de response de const à let . L'utilisation de let n'est pas une bonne pratique dans ce cas puisque nous ne modifions pas la valeur de response . L'éditeur doit afficher une erreur, la règle non respectée et des suggestions pour corriger le code. N'oubliez pas d'activer ESLint et Prettier sur votre éditeur s'ils ne sont pas déjà configurés.
Maintenir le code avec Jest Testing
De nombreuses bibliothèques sont disponibles pour les tests, telles que Jest, Mocha et Storybook. Nous utiliserons Jest dans notre projet pour plusieurs raisons :
- C'est rapide à apprendre.
- Il nécessite une configuration minimale.
- Il offre des tests instantanés faciles à utiliser.
Installons les dépendances requises :
npm i --save-dev jest ts-jest @types/jest Ensuite, nous allons créer un fichier de configuration Jest, jest.config.js , à la racine du projet :
module.exports = { roots: ['src'], testMatch: ['**/__tests__/**/*.+(ts|tsx|js)'], transform: { '^.+\\.(ts|tsx)$': 'ts-jest' } };Nous personnalisons trois options dans notre fichier :
-
roots: Ce tableau contient les dossiers qui seront recherchés pour les fichiers de test - il ne vérifie que sous notre sous-dossiersrc. -
testMatch: ce tableau de modèles glob inclut les extensions de fichier qui seront considérées comme des fichiers Jest. -
transform: Cette option nous permet d'écrire nos tests en TypeScript en utilisant le packagets-jest.
Créons un nouveau dossier __tests__ dans src/test-lambda . À l'intérieur, nous ajouterons le fichier handler.test.ts , où nous créerons notre premier test :
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); }); }); Nous allons revenir à notre fichier package.json et le mettre à jour avec le script de test :
"test": "jest" Lorsque nous allons au terminal et npm run test , nous devrions être accueillis par un test de réussite :
Gérer le contrôle de source avec .gitignore
Nous devons configurer Git pour exclure certains fichiers du contrôle de code source. Nous pouvons créer un fichier .gitignore en utilisant gitignore.io pour ignorer les fichiers qui ne sont pas nécessaires :
# 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 .eslintcacheReady, Set, Build : notre plan de réussite
Nous avons maintenant un projet passe-partout AWS SAM complet avec TypeScript. Nous nous sommes concentrés sur l'obtention des bases et le maintien d'une qualité de code élevée avec le support ESLint, Prettier et Jest. L'exemple de ce didacticiel AWS SAM peut servir de modèle, mettant votre prochain grand projet sur la bonne voie dès le début.
Le blog Toptal Engineering exprime sa gratitude à Christian Loef pour avoir examiné les exemples de code présentés dans cet article.
