Работа с поддержкой TypeScript и Jest: учебное пособие по AWS SAM
Опубликовано: 2022-03-11Модель бессерверных приложений (SAM) AWS, мощный инструмент для создания бессерверных приложений, часто сочетается с JavaScript: 62 % разработчиков в средних и крупных компаниях выбирают JavaScript для своего бессерверного кода. Тем не менее, TypeScript стремительно набирает популярность и намного превосходит JavaScript как третий по популярности язык разработчиков.
Хотя шаблонный шаблон JavaScript найти несложно, запускать проекты AWS SAM с помощью TypeScript сложнее. В следующем руководстве показано, как создать проект AWS SAM TypeScript с нуля, а также как различные части работают вместе. Читатели должны быть лишь немного знакомы с функциями AWS Lambda, чтобы следовать им.
Запуск нашего проекта AWS SAM TypeScript
В основе нашего бессерверного приложения лежат различные компоненты. Сначала мы настроим среду AWS, наш пакет npm и функциональность Webpack, а затем сможем создать, вызвать и протестировать нашу функцию Lambda, чтобы увидеть наше приложение в действии.
Подготовьте среду
Чтобы настроить среду AWS, нам необходимо установить следующее:
- Интерфейс командной строки AWS
- Интерфейс командной строки AWS SAM
- Node.js и нпм
Обратите внимание, что в этом руководстве требуется установить Docker на шаге 2 выше, чтобы протестировать наше приложение локально.
Инициализировать пустой проект
Давайте создадим каталог проекта, aws-sam-typescript-boilerplate и подпапку src для хранения кода. Из каталога проекта мы настроим новый пакет npm:
npm init -y # -y option skips over project questionnaire Эта команда создаст файл package.json внутри нашего проекта.
Добавьте конфигурацию веб-пакета
Webpack — это сборщик модулей, который в основном используется для приложений JavaScript. Поскольку TypeScript компилируется в обычный JavaScript, Webpack эффективно подготовит наш код для веб-браузера. Мы установим две библиотеки и собственный загрузчик:
- веб-пакет: основная библиотека
- webpack-cli: Утилиты командной строки для Webpack
- ts-loader: загрузчик TypeScript для Webpack
npm i --save-dev webpack webpack-cli ts-loader Команда сборки AWS SAM CLI, sam build , замедляет процесс разработки, поскольку пытается запустить 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: загружает объект entry (где Webpack начинает сборку пакета) из ресурсаAWS::Serverless::Function. -
output: указывает на место назначения выходных данных сборки (в данном случае.aws-sam/build). Здесь мы также указываем целевую библиотеку какcommonjs2, что присваивает возвращаемое значение точки входа вmodule.exports. Эта точка входа используется по умолчанию для сред Node.js. -
devtool: это создает исходную картуapp.js.mapв нашем месте вывода сборки. Он сопоставляет наш исходный код с кодом, работающим в веб-браузере, и поможет при отладке, если мы установим для переменной средыNODE_OPTIONSзначение--enable-source-mapsдля нашей Lambda. -
resolve: указывает Webpack обрабатывать файлы TypeScript перед файлами JavaScript. -
target: это указывает Webpack нацелить Node.js в качестве нашей среды. Это означает, чтоrequireбудет использовать функцию запроса Node.js для загрузки фрагментов при компиляции. -
module: это применяет загрузчик TypeScript ко всем файлам, которые соответствуют условиюtest. Другими словами, это гарантирует, что все файлы с расширением.tsили.tsxбудут обработаны загрузчиком. -
plugins: это помогает Webpack идентифицировать и использовать нашaws-sam-webpack-plugin.
В первой строке мы отключили конкретное правило ESLint для этого файла. Стандартные правила ESLint, которые мы настроим позже, не рекомендуют использовать оператор require . Мы предпочитаем 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. Мы добавили include , чтобы добавить файлы из папки src в программу, и exclude , чтобы избежать компиляции TypeScript для папки node_modules — мы не будем касаться этого кода напрямую.
Создайте лямбда-функцию
До сих пор мы не писали код Lambda для нашего бессерверного приложения, поэтому давайте приступим. В папке src , которую мы создали ранее, мы создадим подпапку test-lambda , содержащую файл app.ts с этой функцией 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 с телом. Мы сможем запустить код после еще одного шага.
Включить файл шаблона 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 Этот файл шаблона генерирует функцию Lambda, доступную из HTTP GET API. Обратите внимание, что версия, указанная в строке Runtime: может нуждаться в настройке.
Запустите приложение
Чтобы запустить приложение, мы должны добавить новый скрипт в файл package.json для сборки проекта с помощью Webpack. В файле могут быть существующие сценарии, например пустой тестовый сценарий. Мы можем добавить скрипт сборки следующим образом:
"scripts": { "build": "webpack-cli" } Если вы запустите npm run build из корня проекта, вы должны увидеть созданную папку сборки .aws-sam . Тем из нас, кто работает в среде Mac, может потребоваться сделать скрытые файлы видимыми, нажав Command + Shift + . чтобы увидеть папку.
Теперь мы запустим локальный HTTP-сервер для проверки нашей функции:
sam local start-apiКогда мы посещаем конечную точку теста в веб-браузере, мы должны увидеть сообщение об успешном завершении.
Консоль должна показать, что функция монтируется в контейнере 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 . Теперь ваш проект будет автоматически компилироваться при изменении любого кода. Измените сообщение кода, обновите свою веб-страницу и посмотрите обновленный результат.
Улучшите качество кода с помощью 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 Далее мы добавим наш линтер, создав файл конфигурации .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"] } } } } Обратите внимание, что раздел extensions нашего файла должен содержать конфигурацию плагина extends в качестве последней строки, чтобы отображать ошибки Prettier как ошибки ESLint, видимые в нашем редакторе. Мы следуем рекомендуемым ESLint настройкам для TypeScript с некоторыми пользовательскими настройками, добавленными в раздел rules . Не стесняйтесь просматривать доступные правила и дополнительно настраивать параметры. Мы решили включить:
- Ошибка, если мы не используем строки в одинарных кавычках.
- Предупреждение, когда мы не указываем регистр по
defaultв операторахswitch. - Предупреждение, если мы переназначаем любой параметр функции.
- Предупреждение, если мы вызываем оператор
awaitвнутри цикла. - Ошибка для неиспользуемых переменных, которые со временем делают код нечитаемым и подверженным ошибкам.
Мы уже настроили нашу конфигурацию ESLint для работы с форматированием Prettier. (Дополнительная информация доступна в проекте 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 . Использование let в этом случае не является хорошей практикой, так как мы не изменяем значение response . Редактор должен отображать ошибку, нарушенное правило и предложения по исправлению кода. Не забудьте включить ESLint и Prettier в вашем редакторе, если они еще не настроены.
Поддерживайте код с помощью Jest Testing
Многие библиотеки доступны для тестирования, такие как 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' } };Мы настраиваем три параметра в нашем файле:
-
roots: этот массив содержит папки, в которых будут выполняться поиски тестовых файлов — он проверяет только нашу подпапкуsrc. -
testMatch: этот массив шаблонов глобусов включает расширения файлов, которые будут считаться файлами Jest. -
transform: этот параметр позволяет нам писать наши тесты на TypeScript с использованием пакетаts-jest.
Давайте создадим новую папку __tests__ внутри src/test-lambda . Внутри мы добавим файл 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 , нас должен приветствовать пройденный тест:
Управление исходным кодом с помощью .gitignore
Мы должны настроить Git, чтобы исключить определенные файлы из системы контроля версий. Мы можем создать файл .gitignore с помощью gitignore.io, чтобы пропустить ненужные файлы:
# 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Готово, установлено, построено: наш план успеха
Теперь у нас есть полный шаблонный проект AWS SAM с TypeScript. Мы сосредоточились на правильном понимании основ и поддержании высокого качества кода с поддержкой ESLint, Prettier и Jest. Пример из этого руководства по AWS SAM может послужить образцом для планирования вашего следующего крупного проекта с самого начала.
Блог Toptal Engineering выражает благодарность Кристиану Лоэфу за рассмотрение примеров кода, представленных в этой статье.
