

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 为运行时打包 TypeScript、和源映射 `APPSYNC_JS`
<a name="additional-utilities"></a>

TypeScript 通过提供类型安全和早期错误检测来增强 AWS AppSync 开发。你可以在本地编写 TypeScript 代码，然后将其转换为， JavaScript 然后再将其与`APPSYNC_JS`运行时一起使用。该过程从为环境安装 TypeScript 和配置 tsconfig.json 开始。`APPSYNC_JS`然后，您可以使用 esbuild 等捆绑工具编译和捆绑代码。Amplify CLI 将从 GraphQL 架构生成类型，您可以在解析器代码中使用这些类型。

您可以在解析器和函数代码中使用自定义库和外部库，只要这些库符合 `APPSYNC_JS` 要求即可。捆绑工具将代码合并到单个文件中以供在中使用。 AWS AppSync可以包含源映射，以帮助调试。

## 使用库并捆绑您的代码
<a name="using-external-libraries"></a>

在您的解析器和函数代码中，您可以使用自定义库和外部库，只要它们符合 `APPSYNC_JS` 要求即可。这样，就可以在应用程序中重复使用现有的代码。要使用由多个文件定义的库，必须使用捆绑工具（例如 [esbuild](https://esbuild.github.io/)）将代码合并到一个文件中，然后将其保存到 AWS AppSync 解析器或函数中。

在捆绑代码时，请记住以下几点：
+ `APPSYNC_JS`仅支持 ECMAScript 模块 (ESM)。
+ `@aws-appsync/*` 模块集成到 `APPSYNC_JS` 中，不应将其与您的代码捆绑在一起。
+ `APPSYNC_JS` 运行时系统与 NodeJS 类似，即，不会在浏览器环境中运行代码。
+ 您可以包含可选的源映射。不过，不要包含源内容。

  要了解源映射的更多信息，请参阅[使用源映射](#source-maps)。

例如，要捆绑位于 `src/appsync/getPost.resolver.js` 中的解析器代码，您可以使用以下 esbuild CLI 命令：

```
$ esbuild --bundle \
--sourcemap=inline \
--sources-content=false \
--target=esnext \
--platform=node \
--format=esm \
--external:@aws-appsync/utils \
--outdir=out/appsync \
 src/appsync/getPost.resolver.js
```

## 构建您的代码并使用 TypeScript
<a name="working-with-typescript"></a>

[TypeScript](https://www.typescriptlang.org/)是一种由 Microsoft 开发 JavaScript的编程语言，它提供所有功能以及 TypeScript 打字系统。在将代码保存 TypeScript 到之前，您可以使用编写类型安全的代码并在构建时捕获错误和错误。 AWS AppSync`@aws-appsync/utils` 包是完全类型化的。

`APPSYNC_JS`运行时不 TypeScript 直接支持。在将 TypeScript 代码保存到之前，必须先将 JavaScript 代码转换为`APPSYNC_JS`运行时支持的代码。 AWS AppSync您可以使用 TypeScript 在本地集成开发环境 (IDE) 中编写代码，但请注意，您无法在 AWS AppSync 控制台中创建 TypeScript 代码。

首先，请确保已在项目中[TypeScript](https://www.typescriptlang.org/download)安装。然后，使用配置您的 TypeScript 转码设置以与`APPSYNC_JS`运行时配合使用[TSConfig](https://www.typescriptlang.org/tsconfig)。以下是您可以使用的基本 `tsconfig.json` 文件示例：

```
// tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
   "noEmit": true,
   "moduleResolution": "node",
  }
}
```

然后，您可以使用 esbuild 等捆绑工具编译和捆绑代码。例如，给定一个项目，你的 AWS AppSync 代码位于`src/appsync`，你可以使用以下命令来编译和捆绑你的代码：

```
$ esbuild --bundle \
--sourcemap=inline \
--sources-content=false \
--target=esnext \
--platform=node \
--format=esm \
--external:@aws-appsync/utils \
--outdir=out/appsync \
 src/appsync/**/*.ts
```

### 使用 Amplify codegen
<a name="working-with-amplify-codegen"></a>

您可以使用 [Amplify CLI](https://docs.amplify.aws/cli/) 生成架构的类型。从 `schema.graphql` 文件所在的目录中，运行以下命令并查看提示以配置 codegen：

```
$  npx @aws-amplify/cli codegen add
```

要在某些情况下（例如，更新架构时）重新生成 codegen，请运行以下命令：

```
$ npx @aws-amplify/cli codegen
```

然后，您可以在解析器代码中使用生成的类型。例如，给定以下架构：

```
type Todo {
  id: ID!
  title: String!
  description: String
}

type Mutation {
  createTodo(title: String!, description: String): Todo
}

type Query {
  listTodos: Todo
}
```

你可以在以下示例 AWS AppSync 函数中使用生成的类型：

```
import { Context, util } from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
import { CreateTodoMutationVariables, Todo } from './API' // codegen

export function request(ctx: Context<CreateTodoMutationVariables>) {
	ctx.args.description = ctx.args.description ?? 'created on ' + util.time.nowISO8601()
	return ddb.put<Todo>({ key: { id: util.autoId() }, item: ctx.args })
}

export function response(ctx) {
	return ctx.result as Todo
}
```

### 在中使用泛型 TypeScript
<a name="working-with-typescript-generics"></a>

您可以将泛型与提供的多种类型一起使用。例如，下面的代码片段是 `Todo` 类型：

```
export type Todo = {
  __typename: "Todo",
  id: string,
  title: string,
  description?: string | null,
};
```

您可以为使用 `Todo` 的订阅编写解析器。在您的 IDE 中，类型定义和自动完成提示将指导您正确使用 `toSubscriptionFilter` 转换实用程序：

```
import { util, Context, extensions } from '@aws-appsync/utils'
import { Todo } from './API'

export function request(ctx: Context) {
  return {}
}

export function response(ctx: Context) {
  const filter = util.transform.toSubscriptionFilter<Todo>({
    title: { beginsWith: 'hello' },
    description: { contains: 'created' },
  })
  extensions.setSubscriptionFilter(filter)
  return null
}
```

## 检查您的包
<a name="using-lint-with-bundles"></a>

您可以导入 `esbuild-plugin-eslint` 插件以自动检查您的包。然后，您可以提供启用 ESLint 功能的 `plugins` 值以启用该插件。以下是在名为的文件中使用 esbuild JavaScript API 的片段：`build.mjs`

```
/* eslint-disable */
import { build } from 'esbuild'
import eslint from 'esbuild-plugin-eslint'
import glob from 'glob'
const files = await glob('src/**/*.ts')

await build({
  format: 'esm',
  target: 'esnext',
  platform: 'node',
  external: ['@aws-appsync/utils'],
  outdir: 'dist/',
  entryPoints: files,
  bundle: true,
  plugins: [eslint({ useEslintrc: true })],
})
```

## 使用源映射
<a name="source-maps"></a>

您可以在 JavaScript 代码中提供内联源映射 (`sourcemap`)。当您打包 JavaScript 或 TypeScript 编写代码并希望在日志和运行时 JavaScript 错误消息中查看对输入源文件的引用时，源映射非常有用。

您的 `sourcemap` 必须出现在代码末尾。它是由采用以下格式的单个注释行定义的：

```
//# sourceMappingURL=data:application/json;base64,<base64 encoded string>
```

示例如下：

```
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsibGliLmpzIiwgImNvZGUuanMiXSwKICAibWFwcGluZ3MiOiAiO0FBQU8sU0FBUyxRQUFRO0FBQ3RCLFNBQU87QUFDVDs7O0FDRE8sU0FBUyxRQUFRLEtBQUs7QUFDM0IsU0FBTyxNQUFNO0FBQ2Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
```

可以使用 esbuild 创建源映射。以下示例向您展示了在构建和捆绑代码时如何使用 esbuild JavaScript API 来包含内联源映射：

```
/* eslint-disable */
import { build } from 'esbuild'
import eslint from 'esbuild-plugin-eslint'
import glob from 'glob'
const files = await glob('src/**/*.ts')

await build({
  sourcemap: 'inline',
  sourcesContent: false,
  
  format: 'esm',
  target: 'esnext',
  platform: 'node',
  external: ['@aws-appsync/utils'],
  outdir: 'dist/',
  entryPoints: files,
  bundle: true,
  plugins: [eslint({ useEslintrc: true })],
})
```

特别是，`sourcemap` 和 `sourcesContent` 选项指定应在每个构建末尾的行中添加源映射，但源映射不应包含源内容。作为惯例，我们建议不要在您的 `sourcemap` 中包含源内容。您可以将 `sources-content` 设置为 `false` 以在 esbuild 中禁用该功能。

要说明源映射的工作方式，请查看以下示例，其中解析器代码引用帮助程序库中的帮助程序函数。该代码在解析器代码和帮助程序库中包含日志语句：

**./src/default.resolver.ts**（您的解析器）

```
import { Context } from '@aws-appsync/utils'
import { hello, logit } from './helper'

export function request(ctx: Context) {
  console.log('start >')
  logit('hello world', 42, true)
  console.log('< end')
  return 'test'
}

export function response(ctx: Context): boolean {
  hello()
  return ctx.prev.result
}
```

**.src/helper.ts**（帮助程序文件）

```
export const logit = (...rest: any[]) => {
  // a special logger
  console.log('[logger]', ...rest.map((r) => `<${r}>`))
}

export const hello = () => {
  // This just returns a simple sentence, but it could do more.
  console.log('i just say hello..')
}
```

在您构建并捆绑解析器文件时，您的解析器代码将包含内联源映射。当您的解析器运行时， CloudWatch 日志中会显示以下条目：

![\[CloudWatch log entries showing resolver code execution with inline source map information.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cloudwatch-sourcemap.jpeg)


查看 CloudWatch 日志中的条目，您会注意到这两个文件的功能已捆绑在一起并行运行。每个文件的原始文件名也清晰地反映在日志中。