Lavorare con TypeScript e Jest Support: un tutorial AWS SAM
Pubblicato: 2022-03-11Un potente strumento per la creazione di applicazioni serverless, AWS Serverless Application Model (SAM) si accoppia spesso con JavaScript: il 62% degli sviluppatori di aziende di medie e grandi dimensioni sceglie JavaScript per il proprio codice serverless. Tuttavia, TypeScript sta crescendo in popolarità e supera di gran lunga JavaScript come terzo linguaggio più amato dagli sviluppatori.
Sebbene JavaScript non sia difficile da trovare, l'avvio di progetti AWS SAM con TypeScript è più complesso. Il seguente tutorial mostra come creare un progetto AWS SAM TypeScript da zero e come le diverse parti interagiscono. I lettori devono avere solo una certa familiarità con le funzioni di AWS Lambda per seguire.
Avvio del nostro progetto TypeScript AWS SAM
Le basi della nostra applicazione serverless includono vari componenti. Per prima cosa configureremo l'ambiente AWS, il nostro pacchetto npm e la funzionalità Webpack, quindi potremo creare, invocare e testare la nostra funzione Lambda per vedere la nostra applicazione in azione.
Preparare l'ambiente
Per configurare l'ambiente AWS, è necessario installare quanto segue:
- AWS CLI
- CLI di AWS SAM
- Node.js e npm
Tieni presente che questo tutorial richiede l'installazione di Docker durante il passaggio 2 sopra per testare la nostra applicazione in locale.
Inizializza un progetto vuoto
Creiamo la directory del progetto, aws-sam-typescript-boilerplate e una sottocartella src per contenere il codice. Dalla directory del progetto, imposteremo un nuovo pacchetto npm:
npm init -y # -y option skips over project questionnaire Questo comando creerà un file package.json all'interno del nostro progetto.
Aggiungi la configurazione del Webpack
Webpack è un bundler di moduli utilizzato principalmente per le applicazioni JavaScript. Poiché TypeScript viene compilato in JavaScript semplice, Webpack preparerà efficacemente il nostro codice per il browser web. Installeremo due librerie e un caricatore personalizzato:
- pacchetto web: libreria principale
- webpack-cli: utilità della riga di comando per Webpack
- ts-loader: caricatore TypeScript per Webpack
npm i --save-dev webpack webpack-cli ts-loader Il comando di build della AWS SAM CLI, sam build , rallenta il processo di sviluppo perché tenta di eseguire npm install per ogni funzione, causando la duplicazione. Useremo un comando di build alternativo dalla libreria aws-sam-webpack-plugin per velocizzare il nostro ambiente.
npm i --save-dev aws-sam-webpack-plugin Per impostazione predefinita, Webpack non fornisce un file di configurazione. Creiamo un file di configurazione personalizzato chiamato webpack.config.js nella cartella principale:
/* 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] };Esaminiamo ora le varie parti:
-
entry: carica l'oggetto entry (dove Webpack inizia a creare il bundle) dalla risorsaAWS::Serverless::Function. -
output: punta alla destinazione dell'output di compilazione (in questo caso,.aws-sam/build). Qui specifichiamo anche la libreria di destinazione comecommonjs2, che assegna il valore di ritorno del punto di ingresso amodule.exports. Questo punto di ingresso è l'impostazione predefinita per gli ambienti Node.js. -
devtool: questo crea una mappa di origine,app.js.map, nella nostra destinazione di output di build. Mappa il nostro codice originale sul codice in esecuzione nel browser Web e aiuta con il debug se impostiamo la variabile di ambienteNODE_OPTIONSsu--enable-source-mapsper il nostro Lambda. -
resolve: indica a Webpack di elaborare i file TypeScript prima dei file JavaScript. -
target: questo dice a Webpack di scegliere come target Node.js come nostro ambiente. Ciò significa che Webpack utilizzerà la funzione Node.jsrequireper caricare i blocchi durante la compilazione. -
module: applica il caricatore TypeScript a tutti i file che soddisfano la condizione ditest. In altre parole, garantisce che tutti i file con estensione.tso.tsxvengano gestiti dal caricatore. -
plugins: questo aiuta Webpack a identificare e utilizzare il nostroaws-sam-webpack-plugin.
Nella prima riga, abbiamo disabilitato una particolare regola ESLint per questo file. Le regole standard di ESLint che configureremo in seguito scoraggiano l'uso dell'istruzione require . Preferiamo require l' import in Webpack, quindi faremo un'eccezione.
Imposta il supporto per i caratteri dattiloscritti
L'aggiunta del supporto TypeScript migliorerà l'esperienza dello sviluppatore:
- Prevenire i messaggi di avviso sulle dichiarazioni di tipo mancanti.
- Fornire la convalida del tipo.
- Offrendo il completamento automatico all'interno dell'IDE.
Innanzitutto, installeremo TypeScript per il nostro progetto in locale (salta questo passaggio se hai installato TypeScript a livello globale):
npm i --save-dev typescriptIncluderemo i tipi per le librerie che stiamo utilizzando:
npm i --save-dev @types/node @types/webpack @types/aws-lambda Ora creeremo il file di configurazione TypeScript, tsconfig.json , nella radice del progetto:
{ "compilerOptions": { "target": "ES2015", "module": "commonjs", "sourceMap": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, }, "include": ["src/**/*.ts", "src/**/*.js"], "exclude": ["node_modules"] } Qui stiamo seguendo la configurazione predefinita consigliata dalla comunità TypeScript. Abbiamo aggiunto include per aggiungere i file nella cartella src al programma ed exclude per evitare la compilazione di TypeScript per la cartella node_modules : non toccheremo questo codice direttamente.
Crea una funzione Lambda
Finora non abbiamo scritto alcun codice Lambda per la nostra applicazione serverless, quindi entriamo. Nella cartella src creata in precedenza, creeremo una sottocartella test-lambda contenente un file app.ts con questa funzione 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; };Questa semplice funzione segnaposto restituisce una risposta 200 con un corpo. Saremo in grado di eseguire il codice dopo un altro passaggio.
Includi il file modello AWS
AWS SAM richiede un file modello per trasferire il nostro codice e distribuirlo nel cloud. Crea il file template.yaml nella cartella principale:
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 Questo file modello genera una funzione Lambda accessibile da un'API HTTP GET. Si noti che la versione a cui si fa riferimento nella riga Runtime: potrebbe richiedere la personalizzazione.
Esegui l'applicazione
Per eseguire l'applicazione, dobbiamo aggiungere un nuovo script nel file package.json per creare il progetto con Webpack. Il file potrebbe avere script esistenti, ad esempio uno script di test vuoto. Possiamo aggiungere lo script di compilazione in questo modo:
"scripts": { "build": "webpack-cli" } Se esegui npm run build dalla radice del progetto, dovresti vedere la cartella build, .aws-sam , creata. Quelli di noi in un ambiente Mac potrebbero dover rendere visibili i file nascosti premendo Comando + Maiusc + . per vedere la cartella.
Ora avvieremo un server HTTP locale per testare la nostra funzione:
sam local start-apiQuando visitiamo l'endpoint di test in un browser Web, dovremmo visualizzare un messaggio di successo.
La console dovrebbe mostrare che la funzione viene montata in un contenitore Docker prima dell'esecuzione, motivo per cui abbiamo installato Docker in precedenza:
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 containerMigliorare il nostro flusso di lavoro di sviluppo per un ambiente professionale
Il nostro progetto è attivo e funzionante, l'aggiunta di alcuni ritocchi finali garantirà un'esperienza di sviluppo eccezionale che aumenterà la produttività e la collaborazione.

