ساخت پروژه های AWS SAM TypeScript با پشتیبانی Jest


یک ابزار قدرتمند برای ساخت برنامه های بدون سرور، مدل برنامه بدون سرور AWS (SAM) اغلب با جاوا اسکریپت جفت می شود: 62% توسعه دهندگان در شرکت های متوسط ​​و بزرگ جاوا اسکریپت را برای کدهای بدون سرور خود انتخاب می کنند. با این حال، تایپ اسکریپت در حال افزایش محبوبیت است و به مراتب از جاوا اسکریپت به عنوان توسعه دهندگان بالاتر است. سوممحبوب ترین زبان

در حالی که پیدا کردن boilerplate جاوا اسکریپت کار سختی نیست، شروع پروژه های AWS SAM با TypeScript پیچیده تر است. آموزش زیر نحوه ایجاد یک پروژه AWS SAM TypeScript را از ابتدا و همچنین نحوه کار قسمت های مختلف با هم را نشان می دهد. خوانندگان فقط باید تا حدودی با توابع AWS Lambda آشنا باشند تا دنبال شوند.

شروع پروژه AWS SAM TypeScript ما

اساس برنامه بدون سرور ما شامل اجزای مختلفی است. ابتدا محیط AWS، بسته npm خود و عملکرد Webpack را پیکربندی می‌کنیم – سپس می‌توانیم عملکرد Lambda خود را ایجاد، فراخوانی و آزمایش کنیم تا برنامه خود را در عمل ببینیم.

محیط زیست را آماده کنید

برای راه اندازی محیط AWS باید موارد زیر را نصب کنیم:

  1. AWS CLI
  2. AWS SAM CLI
  3. Node.js و npm

توجه داشته باشید که این آموزش نیاز به نصب دارد داکر در مرحله 2 بالا برای آزمایش برنامه ما به صورت محلی.

یک پروژه خالی را راه اندازی کنید

بیایید دایرکتوری پروژه را ایجاد کنیم، aws-sam-typescript-boilerplate، و الف src زیر پوشه برای نگهداری کد از دایرکتوری پروژه، یک بسته جدید npm را راه اندازی می کنیم:

npm init -y # -y option skips over project questionnaire

این دستور یک را ایجاد می کند package.json فایل داخل پروژه ما

پیکربندی Webpack را اضافه کنید

Webpack یک بسته ماژول است که عمدتاً برای برنامه های جاوا اسکریپت استفاده می شود. از آنجایی که TypeScript به جاوا اسکریپت ساده کامپایل می شود، Webpack به طور موثر کد ما را برای مرورگر وب آماده می کند. ما دو کتابخانه و یک لودر سفارشی نصب خواهیم کرد:

npm i --save-dev webpack webpack-cli ts-loader

دستور ساخت AWS SAM CLI، sam build، روند توسعه را کند می کند زیرا سعی می کند اجرا شود npm install برای هر تابع، باعث تکرار. ما از یک دستور ساخت جایگزین استفاده خواهیم کرد پلاگین aws-sam-webpack کتابخانه برای سرعت بخشیدن به محیط ما

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: این شیء ورودی (جایی که Webpack شروع به ساخت بسته نرم افزاری می کند) را از قسمت بارگیری می کند AWS::Serverless::Function منبع
  • output: این به مقصد خروجی ساخت اشاره می کند (در این مورد، .aws-sam/build). در اینجا کتابخانه هدف را نیز به عنوان مشخص می کنیم commonjs2، که مقدار بازگشتی نقطه ورودی را به آن اختصاص می دهد module.exports. این نقطه ورودی پیش فرض برای محیط های Node.js است.
  • devtool: این یک نقشه منبع ایجاد می کند، app.js.map، در مقصد خروجی ساخت ما. کد اصلی ما را به کدهای در حال اجرا در مرورگر وب نگاشت می کند و اگر متغیر محیط را تنظیم کنیم به اشکال زدایی کمک می کند. NODE_OPTIONS به --enable-source-maps برای لامبدای ما
  • resolve: این به Webpack می گوید که فایل های TypeScript را قبل از فایل های JavaScript پردازش کند.
  • target: این به Webpack می گوید که Node.js را به عنوان محیط ما مورد هدف قرار دهد. این بدان معناست که Webpack از Node.js استفاده خواهد کرد require عملکردی برای بارگذاری تکه ها هنگام کامپایل کردن.
  • module: این لودر TypeScript را برای همه فایل هایی که مطابق با آن هستند اعمال می کند test وضعیت. به عبارت دیگر، تضمین می کند که تمام فایل های دارای a .ts یا .tsx پسوند توسط لودر مدیریت خواهد شد.
  • plugins: این به Webpack کمک می کند تا ما را شناسایی و استفاده کند aws-sam-webpack-plugin.

