Создание производственной AWS Lambda с помощью TypeScript
В этой статье я расскажу о шагах и компонентах, необходимых для создания AWS Lambda с помощью TypeScript. Это включает в себя настройку TypeScript, WebPack, Jest для тестирования и упаковки, а также выполнение этой работы с помощью генератора Yeoman aws-lambda-typescript
.
TLDR; Эта работа была выпущена как генератор Yeoman, который можно использовать для генерации скелетного кода для TypeScript AWS Lambda:
npm install -g yo npm i -g generator-aws-lambda-typescript yo aws-lambda-typescript
AWS Lambda — прекрасное решение для тех, кто хочет поддерживать высокую доступность и в то же время снижать затраты. Это особенно рентабельно для решений с низким трафиком, где обслуживание долго работающих контейнеров или виртуальных машин EC2 может привести к слишком большому финансовому бремени.
Общие проблемы, решаемые в этой статье,
- размер функции Lambda — NPM и папка
node_modules
могут быть очень тяжелыми и превышать размеры развертывания. Огромные пакеты затрудняют повторное развертывание кода, его эффективную разработку и тестирование. - холодный старт — это время, необходимое для инициализации функции Lambda, прежде чем она сможет обработать запрос. Когда функция не используется в течение нескольких минут или необходимо запустить новый экземпляр для обработки более высокого трафика, инициализация (холодный запуск) может значительно увеличить время отклика, что может привести к ухудшению взаимодействия с конечным пользователем.
Решение проблем с холодным запуском заключается в использовании среды выполнения и языка, которые обеспечивают быстрый и эффективный запуск. Лучшим вариантом является JavaScript, однако из-за отсутствия типизации он может оказаться не лучшим выбором для крупных корпоративных проектов.
Естественной альтернативой является использование TypeScript, но он изначально не поддерживается AWS Lambda, поэтому для него требуется настроить транспирацию-tsc
. Простая упаковка node_modules
с транспилированным выходным кодом JavaScript может привести к созданию огромных ZIP-файлов, содержащих сотни или более МБ данных, и, возможно, превышение ограничений AWS для пакетов развертывания.
Чтобы решить проблемы с размером, мы можем использовать Webpack, который хорошо известен во фронтенд-разработке и имеет возможности минимизации (встряхивания дерева) и объединения в проекты с одним файлом.
Во-первых, нам нужно установить все необходимые dev-зависимости (TypeScript, linter, тесты, сборка):
npm i --save-dev ts-loader ts-node typescript webpack webpack-cli \ prettier jest eslint-plugin-prettie eslint \ @typescript-eslint/eslint-plugin @jest/globals \ @types/aws-lambda
Скорее всего нам потребуется один из пакетов AWS SDK
npm i @aws-sdk/client-s3
Во-первых, нам нужно настроить tsconfig.json
в соответствии с нашими потребностями в языковой поддержке. Для поддержки бэктрейсов мы должны установить sourceMaps: true
— иначе Erros в логах будет содержать бессмысленную информацию о местонахождении ошибки (хороший бэктрейс может сэкономить много времени для устранения проблем с продакшеном).
{ "compilerOptions": { "lib": [ "ES2022"], "alwaysStrict": true, "esModuleInterop": true, "noUnusedLocals": true, "noUnusedParameters": true, "strictNullChecks": true, "sourceMap": true, "strict": true, } }
Далее идет настройка webpack.config.js
const path = require('path'); const { merge } = require('webpack-merge'); /** @type {import('webpack').Configuration} */ const commonConfig = { entry: './src/index.ts', /** Most recent Node version supported by Lambda when creating this template */ target: 'node18', /** Inline source map always, to get meaningful stack traces */ devtool: 'inline-source-map', output: { filename: 'index.js', path: path.resolve(__dirname, 'dist'), library: { type: 'commonjs2', }, }, externals: [ /** Exclude all `@aws-sdk/*` packages, as those are provided in Lambda Node container. */ /@aws-sdk\/.*/, ], module: { /** * Configure TypeScript loader, as WebPack natively doesn't support TypeScript * ts-loader can be installed with `npm i --save-dev ts-loader` */ rules: [ { test: /\.ts$/, use: 'ts-loader', exclude: path.resolve(__dirname, 'node_modules'), }, ], }, resolve: { extensions: ['.js', '.mjs', '.ts'], }, }; /** @type {import('webpack').Configuration} */ const devOptions = { mode: 'development', }; /** @type {import('webpack').Configuration} */ const prodOptions = { mode: 'production', }; module.exports = (_env, argv) => { return merge(commonConfig, argv.mode == 'production' ? prodOptions : devOptions); };
В дополнение к этому необходимо не забыть настроить среду выполнения JavaScript AWS для поддержки исходных карт, это можно сделать, установив переменную среды NODE_MODULES=--enable-source-maps
в консоли или сценарии развертывания:
Конечно же, не забываем добавить основной исходный файл src/index.ts
import * as process from 'process'; import { APIGatewayProxyEvent, Context } from 'aws-lambda'; /* * Insert rest of function static initialization here, things like * - loading KMS keys * - setting up clients * will be shared among executions of handler. */ export const handler = async (event: APIGatewayProxyEvent, _ctx: Context) => { console.log('Received Event', event); };
Мы можем построить весь проект с
./node_modules/.bin/webpack build --mode production
Или запустить в режиме разработки/просмотра с
webpack --watch
Этот краткий пошаговый обзор должен дать более глубокое понимание того, как AWS Lambdas можно создавать с помощью TypeScript и Webpack. Для готового пакета предлагаю использовать генератор Yeoman, упомянутый в начале статьи.
В следующих статьях я опишу другие облачные подходы. Следите за обновлениями. Хорошего дня!