Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,110 changes: 1,110 additions & 0 deletions PATCH-EN.md

Large diffs are not rendered by default.

138 changes: 129 additions & 9 deletions src/Nextjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Distribution } from 'aws-cdk-lib/aws-cloudfront';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';

import {
OptionalNextjsDistributionProps,
OptionalNextjsDomainProps,
Expand All @@ -17,6 +18,7 @@ import { NextjsDistribution } from './NextjsDistribution';
import { NextjsDomain, NextjsDomainProps } from './NextjsDomain';
import { NextjsImage } from './NextjsImage';
import { NextjsInvalidation } from './NextjsInvalidation';
import { NextjsMultiServer } from './NextjsMultiServer';
import { NextjsOverrides } from './NextjsOverrides';
import { NextjsRevalidation } from './NextjsRevalidation';
import { NextjsServer } from './NextjsServer';
Expand Down Expand Up @@ -105,6 +107,28 @@ export interface NextjsProps {
* instead of waiting for the entire response to be generated.
*/
readonly streaming?: boolean;
/**
* Enable multi-server mode based on open-next.output.json.
* This will create separate Lambda functions for different API routes
* based on the configuration in open-next.output.json.
* @default false
*/
readonly enableMultiServer?: boolean;
/**
* Enable dynamic behaviors from open-next.output.json.
* This will automatically create CloudFront behaviors based on the
* patterns defined in open-next.output.json.
* Only works when enableMultiServer is true.
* @default false
*/
readonly enableDynamicBehaviors?: boolean;
/**
* Only create Lambda functions that are actually used in CloudFront behaviors.
* This can significantly reduce costs by avoiding unused functions.
* Only works when enableMultiServer is true.
* @default false
*/
readonly createOnlyUsedFunctions?: boolean;
}

/**
Expand All @@ -126,6 +150,10 @@ export class Nextjs extends Construct {
* The main NextJS server handler lambda function.
*/
public serverFunction: NextjsServer;
/**
* Multi-server instance for managing multiple Lambda functions (when enabled).
*/
public multiServer?: NextjsMultiServer;
/**
* The image optimization handler lambda function.
*/
Expand Down Expand Up @@ -178,13 +206,102 @@ export class Nextjs extends Construct {
...props.overrides?.nextjs?.nextjsStaticAssetsProps,
});

this.serverFunction = new NextjsServer(this, 'Server', {
environment: props.environment,
nextBuild: this.nextBuild,
staticAssetBucket: this.staticAssets.bucket,
overrides: props.overrides?.nextjsServer,
...props.overrides?.nextjs?.nextjsServerProps,
});
// Create server function(s) - either single or multi-server mode
if (props.enableMultiServer) {
this.multiServer = new NextjsMultiServer(this, 'MultiServer', {
environment: props.environment,
nextBuild: this.nextBuild,
staticAssetBucket: this.staticAssets.bucket,
enableMultiServer: true,
createOnlyUsedFunctions: props.createOnlyUsedFunctions,
excludePatterns: [
'*.DS_Store',
'*.log',
'*.tmp',
'*.test.js',
'*.spec.js',
'*.git*',
'node_modules/.cache/*',
'.env*',
'coverage/*',
'jest.config.js',
'*.md',
'LICENSE*',
'README*',
'.eslint*',
'.prettier*',
'tsconfig.json',
'*.map',
'*.d.ts.map',
'*.js.map',
'*.css.map',
'.next/cache/*',
'.next/trace',
'*.pid',
'*.backup',
'*.bak',
'*.old',
'log-events-viewer-result*.csv',
'.coverage/*',
'webpack-stats.json',
'bundle-analyzer/*',
'*.psd',
'*.sketch',
'.storybook/*',
'docs/*',
// Additional patterns for size optimization
'node_modules/@types/*',
'node_modules/typescript/*',
'node_modules/eslint/*',
'node_modules/prettier/*',
'node_modules/@typescript-eslint/*',
'node_modules/@babel/*',
'node_modules/babel-*/*',
'node_modules/webpack/*',
'node_modules/rollup/*',
'node_modules/vite/*',
'node_modules/jest/*',
'node_modules/@jest/*',
'node_modules/vitest/*',
'node_modules/puppeteer/*',
'node_modules/playwright/*',
'node_modules/chrome-aws-lambda/*',
'node_modules/chromium/*',
'node_modules/canvas/*',
'node_modules/sharp/*',
'*.test.ts',
'*.test.tsx',
'*.spec.ts',
'*.spec.tsx',
'__tests__/*',
'__mocks__/*',
'test/*',
'tests/*',
'.git/*',
'.vscode/*',
'.idea/*',
'*.tsbuildinfo',
'*.swp',
'*.swo',
'*~',
],
overrides: props.overrides?.nextjsServer,
quiet: props.quiet,
...props.overrides?.nextjs?.nextjsServerProps,
});
// For backwards compatibility, expose the main function as serverFunction
// Multi-server mode now uses enhanced behavior processing for better performance
this.serverFunction = this.multiServer.lambdaFunction as any;
} else {
this.serverFunction = new NextjsServer(this, 'Server', {
environment: props.environment,
nextBuild: this.nextBuild,
staticAssetBucket: this.staticAssets.bucket,
overrides: props.overrides?.nextjsServer,
...props.overrides?.nextjs?.nextjsServerProps,
});
}

