From eee7f0049c5575654d6844e29e0d3b94dda7ce2b Mon Sep 17 00:00:00 2001 From: bboure Date: Thu, 29 Jun 2023 08:32:03 +0200 Subject: [PATCH] improvements --- doc/general-config.md | 19 +++++++++++++++ .../__snapshots__/base.test.ts.snap | 3 ++- src/__tests__/validation/base.test.ts | 6 +++++ src/resources/JsResolver.ts | 23 +++++++++++++++---- src/types/plugin.ts | 2 ++ src/validation.ts | 9 ++++++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/doc/general-config.md b/doc/general-config.md index 26e79905..3c9e2e9f 100644 --- a/doc/general-config.md +++ b/doc/general-config.md @@ -51,6 +51,7 @@ appSync: - `xrayEnabled`: Boolean. Enable or disable X-Ray tracing. - `visibility`: Optional. `GLOBAL` or `PRIVATE`. Defaults to `GLOBAL`. - `tags`: A key-value pair for tagging this AppSync API +- `esbuild`: Custom esbuild options, or `false` See [Esbuild](#Esbuild) ## Schema @@ -186,3 +187,21 @@ appSync: - `excludeVerboseContent`: Boolean, Optional. Exclude or not verbose content (headers, response headers, context, and evaluated mapping templates), regardless of field logging level. Defaults to `false`. - `retentionInDays`: Optional. Number of days to retain the logs. Defaults to [`provider.logRetentionInDays`](https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml#general-function-settings). - `roleArn`: Optional. The role ARN to use for AppSync to write into CloudWatch. If not specified, a new role is created by default. + +## Esbuild + +By default, this plugin will use esbuild in order to transpile and bundle Javascript resolvers. This option allows you to pass custom options that must be passed to esbuild. + +Use these options carefully. Some options are not compatible with AWS AppSync. For more details about using esbuild with AppSync, see the [official guidelines](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html#additional-utilities) + +Set this option to `false` to disable esbuild. + +Example: + +Override the target and disable sourcemap. + +```yml +esbuild: + target: 'es2020', + sourcemap: false +``` diff --git a/src/__tests__/validation/__snapshots__/base.test.ts.snap b/src/__tests__/validation/__snapshots__/base.test.ts.snap index c0639dc0..79de3130 100644 --- a/src/__tests__/validation/__snapshots__/base.test.ts.snap +++ b/src/__tests__/validation/__snapshots__/base.test.ts.snap @@ -56,5 +56,6 @@ exports[`Valdiation should validate 1`] = ` : must have required property 'authentication' /unknownPorp: invalid (unknown) property /xrayEnabled: must be boolean -/visibility: must be \\"GLOBAL\\" or \\"PRIVATE\\"" +/visibility: must be \\"GLOBAL\\" or \\"PRIVATE\\" +/esbuild: must be an esbuild config object or false" `; diff --git a/src/__tests__/validation/base.test.ts b/src/__tests__/validation/base.test.ts index bd9b7ee6..7571d455 100644 --- a/src/__tests__/validation/base.test.ts +++ b/src/__tests__/validation/base.test.ts @@ -12,6 +12,11 @@ describe('Valdiation', () => { tags: { foo: 'bar', }, + esbuild: { + target: 'es2020', + sourcemap: false, + treeShaking: false, + }, }), ).toBe(true); @@ -20,6 +25,7 @@ describe('Valdiation', () => { visibility: 'FOO', xrayEnabled: 'BAR', unknownPorp: 'foo', + esbuild: 'bad', }); }).toThrowErrorMatchingSnapshot(); }); diff --git a/src/resources/JsResolver.ts b/src/resources/JsResolver.ts index 6d7186c5..76bf7189 100644 --- a/src/resources/JsResolver.ts +++ b/src/resources/JsResolver.ts @@ -19,18 +19,33 @@ export class JsResolver { ); } + return this.processTemplateSubstitutions(this.getResolverContent()); + } + + getResolverContent(): string { + if (this.api.config.esbuild === false) { + return fs.readFileSync(this.config.path, 'utf8'); + } + // process with esbuild // this will: // - Bundle the code into one file if necessary // - Transpile typescript to javascript if necessary - const buildResult = buildSync({ + target: 'esnext', + sourcemap: 'inline', + treeShaking: true, + minifyWhitespace: true, + minifyIdentifiers: true, + // custom config overrides + ...this.api.config.esbuild, + // These options are required and can't be changed + platform: 'node', + format: 'esm', entryPoints: [this.config.path], bundle: true, write: false, external: ['@aws-appsync/utils'], - format: 'esm', - target: 'es2020', }); if (buildResult.errors.length > 0) { @@ -45,7 +60,7 @@ export class JsResolver { ); } - return this.processTemplateSubstitutions(buildResult.outputFiles[0].text); + return buildResult.outputFiles[0].text; } processTemplateSubstitutions(template: string): string | IntrinsicFunction { diff --git a/src/types/plugin.ts b/src/types/plugin.ts index ea56c8b5..bd96c72c 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -1,4 +1,5 @@ import { CfnWafRuleStatement, IntrinsicFunction } from './cloudFormation'; +import { BuildOptions } from 'esbuild'; export type AppSyncConfig = { name: string; @@ -17,6 +18,7 @@ export type AppSyncConfig = { waf?: WafConfig; tags?: Record; visibility?: 'GLOBAL' | 'PRIVATE'; + esbuild?: BuildOptions | false; }; export type IamStatement = { diff --git a/src/validation.ts b/src/validation.ts index a1870492..bc2887e2 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -838,6 +838,15 @@ export const appSyncSchema = { ], errorMessage: 'contains invalid pipeline function definitions', }, + esbuild: { + oneOf: [ + { + type: 'object', + }, + { const: false }, + ], + errorMessage: 'must be an esbuild config object or false', + }, }, required: ['name', 'authentication'], additionalProperties: {