Lucrul cu TypeScript și suport Jest: un tutorial AWS SAM
Publicat: 2022-03-11Un instrument puternic pentru construirea de aplicații fără server, modelul de aplicații fără server (SAM) AWS se asociază frecvent cu JavaScript: 62% dintre dezvoltatorii companiilor mijlocii și mari aleg JavaScript pentru codul lor fără server. Cu toate acestea, TypeScript este în creștere în popularitate și depășește cu mult JavaScript ca al treilea cel mai iubit limbaj al dezvoltatorilor.
Deși standardul JavaScript nu este greu de găsit, pornirea proiectelor AWS SAM cu TypeScript este mai complexă. Următorul tutorial arată cum să creați un proiect AWS SAM TypeScript de la zero, precum și modul în care diferitele părți funcționează împreună. Cititorii trebuie să fie doar oarecum familiarizați cu funcțiile AWS Lambda pentru a urma.
Începem proiectul nostru AWS SAM TypeScript
Fundamentul aplicației noastre fără server include diverse componente. Mai întâi vom configura mediul AWS, pachetul nostru npm și funcționalitatea Webpack – apoi putem crea, invoca și testa funcția noastră Lambda pentru a vedea aplicația noastră în acțiune.
Pregătiți Mediul
Pentru a configura mediul AWS, trebuie să instalăm următoarele:
- AWS CLI
- AWS SAM CLI
- Node.js și npm
Rețineți că acest tutorial necesită instalarea Docker în timpul pasului 2 de mai sus pentru a testa aplicația noastră local.
Inițializați un proiect gol
Să creăm directorul proiectului, aws-sam-typescript-boilerplate și un subfolder src pentru a păstra codul. Din directorul de proiect, vom configura un nou pachet npm:
npm init -y # -y option skips over project questionnaire Această comandă va crea un fișier package.json în interiorul proiectului nostru.
Adăugați configurația Webpack
Webpack este un bundler de module utilizat în principal pentru aplicațiile JavaScript. Deoarece TypeScript se compilează în JavaScript simplu, Webpack va pregăti efectiv codul nostru pentru browserul web. Vom instala două biblioteci și un încărcător personalizat:
- webpack: bibliotecă de bază
- webpack-cli: utilitare de linie de comandă pentru Webpack
- ts-loader: încărcător TypeScript pentru Webpack
npm i --save-dev webpack webpack-cli ts-loader Comanda de compilare AWS SAM CLI, sam build , încetinește procesul de dezvoltare deoarece încearcă să ruleze npm install pentru fiecare funcție, provocând dublarea. Vom folosi o comandă de compilare alternativă din biblioteca aws-sam-webpack-plugin pentru a accelera mediul nostru.
npm i --save-dev aws-sam-webpack-plugin În mod implicit, Webpack nu oferă un fișier de configurare. Să facem un fișier de configurare personalizat numit webpack.config.js în folderul rădăcină:
/* 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] };Acum să examinăm diferitele părți:
-
entry: Aceasta încarcă obiectul de intrare (unde Webpack începe să construiască pachetul) din resursaAWS::Serverless::Function. -
output: Aceasta indică destinația ieșirii de compilare (în acest caz,.aws-sam/build). Aici specificăm și biblioteca țintă cacommonjs2, care atribuie valoarea de returnare a punctului de intraremodule.exports. Acest punct de intrare este implicit pentru mediile Node.js. -
devtool: Aceasta creează o hartă sursă,app.js.map, în destinația noastră de ieșire a compilației. Mapează codul nostru original la codul care rulează în browserul web și va ajuta la depanare dacă setăm variabila de mediuNODE_OPTIONSla--enable-source-mapspentru Lambda noastră. -
resolve: Aceasta îi spune lui Webpack să proceseze fișierele TypeScript înaintea fișierelor JavaScript. -
target: Acest lucru îi spune lui Webpack să vizeze Node.js ca mediu. Aceasta înseamnă că Webpack va folosi funcția Node.jsrequirepentru a încărca bucăți atunci când se compilează. -
module: Acesta aplică încărcătorul TypeScript la toate fișierele care îndeplinesc condiția detest. Cu alte cuvinte, se asigură că toate fișierele cu.tssau.tsxvor fi gestionate de încărcător. -
plugins: aceasta ajută Webpack să identifice și să utilizeze pluginul nostruaws-sam-webpack-plugin.
În prima linie, am dezactivat o anumită regulă ESLint pentru acest fișier. Regulile standard ESLint pe care le vom configura ulterior descurajează utilizarea instrucțiunii require . Preferăm să import în require , așa că vom face o excepție.
Configurați suport TypeScript
Adăugarea suportului TypeScript va îmbunătăți experiența dezvoltatorului prin:
- Prevenirea mesajelor de avertizare cu privire la lipsa declarațiilor de tip.
- Furnizarea de validare a tipului.
- Oferind completare automată în interiorul IDE.
Mai întâi, vom instala local TypeScript pentru proiectul nostru (săriți peste acest pas dacă aveți TypeScript instalat la nivel global):
npm i --save-dev typescriptVom include tipurile pentru bibliotecile pe care le folosim:
npm i --save-dev @types/node @types/webpack @types/aws-lambda Acum, vom crea fișierul de configurare TypeScript, tsconfig.json , în rădăcina proiectului:
{ "compilerOptions": { "target": "ES2015", "module": "commonjs", "sourceMap": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, }, "include": ["src/**/*.ts", "src/**/*.js"], "exclude": ["node_modules"] } Aici urmărim configurația implicită recomandată de comunitatea TypeScript. Am adăugat include pentru a adăuga fișierele din folderul src la program și am exclude pentru a evita compilarea TypeScript pentru folderul node_modules - nu vom atinge acest cod direct.
Creați o funcție Lambda
Nu am scris niciun cod Lambda pentru aplicația noastră fără server până acum, așa că haideți să intrăm. În folderul src creat mai devreme, vom crea un subfolder test-lambda care conține un fișier app.ts cu această funcție 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; };Această funcție simplă de substituent returnează un răspuns 200 cu un corp. Vom putea rula codul după încă un pas.
Includeți fișierul șablon AWS
AWS SAM necesită un fișier șablon pentru a transpila codul nostru și a-l implementa în cloud. Creați fișierul template.yaml în folderul rădăcină:
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 Acest fișier șablon generează o funcție Lambda accesibilă dintr-un API GET HTTP. Rețineți că versiunea la care se face referire în linia Runtime: poate necesita personalizare.
Rulați aplicația
Pentru a rula aplicația, trebuie să adăugăm un nou script în fișierul package.json pentru construirea proiectului cu Webpack. Fișierul poate avea scripturi existente, cum ar fi un script de testare gol. Putem adăuga scriptul de compilare astfel:
"scripts": { "build": "webpack-cli" } Dacă rulați npm run build de la rădăcina proiectului, ar trebui să vedeți folderul de compilare, .aws-sam , creat. Aceia dintre noi într-un mediu Mac poate avea nevoie să facă vizibile fișierele ascunse apăsând Command + Shift + . pentru a vedea folderul.
Acum vom porni un server HTTP local pentru a ne testa funcția:
sam local start-apiCând vizităm punctul final de testare într-un browser web, ar trebui să vedem un mesaj de succes.
Consola ar trebui să arate că funcția este montată într-un container Docker înainte de a rula, motiv pentru care am instalat Docker mai devreme:
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Îmbunătățirea fluxului nostru de lucru de dezvoltare pentru un cadru profesional
Proiectul nostru este în funcțiune, adăugarea de câteva retușuri finale va asigura o experiență de dezvoltator excepțională, care va crește productivitatea și colaborarea.