// build image optimization
this.imageOptimizationFunction = new NextjsImage(this, 'Image', {
bucket: props.imageOptimizationBucket || this.bucket,
Expand All @@ -196,7 +313,8 @@ export class Nextjs extends Construct {
// build revalidation queue and handler function
this.revalidation = new NextjsRevalidation(this, 'Revalidation', {
nextBuild: this.nextBuild,
serverFunction: this.serverFunction,
serverFunction: this.multiServer ? undefined : this.serverFunction,
multiServer: this.multiServer,
overrides: props.overrides?.nextjsRevalidation,
...props.overrides?.nextjs?.nextjsRevalidationProps,
});
Expand All @@ -216,7 +334,9 @@ export class Nextjs extends Construct {
staticAssetsBucket: this.staticAssets.bucket,
nextBuild: this.nextBuild,
nextDomain: this.domain,
serverFunction: this.serverFunction.lambdaFunction,
serverFunction: this.multiServer ? undefined : this.serverFunction.lambdaFunction,
multiServer: this.multiServer,
enableDynamicBehaviors: props.enableDynamicBehaviors,
imageOptFunction: this.imageOptimizationFunction,
overrides: props.overrides?.nextjsDistribution,
...props.overrides?.nextjs?.nextjsDistributionProps,
Expand Down
11 changes: 8 additions & 3 deletions src/NextjsBucketDeployment.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as path from 'node:path';
import { CustomResource, Duration, Token } from 'aws-cdk-lib';
import { Code, Function } from 'aws-cdk-lib/aws-lambda';
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { IBucket } from 'aws-cdk-lib/aws-s3';
import { Asset } from 'aws-cdk-lib/aws-s3-assets';
import { Construct } from 'constructs';
import * as path from 'node:path';

import { OptionalCustomResourceProps, OptionalFunctionProps } from './generated-structs';
import { getCommonFunctionProps } from './utils/common-lambda-props';

Expand Down Expand Up @@ -129,8 +130,12 @@ export class NextjsBucketDeployment extends Construct {
}

private createFunction() {
const commonProps = getCommonFunctionProps(this, 'nextjs-bucket-deployment');
const { runtime, ...otherProps } = commonProps;

const fn = new Function(this, 'Fn', {
...getCommonFunctionProps(this),
...otherProps,
runtime: runtime || Runtime.NODEJS_20_X, // Provide default runtime
code: Code.fromAsset(path.resolve(__dirname, '..', 'assets', 'lambdas', 'nextjs-bucket-deployment')),
handler: 'index.handler',
timeout: Duration.minutes(5),
Expand Down
Loading