Agrupación, TypeScript y mapas de origen para el tiempo de ejecución de APPSYNC_JS - AWS AppSync

Agrupación, TypeScript y mapas de origen para el tiempo de ejecución de APPSYNC_JS

TypeScript mejora el desarrollo de AWS AppSync al proporcionar seguridad de tipos y detección temprana de errores. Puede escribir código de TypeScript de forma local y transpilarlo a JavaScript antes de usarlo con el tiempo de ejecución de APPSYNC_JS. El proceso comienza con la instalación de TypeScript y la configuración de tsconfig.json para el entorno de APPSYNC_JS. A continuación, puede usar herramientas de agrupación como esbuild para compilar y agrupar el código. La CLI de Amplify generará tipos a partir del esquema de GraphQL, lo que permite usar dichos tipos en el código del solucionador.

Puede usar bibliotecas personalizadas y externas en el código de solucionador y función, siempre que cumplan los requisitos de APPSYNC_JS. Las herramientas de agrupación combinan el código en un único archivo para usarlo en AWS AppSync. Los mapas de origen se pueden incluir para facilitar la depuración.

Uso de bibliotecas y agrupación del código

En su código de solucionador y función, puede utilizar bibliotecas personalizadas y externas siempre que cumplan los requisitos de APPSYNC_JS. Esto permite reutilizar el código existente en su aplicación. Para utilizar bibliotecas definidas por varios archivos, debe usar una herramienta de agrupación, como esbuild, para combinar el código en un solo archivo que, a continuación, se puede guardar en su solucionador o función de AWS AppSync.

Al agrupar el código, tenga en cuenta lo siguiente:

  • APPSYNC_JS solo admite módulos ECMAScript (ESM).

  • Los módulos @aws-appsync/* están integrados en APPSYNC_JS y no deben agruparse con su código.

  • El entorno de versión ejecutable APPSYNC_JS es similar a NodeJS en que el código no se ejecuta en un entorno del navegador.

  • Puede incluir un mapa de origen opcional. Sin embargo, no incluya el contenido de origen.

    Para obtener más información sobre los mapas de origen, consulte Uso de mapas de origen.

Por ejemplo, para agrupar el código de solucionador ubicado en src/appsync/getPost.resolver.js, puede usar el siguiente comando de la CLI esbuild:

$ 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

Creación del código y trabajo con TypeScript

TypeScript es un lenguaje de programación desarrollado por Microsoft que ofrece todas las características de JavaScript junto con el sistema de escritura de TypeScript. Puede usar TypeScript para escribir código con seguridad de tipos y detectar errores en el momento de la compilación antes de guardar el código en AWS AppSync. El paquete @aws-appsync/utils está completamente escrito.

La versión ejecutable APPSYNC_JS no admite TypeScript directamente. Primero debe transpilar el código de TypeScript a código JavaScript que la versión ejecutable APPSYNC_JS admita antes de guardar el código en AWS AppSync. Puede usar TypeScript para escribir el código en su entorno de desarrollo integrado (IDE) local, pero tenga en cuenta que no puede crear código de TypeScript en la consola AWS AppSync.

Para empezar, asegúrese de tener TypeScript instalado en su proyecto. A continuación, establezca la configuración de transcompilación de TypeScript para trabajar con la versión ejecutable APPSYNC_JS mediante TSConfig. Este es un ejemplo de un archivo tsconfig.json básico que puede usar:

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

A continuación, puede usar una herramienta de agrupación como esbuild para compilar y agrupar el código. Por ejemplo, en el caso de un proyecto con su código AWS AppSync ubicado en src/appsync, puede usar el siguiente comando para compilar y agrupar el código:

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

Uso de CodeGen de Amplify

Puede usar la CLI de Amplify a fin de generar los tipos para su esquema. En el directorio donde se encuentra su archivo schema.graphql, ejecute el siguiente comando y revise las instrucciones para configurar el CodeGen:

$ npx @aws-amplify/cli codegen add

Para regenerar el CodeGen en determinadas circunstancias (por ejemplo, cuando se actualiza el esquema), ejecute el siguiente comando:

$ npx @aws-amplify/cli codegen

A continuación, puede usar los tipos generados en el código de solucionador. Por ejemplo, en el caso del esquema siguiente:

type Todo { id: ID! title: String! description: String } type Mutation { createTodo(title: String!, description: String): Todo } type Query { listTodos: Todo }

Podría utilizar los tipos generados en la siguiente función de AWS AppSync de ejemplo:

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 }

Uso de genéricos en TypeScript

Puede usar genéricos con varios de los tipos proporcionados. Por ejemplo, el siguiente fragmento de código es un tipo Todo:

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

Puede escribir un solucionador para una suscripción que haga uso de Todo. En su IDE, las definiciones de tipo y las sugerencias de autocompletar servirán como guía para utilizar correctamente la utilidad de transformación 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 }

Análisis de sus paquetes

Puede analizar sus paquetes automáticamente mediante la importación del complemento esbuild-plugin-eslint. Después, puede habilitarlo proporcionando un valor plugins que habilite las capacidades de eslint. A continuación se muestra un fragmento de código que usa la API de JavaScript esbuild en un archivo llamado 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 })], })

Uso de mapas de origen

Puede proporcionar un mapa de origen en línea (sourcemap) con su código JavaScript. Los mapas de origen son útiles al agrupar código JavaScript o de TypeScript y cuando desea ver referencias a los archivos de origen de entrada en los registros y mensajes de error de JavaScript de la versión ejecutable.

Su sourcemap debe aparecer al final del código. Se define mediante una única línea de comentario que sigue el siguiente formato:

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

A continuación se muestra un ejemplo:

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

Los mapas de origen se pueden crear con esbuild. En el siguiente ejemplo se muestra cómo usar la API de JavaScript esbuild para incluir un mapa de origen en línea cuando al compilarse y agruparse el código:

/* 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 })], })

En concreto, las opciones sourcemap y sourcesContent especifican que se debe añadir un mapa de origen en línea al final de cada compilación, pero no debe incluir el contenido de origen. Por convención, se recomienda no incluir el contenido de origen en el sourcemap. Establezca sources-content en false para deshabilitarlo en esbuild.

Para ilustrar el funcionamiento de los mapas de origen, revise el siguiente ejemplo, en el que un código de solucionador hace referencia a funciones auxiliares de una biblioteca auxiliar. El código contiene instrucciones de registro en el código de solucionador y en la biblioteca auxiliar:

./src/default.resolver.ts (su solucionador)

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 (un archivo auxiliar)

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..') }

Al compilar y agrupar el archivo de resolución, el código de solucionador incluirá un mapa de origen en línea. Al ejecutarse el solucionador, aparecen las siguientes entradas en los registros de CloudWatch:

CloudWatch log entries showing resolver code execution with inline source map information.

Si observa las entradas en el registro de CloudWatch, verá que se han agrupado las funcionalidades de los dos archivos y se ejecutan simultáneamente. El nombre original de cada archivo también aparece claramente reflejado en los registros.