在 TypeScript 中使用 AWS CDK - AWS Cloud Development Kit (AWS CDK) v2

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。

在 TypeScript 中使用 AWS CDK

TypeScript 是一种 AWS Cloud Development Kit (AWS CDK) 完全支持且视为稳定的客户端语言。在 TypeScript 中使用 AWS CDK 采用了熟悉的工具,包括 Microsoft 的 TypeScript 编译器 (tsc)、Node.js 和节点包管理器 (npm)。如果您愿意,也可以使用 Yarn,不过本指南中的示例使用的是 NPM。通过 NPM 存储库 npmjs.org 来分发构成 AWS 构造库的模块。

您可以使用任何编辑器或 IDE。许多 AWS CDK 开发人员都使用 Visual Studio Code(或其开源等效版本 VSCodium),该编辑器可为 TypeScript 提供卓越支持。

开始使用 TypeScript

要使用 AWS CDK,您必须拥有 AWS 账户和凭证,并已安装 Node.js 和 AWS CDK Toolkit。请参阅 开始使用 AWS CDK

您还需要 TypeScript 本身(版本 3.8 或更高版本)。如果您还没有 TypeScript,可使用 npm 进行安装。

npm install -g typescript
注意

如果遇到权限错误,且在系统上拥有管理员访问权限,请尝试 sudo npm install -g typescript

通过定期的 npm update -g typescript 让 TypeScript 保持为最新版本。

注意

第三方语言弃用:语言版本仅在供应商或社区共享其 EOL(生命周期终止)之前才受支持,如有更改,会另行通知。

创建项目

您可以通过在空目录中调用 cdk init 来创建一个新的 AWS CDK 项目。使用 --language 选项并指定 typescript

mkdir my-project cd my-project cdk init app --language typescript

创建项目还会安装 aws-cdk-lib 模块及其依赖项。

cdk init 使用项目文件夹的名称来命名项目的各种元素,包括类、子文件夹和文件。文件夹名称中的连字符都将转换为下划线。但是,名称应遵循 TypeScript 标识符的形式;例如,名称不应以数字开头,也不应包含空格。

使用本地 tsccdk

在大多数情况下,本指南假设您已全局安装 TypeScript 和 CDK Toolkit (npm install -g typescript aws-cdk),并且提供的命令示例(例如 cdk synth)也遵循此假设。这种方法可以很容易让两个组件保持为最新版本,并且由于两者都采取了严格的向后兼容性方法,所以始终使用最新版本通常风险很小。

有些团队更喜欢在每个项目中指定所有依赖项,包括 TypeScript 编译器和 CDK Toolkit 等工具。通过这种做法,您可以将这些组件固定到特定版本,并确保团队中的所有开发人员(以及您的 CI/CD 环境)都正好使用这些版本。这从根源上消除了可能发生的变更,有助于使构建和部署更加一致且可重复。

CDK 在 TypeScript 项目模板的 package.json 中包含了 TypeScript 和 CDK Toolkit 的依赖项,因此,如果您想使用这种方法,无需对项目进行任何更改。您所需要做的就是使用稍微不同的命令来构建应用程序以及发出 cdk 命令。

操作 使用全局工具 使用本地工具
初始化项目 cdk init --language typescript npx aws-cdk init --language typescript
构建 tsc npm run build
运行 CDK Toolkit 命令 cdk ... npm run cdk ... or npx aws-cdk ...

npx aws-cdk 运行当前项目中本地安装的 CDK Toolkit 版本(如果存在),如有则回退到全局安装。如果不存在全局安装,则 npx 会下载 CDK Toolkit 的临时副本并运行该副本。您可以使用 @ 语法(npx aws-cdk@2.0 --version 打印 2.0.0)来指定 CDK Toolkit 的任意版本。

提示

设置别名,以便您可以在安装本地 CDK Toolkit 时使用 cdk 命令。

macOS/Linux
alias cdk="npx aws-cdk"
Windows
doskey cdk=npx aws-cdk $*

管理 AWS 构造库模块

使用节点软件包管理器 (npm) 来安装和更新供您应用程序使用的 AWS 构造库模块以及您需要的其他软件包。(如果您愿意,可以用 yarn 代替 npm。)npm 还会自动安装这些模块的依赖项。

大多数 AWS CDK 构造都位于名为 aws-cdk-lib 的 CDK 主包中,这是 cdk init 创建的新项目中的默认依赖项。“实验性”AWS 构造库模块(其中更高级别的构造仍在开发中)的命名类似于 @aws-cdk/SERVICE-NAME-alpha。服务名称带有 aws- 前缀。如果您不确定某个模块的名称,请在 NPM 上进行搜索

