作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
穆罕默德·费萨尔的头像

Mohammad Faisal

Mohammad是一名全栈开发人员,他使用Lambda在AWS上构建了多个应用程序, NoSQL, and Node.js. 他在为中型公司优化AWS基础设施方面拥有丰富的经验.

Previously At

Cruise
Share

构建无服务器应用程序的强大工具 AWS 无服务器应用模型(SAM)经常与JavaScript配对: 62% 许多大中型公司的开发人员选择JavaScript编写无服务器代码. 然而,TypeScript的受欢迎程度正在飙升,并且远远超过了JavaScript。 third-most-loved language.

而JavaScript样板并不难找到, 用TypeScript启动AWS SAM项目要复杂得多. 下面的教程展示了如何从头开始创建一个AWS SAM TypeScript项目,以及不同部分是如何协同工作的. 读者只需要稍微熟悉一下 AWS Lambda functions to follow along.

启动AWS SAM TypeScript项目

我们的无服务器应用程序的基础包括各种组件. 我们将首先配置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:这将加载条目对象(Webpack开始构建bundle的地方) AWS::Serverless::Function resource.
  • output:这指向构建输出的目的地(在本例中, .aws-sam/build). 这里我们还将目标库指定为 commonjs2,它将入口点的返回值赋给 module.exports. 这个入口点是Node的默认入口点.js environments.
  • devtool:这将创建一个源映射, app.js.map,在我们的构建输出目的地. 它将我们的原始代码映射到web浏览器中运行的代码,如果我们设置了环境变量,它将有助于调试 NODE_OPTIONS to --enable-source-maps for our Lambda.
  • resolve这告诉Webpack在处理JavaScript文件之前先处理TypeScript文件.
  • target:这告诉Webpack要瞄准Node.js as our environment. 这意味着Webpack将使用Node.js require 函数,用于在编译时加载块.
  • module:这将把TypeScript加载器应用到所有满足 test condition. 换句话说,它确保所有带有 .ts or .tsx 扩展将由加载器处理.
  • plugins:这有助于Webpack识别和使用我们的 aws-sam-webpack-plugin.

在第一行中,我们为这个文件禁用了一个特定的ESLint规则. 我们稍后将配置的ESLint标准规则不鼓励使用 require statement. We prefer require to import 在Webpack中,所以我们会做一个例外.

Set Up TypeScript Support

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

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

First, 我们将在本地为我们的项目安装TypeScript(如果你是全局安装TypeScript,请跳过这一步):

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

到目前为止,我们还没有为我们的无服务器应用程序编写任何Lambda代码,所以让我们开始吧. 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

该模板文件生成一个可从HTTP GET API访问的Lambda函数. 中引用的版本 Runtime: line may need customizing.

Run the Application

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

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

If you run npm run build 在项目的根目录下,您应该看到构建文件夹, .aws-sam, created. 在Mac环境中,我们可能需要通过按下键来显示隐藏文件 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."}.

控制台应该显示该函数在运行之前已挂载到Docker容器中, 这就是我们之前安装Docker的原因:

Invoking app.handler (nodejs14.x)
跳过拉图,使用本地图片:public.ecr.aws / sam / emulation-nodejs14.x:rapid-1.37.0-x86_64.

安装/用户/ mohammadfaisal /文件/学习/ aws-sam-typescript-boilerplate /.aws-sam/build/TestLambda作为/var/task:ro,委托在运行时容器内

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

我们的项目已经开始运行了, 添加一些最后的润色将确保出色的开发体验,从而提高生产力和协作.

优化构建与热重新加载

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

"watch": "webpack-cli -w"

打开一个单独的终端并运行 npm run watch. 现在,当您更改任何代码时,您的项目将自动编译. 修改代码的消息,刷新网页,并查看更新后的结果.

使用ESLint和Prettier提高代码质量

没有ESLint和Prettier, TypeScript或JavaScript项目是不完整的. 这些工具将保持项目的代码质量和一致性.

让我们先安装核心依赖:

NPM I——save-dev eslint prettier

我们将添加一些helper依赖项,这样ESLint和Prettier就可以在TypeScript项目中协同工作:

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 部分必须将Prettier插件配置放在最后一行,以便在编辑器中以ESLint错误的形式显示Prettier错误. 我们遵循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.
  • 对于未使用变量的错误,随着时间的推移,这会使代码不可读并且容易出错.

我们已经设置了ESLint配置来使用更漂亮的格式. (更多信息可在 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. 编辑器应该显示一个错误、被破坏的规则和修复代码的建议. 不要忘记在你的编辑器上启用ESLint和Prettier,如果它们还没有设置好的话.

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测试维护代码

有许多库可用于测试,例如Jest、Mocha和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:这个数组包含了要搜索测试文件的文件夹——它只检查我们的 src subfolder.
  • testMatch:这个glob模式数组包括将被视为Jest文件的文件扩展名.
  • 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,迎接我们的应该是一个合格的测试:

控制台的顶部显示一个绿色的“通过”指示灯和测试文件名, " src / test-lambda / __tests__ /处理程序.test.ts.下一行是“演示测试。.下一行显示了一个绿色的复选标记,后面跟着“这是测试工作的概念证明”. (1 ms).在空白行之后,第一行是:“测试套件:1个通过,总共1个。.第二个是:“考试: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. 我们专注于ESLint的基础知识,并保持高质量的代码, Prettier, and Jest support. 本AWS SAM教程中的示例可以作为一个蓝图, 让你的下一个大项目从一开始就步入正轨.

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

带有“合作伙伴”字样的AWS徽标及其下方标有“高级服务”字样.


Understanding the basics

  • What is AWS SAM?

    AWS无服务器应用模型(SAM)是一个开源AWS框架,允许开发人员更有效地构建无服务器应用程序. 它包括用于本地测试的SAM CLI选项,并与各种AWS无服务器工具集成.

  • How does SAM work?

    AWS SAM使用简单语法来表示函数、api、数据库和事件源映射. 它提供了一个YAML模板来对应用程序建模,并提供了单个部署配置.

  • 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是一名全栈开发人员,他使用Lambda在AWS上构建了多个应用程序, NoSQL, and Node.js. 他在为中型公司优化AWS基础设施方面拥有丰富的经验.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Previously At

Cruise

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

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

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

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

Toptal Developers

Join the Toptal® community.