authors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.
穆罕默德·费萨尔的头像

Mohammad Faisal

Mohammad is a full-stack developer who has architected several applications on AWS using Lambda, NoSQL, and Node.js. He has extensive experience in optimizing AWS infrastructure for midsized companies.

Previously At

Cruise
Share

构建无服务器应用程序的强大工具 AWS 无服务器应用模型(SAM)经常与JavaScript配对: 62% of developers across medium and large companies choose JavaScript for their serverless code. However, TypeScript is soaring in popularity and far outranks JavaScript as developers’ third-most-loved language.

而JavaScript样板并不难找到, 用TypeScript启动AWS SAM项目要复杂得多. The following tutorial shows how to create an AWS SAM TypeScript project from scratch as well as how the different parts work together. 读者只需要稍微熟悉一下 AWS Lambda functions to follow along.

启动AWS SAM TypeScript项目

The groundwork of our serverless application includes various components. 我们将首先配置AWS环境, our npm package, 和Webpack功能-然后我们可以创建, invoke, 并测试Lambda函数以查看应用程序的运行情况.

Prepare the Environment

为了搭建AWS环境,我们需要安装以下组件:

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

注意,本教程需要安装 Docker 在上面的第2步中本地测试我们的应用程序.

初始化空项目

让我们创建项目目录, aws-sam-typescript-boilerplate, and a src subfolder to hold code. 从项目目录中,我们将建立一个新的npm包:

NPM init - y# -y选项跳过项目问卷

该命令将创建一个 package.json file inside our project.

添加Webpack配置

Webpack是一个主要用于JavaScript应用程序的模块打包器. 因为TypeScript编译成纯JavaScript, Webpack将有效地为web浏览器准备我们的代码. 我们将安装两个库和一个自定义加载器:

NPM I——save-dev webpack

AWS SAM CLI构建命令, sam build,因为它试图运行,所以减慢了开发过程 npm install 对于每个函数,导致重复. 控件中的另一个构建命令 aws-sam-webpack-plugin 图书馆加速我们的环境.

NPM I——save-dev -sam-webpack-plugin

默认情况下,Webpack不提供配置文件. 让我们创建一个自定义配置文件 webpack.config.js in the root folder:

/* eslint-disable @typescript-eslint/no-var-require */
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: This loads the entry object (where Webpack starts building the bundle) from the AWS::Serverless::Function resource.
  • output:这指向构建输出的目的地(在本例中, .aws-sam/build). 这里我们还将目标库指定为 commonjs2,它将入口点的返回值赋给 module.exports. 这个入口点是Node的默认入口点.js environments.
  • devtool:这将创建一个源映射, app.js.map,在我们的构建输出目的地. It maps our original code to the code running in the web browser and will help with debugging if we set the environment variable NODE_OPTIONS to --enable-source-maps for our Lambda.
  • resolve: This tells Webpack to process TypeScript files before JavaScript files.
  • target:这告诉Webpack要瞄准Node.js as our environment. 这意味着Webpack将使用Node.js require 函数,用于在编译时加载块.
  • module:这将把TypeScript加载器应用到所有满足 test condition. 换句话说,它确保所有带有 .ts or .tsx 扩展将由加载器处理.
  • plugins:这有助于Webpack识别和使用我们的 aws-sam-webpack-plugin.

In the first line, we have disabled a particular ESLint rule for this file. 我们稍后将配置的ESLint标准规则不鼓励使用 require statement. We prefer require to import 在Webpack中,所以我们会做一个例外.

Set Up TypeScript Support

添加TypeScript支持将改进 developer experience by:

  • 防止关于缺少类型声明的警告消息.
  • Providing type validation.
  • 在IDE内提供自动完成功能.

First, we’ll install TypeScript for our project locally (skip this step if you have TypeScript installed globally):

NPM I——save-dev typescript

我们将包括我们正在使用的库的类型:

@types/node @ webpack @types/aws-lambda

现在,我们要创建TypeScript配置文件, tsconfig.json, in the project root:

{
    "compilerOptions": {
        "target": "ES2015",
        "module": "commonjs",
        "sourceMap": true,
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        “forceConsistentCasingInFileNames”:没错,
    },
    "include": ["src/**/*.ts", "src/**/*.js"],
    “排除”(“node_modules”):
}

Here we are following the default configuration 由TypeScript社区推荐. We have added include 将文件追加到 src folder to the program and exclude 来避免TypeScript编译 node_modules 文件夹——我们不会直接触及这段代码.

Create a Lambda Function

We haven’t written any Lambda code for our serverless application until now, so let’s jump in. In the src 我们之前创建的文件夹,我们将创建一个 test-lambda subfolder containing an app.ts 使用Lambda函数创建文件:

从'aws-lambda'中导入{APIGatewayEvent};