注意

CDK API Reference 也显示了包名称。

例如,以下命令用于安装 AWS CodeStar 的实验模块。

npm install @aws-cdk/aws-codestar-alpha

某些服务的构造库支持位于多个命名空间中。例如,除 aws-route53 之外,还有另外三个 Amazon Route 53 命名空间,分别是 aws-route53-targetsaws-route53-patternsaws-route53resolver

您项目的依赖项在 package.json 中进行维护。您可以编辑此文件,将部分或全部依赖项锁定到特定版本,或者允许在特定条件下将其更新到较新版本。根据您在以下 package.json 中指定的规则,将项目的 NPM 依赖项更新到允许的最新版本:

npm update

在 TypeScript 中,您可以将模块导入到代码中,其名称与使用 NPM 安装模块时使用的名称相同。在应用程序中导入 AWS CDK 类和 AWS 构造库模块时,我们建议采用以下做法。遵循这些准则将有助于让您的代码与其他 AWS CDK 应用程序保持一致并更易于理解。

  • 请使用 ES6 风格的 import 指令,而非 require()

  • 通常,从 aws-cdk-lib 中导入单个类。

    import { App, Stack } from 'aws-cdk-lib';
  • 如果您需要 aws-cdk-lib 中的许多类,则可以使用 cdk 的命名空间别名,而不是导入单个类。避免同时执行这两项操作。

    import * as cdk from 'aws-cdk-lib';
  • 通常,使用短命名空间别名来导入 AWS 服务构造。

    import { aws_s3 as s3 } from 'aws-cdk-lib';

在 TypeScript 中管理依赖项

在 TypeScript CDK 项目中,在项目主目录的 package.json 文件中指定依赖项。核心 AWS CDK 模块位于名为 aws-cdk-lib 的单个 NPM 包中。

当您使用 npm install 来安装包时,NPM 会在 package.json 中记录该包。

如果您愿意,可以用 Yarn 代替 NPM。但是,CDK 不支持 Yarn 的即插即用模式,该模式是 Yarn 2 中的默认模式。将以下内容添加到项目的 .yarnrc.yml 文件以关闭此功能。

nodeLinker: node-modules

CDK 应用程序

以下是 cdk init --language typescript 命令生成的示例 package.json 文件:

{ "name": "my-package", "version": "0.1.0", "bin": { "my-package": "bin/my-package.js" }, "scripts": { "build": "tsc", "watch": "tsc -w", "test": "jest", "cdk": "cdk" }, "devDependencies": { "@types/jest": "^26.0.10", "@types/node": "10.17.27", "jest": "^26.4.2", "ts-jest": "^26.2.0", "aws-cdk": "2.16.0", "ts-node": "^9.0.0", "typescript": "~3.9.7" }, "dependencies": { "aws-cdk-lib": "2.16.0", "constructs": "^10.0.0", "source-map-support": "^0.5.16" } }

对于可部署的 CDK 应用程序,必须在 package.jsondependencies 部分中指定 aws-cdk-lib。您可以使用脱字符(^)版本号说明符来表示您将接受比指定版本更高的版本,前提是它们位于同一个主版本内。

对于实验性构造,请为 alpha 构造库模块指定确切版本,这些模块的 API 可能会发生更改。请勿使用 ^ 或 ~,因为这些模块的更高版本可能会导致 API 发生更改,从而导致您的应用程序中断。

package.jsondevDependencies 部分中指定测试应用程序所需的库和工具版本(例如,jest 测试框架)。或者使用 ^ 来指定可接受更高版本的兼容版本。

第三方构造库

如果您正在开发构造库,请结合 peerDependenciesdevDependencies 部分来指定其依赖项,如以下示例 package.json 文件所示。

{ "name": "my-package", "version": "0.0.1", "peerDependencies": { "aws-cdk-lib": "^2.14.0", "@aws-cdk/aws-appsync-alpha": "2.10.0-alpha", "constructs": "^10.0.0" }, "devDependencies": { "aws-cdk-lib": "2.14.0", "@aws-cdk/aws-appsync-alpha": "2.10.0-alpha", "constructs": "10.0.0", "jsii": "^1.50.0", "aws-cdk": "^2.14.0" } }

peerDependencies 中,使用脱字符(^)来指定您的库所使用的 aws-cdk-lib 的最低版本。这样可以最大限度地提高您的库与一系列 CDK 版本的兼容性。为 alpha 构造库模块指定确切版本,这些模块的 API 可能会发生更改。使用 peerDependencies 可以确保 node_modules 树中所有 CDK 库副本只有一个副本。

