Создание производственной 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, упомянутый в начале статьи.
В следующих статьях я опишу другие облачные подходы. Следите за обновлениями. Хорошего дня!