export const handler = async (event: APIGatewayEvent) => {
    console.. log('传入的事件是',JSON.stringify(event));
    const response = {
        statusCode: 200,
        body: JSON.stringify({message: '请求成功.' })
    };
    return response;
};

这个简单的占位符函数返回一个带有body的200响应. 我们将能够运行一个步骤后的代码.

包括AWS模板文件

AWS SAM requires a template file 翻译我们的代码并将其部署到云端. Create the file template.yaml in the root folder:

AWSTemplateFormatVersion:“2010-09-09”
变换:AWS:: serverless - 2016 - 10 - 31所示
描述:使用TypeScript的AWS SAM样板文件

Globals:
  Function:
    Runtime: nodejs14.根据您的需要修改版本
    Timeout: 30
    
Resources:
  TestLambda:
    类型:AWS: Serverless:函数
    Properties:
      Handler: app.handler
      FunctionName:“Test-Lambda”
      CodeUri: src/test-lambda/
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /test
            Method: get

This template file generates a Lambda function accessible from an HTTP GET API. 中引用的版本 Runtime: line may need customizing.

Run the Application

要运行该应用程序,我们必须在 package.json 文件,用于使用Webpack构建项目. 该文件可能有现有的脚本,比如一个空的测试脚本. 我们可以像这样添加构建脚本:

"scripts": {
   "build": "webpack-cli"
}

If you run npm run build 在项目的根目录下,您应该看到构建文件夹, .aws-sam, created. Those of us in a Mac environment may need to make hidden files visible by pressing Command + Shift + . to see the folder.

现在我们将启动一个本地HTTP服务器来测试我们的函数:

sam local start-api

当我们访问a中的测试端点时 web browser,我们应该看到成功消息.

The web browser shows the link "127.0.0.1:3000/test" in the address bar. Below the address bar, the webpage is blank except for a message reading '{"message": "Request was successful."}.

The console should show that the function gets mounted in a Docker container before it runs, 这就是我们之前安装Docker的原因:

Invoking app.handler (nodejs14.x)
跳过拉图,使用本地图片: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

为专业设置增强我们的开发工作流程

我们的项目已经开始运行了, adding a few finishing touches will ensure an exceptional developer experience that will boost productivity and collaboration.

优化构建与热重新加载

在每次代码更改之后运行构建命令是非常繁琐的. 热重装将解决这个问题. 我们可以在我们的 package.json 要查看文件更改:

"watch": "webpack-cli -w"

打开一个单独的终端并运行 npm run watch. 现在,当您更改任何代码时,您的项目将自动编译. Modify the message of the code, refresh your webpage, and see the updated result.

使用ESLint和Prettier提高代码质量

No TypeScript or JavaScript project is complete without ESLint and Prettier. 这些工具将保持项目的代码质量和一致性.

让我们先安装核心依赖:

NPM I——save-dev eslint prettier

We will add some helper dependencies so ESLint and Prettier can work together in our TypeScript project:

npm i --save-dev \
eslint-config-prettier \
eslint-plugin-prettier \
@typescript-eslint /解析器\
@typescript-eslint / eslint-plugin

接下来,我们将通过创建ESLint配置文件来添加我们的过滤器, .eslintrc,在项目根目录下:

{
    "root": true,
    "env": {
        "es2020": true,
        "node": true,
        "jest": true
    },
    “解析”:“@typescript-eslint /解析器”,
    "extends": [
        "eslint:recommended",
        “插件:@typescript-eslint /推荐”,
        “插件:漂亮/推荐”
    ],
    “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”:“警告”,
        “no-await-in-loop”:“警告”,
        “@typescript-eslint / no-unused-vars”:(
            "error",
            {
                "vars": "all",
                "args": "none"
            }
        ]
    },
    "settings": {
        "import/resolver": {
            "node": {
                "extensions": [".js", ".jsx", ".ts", ".tsx"]
            }
        }
    }
}

Note that the extends section of our file must keep the Prettier plugin configuration as the last line in order to display Prettier errors as ESLint errors visible in our editor. 我们遵循ESLint recommended settings 中添加了一些自定义首选项 rules section. Feel free to browse available rules 并进一步自定义您的设置. We chose to include:

  • 如果不使用单引号字符串则会出现错误.
  • 当我们提供no时发出警告 default case in switch statements.
  • 如果对函数的任何形参重新赋值,将发出警告.
  • A warning if we call an await statement inside a loop.
  • An error for unused variables, which make code unreadable and bug-prone over time.

We have already set up our ESLint configuration to work with Prettier formatting. (更多信息可在 eslint-config-prettier GitHub project.)现在,我们可以创建Prettier配置文件, .prettierrc:

{
    "trailingComma": "none",
    "tabWidth": 4,
    "semi": true,
    "singleQuote": true
}