devDependencies 中,指定测试所需的工具和库,也可以使用 ^ 来表示可以接受更高版本的兼容版本。确切指定(不带 ^ 或 ~)您宣称您的库与之兼容的 aws-cdk-lib 和其他 CDK 软件包的最低版本。这种做法可确保您的测试是针对这些版本运行的。这样,如果您无意中使用了仅较新版本中具备的功能,则您的测试可以将其捕捉到。

警告

只有 NPM 7 及更高版本才能自动安装 peerDependencies。如果您使用的是 NPM 6 或更早版本,或者使用的是 Yarn,则必须在 devDependencies 中包含依赖项的依赖项。否则,将不会进行安装,并且您将收到有关对等依赖项未解决的警告。

安装和更新依赖项

使用以下命令来安装项目的依赖项。

NPM
# Install the latest version of everything that matches the ranges in 'package.json' npm install # Install the same exact dependency versions as recorded in 'package-lock.json' npm ci
Yarn
# Install the latest version of everything that matches the ranges in 'package.json' yarn upgrade # Install the same exact dependency versions as recorded in 'yarn.lock' yarn install --frozen-lockfile

要更新已安装的模块,可以使用前面的 npm installyarn upgrade 命令。任一命令都会将 node_modules 中的软件包更新为可满足 package.json 中规则的最新版本。但是,它们不会更新 package.json 本身,您可能需要执行此操作来设置新的最低版本。如果您将包托管在 GitHub 上,则可以配置 Dependabot 版本更新 来自动更新 package.json。或者,可以使用 npm-check-updates

重要

根据设计,当您安装或更新依赖项时,NPM 和 Yarn 会选择可满足 package.json 中指定要求的每个包的最新版本。这些版本始终存在损坏风险(无论是无意还是有意)。更新项目的依赖项后,请彻底进行测试。

TypeScript 中的 AWS CDK 习语

Props

所有 AWS 构造库类都使用三个参数进行实例化:在其中定义构造的 scope(构造树中的父级)、idpropsprops 参数是键/值对捆绑包,构造使用这些键/值对来配置其创建的 AWS 资源。其他类和方法也使用“属性捆绑包”模式作为参数。

在 TypeScript 中,props 的形状是使用一个接口定义的,该接口可显示必需参数和可选参数及其类型。为每种 props 参数定义一个此类接口,通常特定于单个构造或方法。例如,存储桶构造(在 aws-cdk-lib/aws-s3 module 中)指定符合 BucketProps 接口的 props 参数。

如果属性本身就是一个对象,例如 BucketPropswebsiteRedirect 属性,则该对象将拥有自己的接口,其形状必须符合该接口,在本例中为 RedirectTarget

如果正在子类化一个 AWS 构造库类(或重写采用类似 props 参数的方法),则可以从现有接口继承来创建一个新接口,该新接口可指定您的代码所需的任何新 props。在调用父类或基方法时,通常可以传递收到的整个 props 参数,因为对象中提供但未在接口中指定的所有属性都将被忽略。

AWS CDK 的未来版本可能会碰巧添加一个新属性,其名称与您用于自己属性的名称相同。将收到的值沿继承链向上传递可能会导致意外行为。更安全的做法是传递您收到的 props 的浅副本,同时删除属性或将其设置为 undefined。例如:

super(scope, name, {...props, encryptionKeys: undefined});

或者,为您的属性命名,以便清楚地表明它们属于您的构造。这样,其就不太可能在未来的 AWS CDK 版本中与属性发生冲突。如果有很多属性,请使用一个适当命名的对象来存放它们。

缺失值

对象中的缺失值(例如 props)在 TypeScript 中的值为 undefined。该语言的 3.7 版本引入了简化处理这些值的运算符,这样在达到未定义的值时就能更容易指定默认值和“短路”链接。有关这些功能的更多信息,请参阅 TypeScript 3.7 发行说明,特别是前两个功能“可选链接”和“Null 值合并”。

构建和运行 CDK 应用程序

通常,构建和运行应用程序时,您应位于项目的根目录中。

Node.js 无法直接运行 TypeScript;相反,使用 TypeScript 编译器 tsc 将您的应用程序转换到 JavaScript。然后执行生成的 JavaScript 代码。

每当需要运行您的应用程序时,AWS CDK 都会自动执行此操作。但是,手动编译以检查错误并运行测试可能会很有用。要手动编译您的 TypeScript 应用程序,请发出 npm run build 命令。您也可以发出 npm run watch 命令进入监视模式,在这种模式下,每当您保存对源文件的更改时,TypeScript 编译器都会自动重建您的应用程序。