در خط اول، یک قانون ESLint خاص را برای این فایل غیرفعال کرده ایم. قوانین استاندارد ESLint که بعداً پیکربندی خواهیم کرد، استفاده از آن را متوقف می کنیم require بیانیه. ما ترجیح می دهیم require به import در Webpack بنابراین ما یک استثنا قائل می شویم.

پشتیبانی 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 پوشه – ما مستقیماً این کد را لمس نمی کنیم.

یک تابع لامبدا ایجاد کنید

ما تاکنون هیچ کد لامبدا برای برنامه بدون سرور خود ننوشته ایم، پس بیایید وارد آن شویم. src پوشه ای که قبلا ایجاد کردیم، a ایجاد می کنیم test-lambda زیر پوشه حاوی یک app.ts فایل با این تابع لامبدا:

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 به a نیاز دارد فایل قالب برای انتقال کد ما و استقرار آن در فضای ابری. فایل را ایجاد کنید 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

وقتی از نقطه پایانی آزمون در الف بازدید می کنیم مرورگر اینترنت، باید پیام موفقیت را ببینیم.

مرورگر وب لینک را نشان می دهد "127.0.0.1:3000/تست" در نوار آدرس  در زیر نوار آدرس، صفحه وب خالی است به جز پیامی با خواندن

کنسول باید نشان دهد که این تابع قبل از اجرا در یک ظرف 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

در مرحله بعد، با ایجاد یک فایل پیکربندی ESLint، لینتر خود را اضافه می کنیم. .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"]
            }
        }
    }
}

توجه داشته باشید که extends بخش فایل ما باید پیکربندی افزونه Prettier را به عنوان آخرین خط نگه دارد تا خطاهای زیباتر را به عنوان خطاهای ESLint در ویرایشگر ما نشان دهد. ما ESLint را دنبال می کنیم تنظیمات توصیه شده برای TypeScript، با برخی از اولویت های سفارشی اضافه شده در rules بخش. با خیال راحت مرور کنید قوانین موجود و تنظیمات خود را بیشتر سفارشی کنید. ما انتخاب کردیم که شامل موارد زیر باشد:

  • اگر از رشته های تک نقل قولی استفاده نکنیم یک خطا رخ می دهد.
  • یک هشدار زمانی که ما ارائه می دهیم نه default مورد در switch بیانیه.
  • اگر هر پارامتری از یک تابع را مجدداً اختصاص دهیم یک هشدار.
  • اخطار اگر با an تماس بگیریم 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 را در ویرایشگر خود فعال کنید اگر قبلاً تنظیم نشده اند.

ویرایشگر یک خط کد را نمایش می دهد که مقداری را به متغیر اختصاص می دهد "اجازه دهید پاسخ دهد" خط یک لامپ زرد رنگ در کنار آن و کلمه را نشان می دهد "واکنش" دارای یک خط زیر قرمز و یک پاپ آپ خطا در بالای آن است.  پاپ آپ خطا ابتدا متغیر را تعریف می کند "واکنش" و می خواند: "let answer: { statusCode: number;  بدنه: رشته  }." در زیر تعریف، پیام خطا به شرح زیر است: "

کد را با Jest Testing حفظ کنید

بسیاری از کتابخانه ها مانند Jest، Mocha و Storybook برای آزمایش در دسترس هستند. ما استفاده خواهیم کرد است در پروژه ما به چند دلیل:

  • یادگیری آن سریع است.
  • به حداقل تنظیمات نیاز دارد.
  • این آزمایش عکس فوری با استفاده آسان را ارائه می دهد.

بیایید وابستگی های مورد نیاز را نصب کنیم:

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: این آرایه از الگوهای glob شامل پسوندهای فایلی است که فایل های 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 از کریستین لوف برای بررسی نمونه کدهای ارائه شده در این مقاله تشکر می کند.

لوگوی AWS با کلمه
Toptal به عنوان یک شریک مشاوره پیشرفته در شبکه شریک آمازون (APN)، به شرکت‌ها امکان دسترسی به کارشناسان دارای گواهینامه AWS را در صورت تقاضا، در هر نقطه از جهان می‌دهد.


ادامه مطلب در وبلاگ مهندسی تاپتال:



منبع

Matthew Newman

Matthew Newman Matthew has over 15 years of experience in database management and software development, with a strong focus on full-stack web applications. He specializes in Django and Vue.js with expertise deploying to both server and serverless environments on AWS. He also works with relational databases and large datasets
[ Back To Top ]