这些布景来自美缇埃 official documentation; you can modify them as you desire. 我们更新了以下属性:

  • trailingComma: We changed this from es5 to none to avoid trailing commas.
  • semi: We changed this from false to true 因为我们更喜欢在每行的末尾有一个分号.

最后,是时候看看ESLint和Prettier的实际应用了. In our app.ts file, we’ll change the response variable type from const to let. Using let 是不是在这种情况下的好做法既然我们不修改的值 response. The editor should display an error, the broken rule, and suggestions to fix the code. Don’t forget to enable ESLint and Prettier on your editor if they are not set up already.

The editor displays a line of code assigning a value to the variable "let response." The line shows a yellow lightbulb next to it, and the word "response" has a red underline and an error pop-up above it. The error pop-up first defines the variable "response" and reads: "let response: { statusCode: number; body: string; }." Below the definition, the error message reads: "'response' is never reassigned. Use 'const' instead. eslint(prefer-const)." Below the error message, two options read: "View Problem" or "Quick Fix."

用Jest测试维护代码

Many libraries are available for testing, such as Jest, Mocha, and Storybook. We will use Jest 在我们的项目中有几个原因:

  • It’s fast to learn.
  • It requires minimal setup.
  • 它提供了易于使用的快照测试.

让我们安装所需的依赖项:

NPM I—save-dev jest -jest @types/jest

接下来,我们将创建一个Jest配置文件, jest.config.js,在项目根目录下:

module.exports = {
    roots: ['src'],
    testMatch: [' * * / __tests__ / * * / *.+(ts|tsx|js)'],
    transform: {
        '^.+\\.(ts|tsx)$': 'ts-jest'
    }
};

我们在文件中定制了三个选项:

  • roots: This array contains the folders that will be searched for test files—it only checks beneath our src subfolder.
  • testMatch: This array of glob patterns includes the file extensions that will be considered Jest files.
  • transform:这个选项允许我们在TypeScript中使用 ts-jest package.

Let’s make a new __tests__ folder inside src/test-lambda. 在其中,我们将添加文件 handler.test.ts,在这里我们将创建第一个测试:

import { handler } from '../app';
const event: any = {
    body: JSON.stringify({}),
    headers: {}
};

describe('Demo test', () => {
    这是测试有效的概念证明.', async () => {
        Const res = await handler(事件);
        expect(res.statusCode).toBe(200);
    });
});

We will return to our package.json 用测试脚本文件并更新它:

"test": "jest"

当我们跑到终点站的时候 npm run test,迎接我们的应该是一个合格的测试:

The top of the console shows a green "Pass" indicator and the test file name, " src / test-lambda / __tests__ /处理程序.test.ts.下一行是“演示测试。." The next line shows a green check mark followed by "This is the proof of concept that the test works. (1 ms)." After a blank line, the first line reads: "Test Suites: 1 passed, 1 total.第二个是:“考试:1次通过,1次总分。.第三个是:“快照:总共0个。.第四个写着:“时间:0。.959 s.最后一行是:“运行所有的测试套件。."

处理源代码控制 .gitignore

我们应该将Git配置为从源代码管理中排除某些文件. We can create a .gitignore file using 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

#可选的npm缓存目录
.npm

# Optional ESLint cache
.eslintcache

准备,设置,构建:我们的成功蓝图

我们现在有了一个完整的AWS SAM boilerplate project with TypeScript. We’ve focused on getting the basics right and maintaining high code quality with ESLint, Prettier, and Jest support. 本AWS SAM教程中的示例可以作为一个蓝图, 让你的下一个大项目从一开始就步入正轨.

Toptal Engineering博客向 Christian Loef 查看本文中提供的代码示例.

The AWS logo with the word "PARTNER" and the text "Advanced Tier Services" below that.


Understanding the basics

  • What is AWS SAM?

    The AWS Serverless Application Model (SAM) is an open-source AWS framework that allows developers to more efficiently build serverless applications. It includes SAM CLI options for local testing and integrates with various AWS serverless tools.

  • How does SAM work?

    AWS SAM uses simple syntax to express functions, APIs, databases, and event source mappings. It provides a YAML template to model the application and offers single deployment configuration.

  • What is Jest/TypeScript?

    Jest is a testing framework; TypeScript is a programming language. More specifically, Jest通过测试检查代码库的正确性, JavaScript codebases). TypeScript enables IDEs to catch mistakes while coding and improves development workflow; it is a strict syntactical superset of JavaScript.

就这一主题咨询作者或专家.
Schedule a call
穆罕默德·费萨尔的头像
Mohammad Faisal

Located in 达卡,达卡区,孟加拉国

Member since July 19, 2021

About the author

Mohammad is a full-stack developer who has architected several applications on AWS using Lambda, NoSQL, and Node.js. He has extensive experience in optimizing AWS infrastructure for midsized companies.

Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

Previously At

Cruise

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.