Ottimizza la build con la ricarica a caldo
È noioso eseguire il comando build dopo ogni modifica del codice. La ricarica a caldo risolverà questo problema. Possiamo aggiungere un altro script nel nostro package.json per controllare le modifiche ai file:
"watch": "webpack-cli -w" Aprire un terminale separato ed eseguire npm run watch . Ora, il tuo progetto verrà compilato automaticamente quando cambi qualsiasi codice. Modifica il messaggio del codice, aggiorna la tua pagina web e guarda il risultato aggiornato.
Migliora la qualità del codice con ESLint e Prettier
Nessun progetto TypeScript o JavaScript è completo senza ESLint e Prettier. Questi strumenti manterranno la qualità e la coerenza del codice del tuo progetto.
Installiamo prima le dipendenze principali:
npm i --save-dev eslint prettierAggiungeremo alcune dipendenze di supporto in modo che ESLint e Prettier possano lavorare insieme nel nostro progetto TypeScript:
npm i --save-dev \ eslint-config-prettier \ eslint-plugin-prettier \ @typescript-eslint/parser \ @typescript-eslint/eslint-plugin Successivamente, aggiungeremo il nostro linter creando un file di configurazione ESLint, .eslintrc , all'interno della radice del progetto:
{ "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"] } } } } Nota che la sezione extends del nostro file deve mantenere la configurazione del plug-in di Prettier come ultima riga per visualizzare gli errori di Prettier come errori ESLint visibili nel nostro editor. Stiamo seguendo le impostazioni consigliate da ESLint per TypeScript, con alcune preferenze personalizzate aggiunte nella sezione delle rules . Sentiti libero di sfogliare le regole disponibili e personalizzare ulteriormente le tue impostazioni. Abbiamo scelto di includere:
- Un errore se non utilizziamo stringhe con virgolette singole.
- Un avviso quando non forniamo case di
defaultnelle istruzioniswitch. - Un avviso se riassegnamo qualsiasi parametro di una funzione.
- Un avviso se chiamiamo un'istruzione
awaitall'interno di un ciclo. - Un errore per le variabili inutilizzate, che rendono il codice illeggibile e soggetto a bug nel tempo.
Abbiamo già impostato la nostra configurazione ESLint per funzionare con la formattazione di Prettier. (Maggiori informazioni sono disponibili nel progetto GitHub eslint-config-prettier .) Ora possiamo creare il file di configurazione di Prettier, .prettierrc :
{ "trailingComma": "none", "tabWidth": 4, "semi": true, "singleQuote": true }Queste impostazioni provengono dalla documentazione ufficiale di Prettier; puoi modificarli a tuo piacimento. Abbiamo aggiornato le seguenti proprietà:
-
trailingComma: l'abbiamo modificato daes5anoneper evitare le virgole finali. -
semi: l'abbiamo cambiato dafalseatrueperché preferiamo avere un punto e virgola alla fine di ogni riga.
Finalmente, è il momento di vedere ESLint e Prettier in azione. Nel nostro file app.ts , cambieremo il tipo di variabile di response da const a let . L'uso di let non è una buona pratica in questo caso poiché non modifichiamo il valore della response . L'editor dovrebbe visualizzare un errore, la regola violata e suggerimenti per correggere il codice. Non dimenticare di abilitare ESLint e Prettier sul tuo editor se non sono già impostati.
Mantieni il codice con Jest Testing
Molte librerie sono disponibili per il test, come Jest, Mocha e Storybook. Useremo Jest nel nostro progetto per alcuni motivi:
- È veloce da imparare.
- Richiede una configurazione minima.
- Offre test snapshot di facile utilizzo.
Installiamo le dipendenze richieste:
npm i --save-dev jest ts-jest @types/jest Successivamente, creeremo un file di configurazione di Jest, jest.config.js , all'interno della radice del progetto:
module.exports = { roots: ['src'], testMatch: ['**/__tests__/**/*.+(ts|tsx|js)'], transform: { '^.+\\.(ts|tsx)$': 'ts-jest' } };Stiamo personalizzando tre opzioni nel nostro file:
-
roots: questo array contiene le cartelle in cui verranno cercati i file di test, controlla solo sotto la nostra sottocartellasrc. -
testMatch: questa matrice di modelli glob include le estensioni di file che saranno considerate file Jest. -
transform: questa opzione ci permette di scrivere i nostri test in TypeScript usando il pacchettots-jest.
Creiamo una nuova cartella __tests__ all'interno src/test-lambda . Al suo interno, aggiungeremo il file handler.test.ts , dove creeremo il nostro primo 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); }); }); Torneremo al nostro file package.json e lo aggiorneremo con lo script di test:
"test": "jest" Quando andiamo al terminale ed npm run test , dovremmo essere accolti con un test di superamento:
Gestisci il controllo del codice sorgente con .gitignore
Dovremmo configurare Git per escludere determinati file dal controllo del codice sorgente. Possiamo creare un file .gitignore usando gitignore.io per saltare i file che non sono richiesti:
# 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 .eslintcachePronto, impostato, costruito: il nostro progetto per il successo
Ora abbiamo un progetto standard AWS SAM completo con TypeScript. Ci siamo concentrati sull'ottenere le basi giuste e mantenere un'elevata qualità del codice con il supporto ESLint, Prettier e Jest. L'esempio di questo tutorial di AWS SAM può fungere da progetto, mettendo sulla buona strada il tuo prossimo grande progetto fin dall'inizio.
Il Toptal Engineering Blog estende la sua gratitudine a Christian Loef per aver esaminato gli esempi di codice presentati in questo articolo.