Optimizați construcția cu reîncărcarea la cald
Este plictisitor să rulezi comanda build după fiecare schimbare de cod. Reîncărcarea la cald va rezolva această problemă. Putem adăuga un alt script în package.json pentru a urmări modificările fișierelor:
"watch": "webpack-cli -w" Deschideți un terminal separat și rulați npm run watch . Acum, proiectul dvs. se va compila automat când modificați orice cod. Modificați mesajul codului, reîmprospătați pagina web și vedeți rezultatul actualizat.
Îmbunătățiți calitatea codului cu ESLint și Prettier
Niciun proiect TypeScript sau JavaScript nu este complet fără ESLint și Prettier. Aceste instrumente vor menține calitatea și consistența codului proiectului dvs.
Să instalăm mai întâi dependențele de bază:
npm i --save-dev eslint prettierVom adăuga câteva dependențe de ajutor, astfel încât ESLint și Prettier să poată lucra împreună în proiectul nostru TypeScript:
npm i --save-dev \ eslint-config-prettier \ eslint-plugin-prettier \ @typescript-eslint/parser \ @typescript-eslint/eslint-plugin În continuare, vom adăuga linter-ul nostru creând un fișier de configurare ESLint, .eslintrc , în interiorul rădăcinii proiectului:
{ "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"] } } } } Rețineți că secțiunea extends a fișierului nostru trebuie să păstreze configurația pluginului Prettier ca ultimă linie pentru a afișa erorile Prettier ca erori ESLint vizibile în editorul nostru. Urmăm setările recomandate de ESLint pentru TypeScript, cu unele preferințe personalizate adăugate în secțiunea de rules . Simțiți-vă liber să răsfoiți regulile disponibile și să personalizați în continuare setările. Am ales să includem:
- O eroare dacă nu folosim șiruri cu ghilimele simple.
- Un avertisment când nu furnizăm niciun caz
defaultîn instrucțiunileswitch. - Un avertisment dacă reatribum orice parametru al unei funcții.
- Un avertisment dacă apelăm o instrucțiune
awaitîn interiorul unei bucle. - O eroare pentru variabilele neutilizate, care fac codul imposibil de citit și predispus la erori în timp.
Am configurat deja configurația noastră ESLint pentru a funcționa cu formatarea Prettier. (Sunt disponibile mai multe informații în proiectul GitHub eslint-config-prettier .) Acum, putem crea fișierul de configurare Prettier, .prettierrc :
{ "trailingComma": "none", "tabWidth": 4, "semi": true, "singleQuote": true }Aceste setări sunt din documentația oficială a lui Prettier; le puteți modifica după cum doriți. Am actualizat următoarele proprietăți:
-
trailingComma: Am schimbat acest lucru de laes5lanonepentru a evita virgulele finale. -
semi: Am schimbat acest lucru de lafalselatruedeoarece preferăm să avem un punct și virgulă la sfârșitul fiecărei linii.
În sfârșit, este timpul să vedeți ESLint și Prettier în acțiune. În fișierul nostru app.ts , vom schimba tipul de variabilă de response din const în let . Utilizarea let nu este o practică bună în acest caz, deoarece nu modificăm valoarea response . Editorul ar trebui să afișeze o eroare, regula încălcată și sugestii pentru a remedia codul. Nu uitați să activați ESLint și Prettier în editorul dvs. dacă nu sunt deja configurate.
Menține codul cu testul Jest
Multe biblioteci sunt disponibile pentru testare, cum ar fi Jest, Mocha și Storybook. Vom folosi Jest în proiectul nostru din câteva motive:
- Este rapid de învățat.
- Necesită o configurare minimă.
- Oferă testare instantanee ușor de utilizat.
Să instalăm dependențele necesare:
npm i --save-dev jest ts-jest @types/jest Apoi, vom crea un fișier de configurare Jest, jest.config.js , în rădăcina proiectului:
module.exports = { roots: ['src'], testMatch: ['**/__tests__/**/*.+(ts|tsx|js)'], transform: { '^.+\\.(ts|tsx)$': 'ts-jest' } };Personalizăm trei opțiuni în fișierul nostru:
-
roots: această matrice conține folderele care vor fi căutate pentru fișierele de testare — se verifică doar sub subdosarul nostrusrc. -
testMatch: Această serie de modele glob include extensiile de fișiere care vor fi considerate fișiere Jest. -
transform: Această opțiune ne permite să scriem testele noastre în TypeScript folosind pachetults-jest.
Să creăm un nou folder __tests__ în interiorul src/test-lambda . În interiorul acestuia, vom adăuga fișierul handler.test.ts , unde vom crea primul nostru 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); }); }); Vom reveni la fișierul nostru package.json și îl vom actualiza cu scriptul de testare:
"test": "jest" Când mergem la terminal și rulăm npm run test , ar trebui să fim întâmpinați cu un test de trecere:
Gestionați controlul sursei cu .gitignore
Ar trebui să configuram Git pentru a exclude anumite fișiere din controlul sursei. Putem crea un fișier .gitignore folosind gitignore.io pentru a sări peste fișierele care nu sunt necesare:
# 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 .eslintcachePregătiți, pregătiți, construiți: planul nostru pentru succes
Avem acum un proiect complet AWS SAM cu TypeScript. Ne-am concentrat pe obținerea corectă a elementelor de bază și pe menținerea calității înalte a codului cu suportul ESLint, Prettier și Jest. Exemplul din acest tutorial AWS SAM poate servi drept model, punând pe drumul cel bun următorul tău mare proiect încă de la început.
Blogul Toptal Engineering își extinde recunoștința lui Christian Loef pentru revizuirea exemplelor de cod prezentate în acest articol.
