From d7d25565578b7db0284d9348dd3383847b3eaa4c Mon Sep 17 00:00:00 2001 From: Jaden VanEckhout Date: Wed, 31 Jul 2024 14:15:51 -0500 Subject: [PATCH] feat: add support for lambda streaming (#225) --- API.md | 61 +++++++++++++++++++ src/Nextjs.ts | 7 +++ src/NextjsBuild.ts | 7 ++- src/NextjsDistribution.ts | 11 +++- .../OptionalNextjsBuildProps.ts | 4 ++ .../OptionalNextjsDistributionProps.ts | 4 ++ 6 files changed, 91 insertions(+), 3 deletions(-) diff --git a/API.md b/API.md index 499a20fb..55102e50 100644 --- a/API.md +++ b/API.md @@ -2797,6 +2797,7 @@ const nextjsBuildProps: NextjsBuildProps = { ... } | environment | {[ key: string ]: string} | *No description.* | | quiet | boolean | *No description.* | | skipBuild | boolean | *No description.* | +| streaming | boolean | *No description.* | --- @@ -2872,6 +2873,18 @@ public readonly skipBuild: boolean; --- +##### `streaming`Optional + +```typescript +public readonly streaming: boolean; +``` + +- *Type:* boolean + +> [{@link NextjsProps.streaming }]({@link NextjsProps.streaming }) + +--- + ### NextjsConstructOverrides #### Initializer @@ -3172,6 +3185,7 @@ const nextjsDistributionProps: NextjsDistributionProps = { ... } | functionUrlAuthType | aws-cdk-lib.aws_lambda.FunctionUrlAuthType | Override lambda function url auth type. | | nextDomain | NextjsDomain | *No description.* | | overrides | NextjsDistributionOverrides | Override props for every construct. | +| streaming | boolean | *No description.* | --- @@ -3302,6 +3316,18 @@ Override props for every construct. --- +##### `streaming`Optional + +```typescript +public readonly streaming: boolean; +``` + +- *Type:* boolean + +> [{@link NextjsProps.streaming }]({@link NextjsProps.streaming }) + +--- + ### NextjsDomainOverrides #### Initializer @@ -3833,6 +3859,7 @@ const nextjsProps: NextjsProps = { ... } | quiet | boolean | Less build output. | | skipBuild | boolean | Skips running Next.js build. Useful if you want to deploy `Nextjs` but haven't made any changes to Next.js app code. | | skipFullInvalidation | boolean | By default all CloudFront cache will be invalidated on deployment. | +| streaming | boolean | Streaming allows you to send data to the client as it's generated instead of waiting for the entire response to be generated. | --- @@ -4009,6 +4036,18 @@ could be important for some users. --- +##### `streaming`Optional + +```typescript +public readonly streaming: boolean; +``` + +- *Type:* boolean + +Streaming allows you to send data to the client as it's generated instead of waiting for the entire response to be generated. + +--- + ### NextjsRevalidationOverrides #### Initializer @@ -7610,6 +7649,7 @@ const optionalNextjsBuildProps: OptionalNextjsBuildProps = { ... } | nextjsPath | string | *No description.* | | quiet | boolean | *No description.* | | skipBuild | boolean | *No description.* | +| streaming | boolean | *No description.* | --- @@ -7673,6 +7713,16 @@ public readonly skipBuild: boolean; --- +##### `streaming`Optional + +```typescript +public readonly streaming: boolean; +``` + +- *Type:* boolean + +--- + ### OptionalNextjsDistributionProps OptionalNextjsDistributionProps. @@ -7699,6 +7749,7 @@ const optionalNextjsDistributionProps: OptionalNextjsDistributionProps = { ... } | overrides | NextjsDistributionOverrides | Override props for every construct. | | serverFunction | aws-cdk-lib.aws_lambda.IFunction | Lambda function to route all non-static requests to. | | staticAssetsBucket | aws-cdk-lib.aws_s3.IBucket | Bucket containing static assets. | +| streaming | boolean | *No description.* | --- @@ -7819,6 +7870,16 @@ Must be provided if you want to serve static files. --- +##### `streaming`Optional + +```typescript +public readonly streaming: boolean; +``` + +- *Type:* boolean + +--- + ### OptionalNextjsDomainProps OptionalNextjsDomainProps. diff --git a/src/Nextjs.ts b/src/Nextjs.ts index 8f3ecd47..e818c32e 100644 --- a/src/Nextjs.ts +++ b/src/Nextjs.ts @@ -100,6 +100,11 @@ export interface NextjsProps { * could be important for some users. */ readonly skipFullInvalidation?: boolean; + /** + * Streaming allows you to send data to the client as it's generated + * instead of waiting for the entire response to be generated. + */ + readonly streaming?: boolean; } /** @@ -160,6 +165,7 @@ export class Nextjs extends Construct { environment: props.environment, quiet: props.quiet, skipBuild: props.skipBuild, + streaming: props.streaming, ...props.overrides?.nextjs?.nextjsBuildProps, }); @@ -205,6 +211,7 @@ export class Nextjs extends Construct { nextjsPath: props.nextjsPath, basePath: props.basePath, distribution: props.distribution, + streaming: props.streaming, staticAssetsBucket: this.staticAssets.bucket, nextBuild: this.nextBuild, nextDomain: this.domain, diff --git a/src/NextjsBuild.ts b/src/NextjsBuild.ts index 10e7cbf3..7f56ffaa 100644 --- a/src/NextjsBuild.ts +++ b/src/NextjsBuild.ts @@ -41,6 +41,10 @@ export interface NextjsBuildProps { * @see {@link NextjsProps.skipBuild} */ readonly skipBuild?: NextjsProps['skipBuild']; + /** + * @see {@link NextjsProps.streaming} + */ + readonly streaming?: NextjsProps['streaming']; } /** @@ -142,7 +146,8 @@ export class NextjsBuild extends Construct { private build() { const buildPath = this.props.buildPath ?? this.props.nextjsPath; - const buildCommand = this.props.buildCommand ?? 'npx open-next@^2 build'; + const defaultBuildCommand = `npx open-next@^2 build ${this.props.streaming ? '--streaming' : ''}`; + const buildCommand = this.props.buildCommand ?? defaultBuildCommand; // run build if (!this.props.quiet) { console.debug(`Running "${buildCommand}" in`, buildPath); diff --git a/src/NextjsDistribution.ts b/src/NextjsDistribution.ts index 27489bd7..f1a811d4 100644 --- a/src/NextjsDistribution.ts +++ b/src/NextjsDistribution.ts @@ -13,7 +13,7 @@ import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; import { HttpOriginProps } from 'aws-cdk-lib/aws-cloudfront-origins'; import { PolicyStatement, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; import * as lambda from 'aws-cdk-lib/aws-lambda'; -import { Runtime } from 'aws-cdk-lib/aws-lambda'; +import { Runtime, InvokeMode } from 'aws-cdk-lib/aws-lambda'; import * as s3 from 'aws-cdk-lib/aws-s3'; import { Construct } from 'constructs'; import { NEXTJS_BUILD_DIR, NEXTJS_STATIC_DIR } from './constants'; @@ -89,6 +89,10 @@ export interface NextjsDistributionProps { * Must be provided if you want to serve static files. */ readonly staticAssetsBucket: s3.IBucket; + /** + * @see {@link NextjsProps.streaming} + */ + readonly streaming?: boolean; } /** @@ -256,7 +260,10 @@ export class NextjsDistribution extends Construct { } private createServerBehaviorOptions(): cloudfront.BehaviorOptions { - const fnUrl = this.props.serverFunction.addFunctionUrl({ authType: this.fnUrlAuthType }); + const fnUrl = this.props.serverFunction.addFunctionUrl({ + authType: this.fnUrlAuthType, + invokeMode: this.props.streaming ? InvokeMode.RESPONSE_STREAM : InvokeMode.BUFFERED, + }); const origin = new origins.HttpOrigin(Fn.parseDomainName(fnUrl.url), this.props.overrides?.serverHttpOriginProps); const serverBehaviorOptions = this.props.overrides?.serverBehaviorOptions; diff --git a/src/generated-structs/OptionalNextjsBuildProps.ts b/src/generated-structs/OptionalNextjsBuildProps.ts index 9f0f539f..6cc35b4c 100644 --- a/src/generated-structs/OptionalNextjsBuildProps.ts +++ b/src/generated-structs/OptionalNextjsBuildProps.ts @@ -4,6 +4,10 @@ * OptionalNextjsBuildProps */ export interface OptionalNextjsBuildProps { + /** + * @stability stable + */ + readonly streaming?: boolean; /** * @stability stable */ diff --git a/src/generated-structs/OptionalNextjsDistributionProps.ts b/src/generated-structs/OptionalNextjsDistributionProps.ts index b6dac9e1..b561dcab 100644 --- a/src/generated-structs/OptionalNextjsDistributionProps.ts +++ b/src/generated-structs/OptionalNextjsDistributionProps.ts @@ -6,6 +6,10 @@ import type { aws_cloudfront, aws_lambda, aws_s3 } from 'aws-cdk-lib'; * OptionalNextjsDistributionProps */ export interface OptionalNextjsDistributionProps { + /** + * @stability stable + */ + readonly streaming?: boolean; /** * Override props for every construct. * @stability stable