diff --git a/README.md b/README.md index c7fa36137..718934b66 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ serverless deploy | [AWS API Gateway Custom Authorizer Function with Auth0 example in NodeJS](https://github.com/serverless/examples/tree/v4/aws-node-auth0-custom-authorizers-api)
This is an example of how to protect API endpoints with Auth0, JSON Web Tokens (jwt) and a custom authorizer lambda function. | nodeJS | | [Dynamic Image Resizing API](https://github.com/serverless/examples/tree/v4/aws-node-dynamic-image-resizer)
This example shows you how to setup a dynamic image resizer API | nodeJS | | [DynamoDB Streams Processing to S3](https://github.com/serverless/examples/tree/v4/aws-node-dynamodb-stream-processing)
This example shows you how to consume a DynamoDB Stream, transform records, and archive them to S3. | nodeJS | +| [AWS Node.js ES Module Bundles with esbuild](https://github.com/serverless/examples/tree/v4/aws-node-esm-esbuild)
This example demonstrates how to bundle TypeScript handlers as ES modules (.mjs) with the built-in esbuild support, without adding a package.json to the deployment artifact. | nodeJS | | [AWS Storing Encrypted Secrets example in NodeJS](https://github.com/serverless/examples/tree/v4/aws-node-env-variables-encrypted-in-a-file)
This example demonstrates how to store secrets like API keys encrypted in your repository while providing them as environment variables to your AWS Lambda functions. | nodeJS | | [AWS Serverless Environment Variables Usage example in NodeJS](https://github.com/serverless/examples/tree/v4/aws-node-env-variables)
This example demonstrates how to use environment variables for AWS Lambdas. | nodeJS | | [Node Express API on AWS](https://github.com/serverless/examples/tree/v4/aws-node-express-api)
This template demonstrates how to develop and deploy a simple Node Express API running on AWS Lambda using the Serverless Framework. | nodeJS | diff --git a/aws-node-esm-esbuild/README.md b/aws-node-esm-esbuild/README.md new file mode 100644 index 000000000..6b8915300 --- /dev/null +++ b/aws-node-esm-esbuild/README.md @@ -0,0 +1,70 @@ + + +# AWS Node.js ES Module Bundles with esbuild + +This example demonstrates how to bundle a TypeScript handler as an ES module using the Serverless Framework's built-in esbuild support. The `outExtension` option emits the bundle as `.mjs`, which makes the Lambda Node.js runtime load it with the ESM loader — no `package.json` with `"type": "module"` needs to be shipped inside the deployment artifact. + +```yaml +build: + esbuild: + format: esm + outExtension: + '.js': '.mjs' +``` + +The handler proves it runs as an ES module by reading `import.meta.url`, which is only available in ESM. Function `handler` values stay unchanged — Lambda resolves the handler file extension automatically. + +This is useful when: + +- You want ES module semantics on Lambda (for example top-level `await` for initialization) with a CommonJS or extension-less project setup, such as a monorepo where the root `package.json` cannot declare `"type": "module"`. +- You want the deployment artifact to contain nothing but the bundled handler files. + +Both `format` and `outExtension` can also be returned from a `configFile` JavaScript configuration — see the [building documentation](https://www.serverless.com/framework/docs/providers/aws/guide/building) for all esbuild options. + +## Usage + +### Deploy + +```bash +serverless deploy +``` + +### Invoke + +After deployment, call the HTTP endpoint printed in the deploy output: + +```bash +curl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/time +``` + +Which should respond with: + +```json +{ + "message": "Hello from a handler loaded as an ES module!", + "time": "2026-07-24T12:00:00.000Z" +} +``` + +You can also invoke the function directly, locally or remotely: + +```bash +serverless invoke local -f time +serverless invoke -f time +``` + +### Clean up + +```bash +serverless remove +``` diff --git a/aws-node-esm-esbuild/serverless.yml b/aws-node-esm-esbuild/serverless.yml new file mode 100644 index 000000000..4e720c960 --- /dev/null +++ b/aws-node-esm-esbuild/serverless.yml @@ -0,0 +1,24 @@ +service: aws-node-esm-esbuild +frameworkVersion: '4' + +provider: + name: aws + runtime: nodejs24.x + architecture: arm64 + +build: + esbuild: + # Emit the bundled handlers as ES modules. The .mjs extension makes the + # Lambda Node.js runtime load them with the ESM loader, without shipping a + # package.json with "type": "module" inside the deployment artifact. + format: esm + outExtension: + '.js': '.mjs' + +functions: + time: + handler: src/handler.currentTime + events: + - httpApi: + path: /time + method: get diff --git a/aws-node-esm-esbuild/src/handler.ts b/aws-node-esm-esbuild/src/handler.ts new file mode 100644 index 000000000..83efa71fe --- /dev/null +++ b/aws-node-esm-esbuild/src/handler.ts @@ -0,0 +1,12 @@ +// Bundled by esbuild to .serverless/build/src/handler.mjs and loaded by the +// Lambda runtime as an ES module — import.meta is only available in ESM. +const loadedAs = import.meta.url.endsWith('.mjs') ? 'ES module' : 'CommonJS' + +export const currentTime = async () => ({ + statusCode: 200, + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + message: `Hello from a handler loaded as an ${loadedAs}!`, + time: new Date().toISOString(), + }), +}) diff --git a/aws-node-http-api-typescript/README.md b/aws-node-http-api-typescript/README.md index 3f92bae88..c05204e39 100644 --- a/aws-node-http-api-typescript/README.md +++ b/aws-node-http-api-typescript/README.md @@ -6,7 +6,7 @@ framework: v4 platform: AWS language: nodeJS authorLink: 'https://github.com/serverless' -authorName: 'Serverless, inc.' +authorName: 'Serverless, Inc.' authorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4' --> diff --git a/aws-node-rest-api-typescript-simple/README.md b/aws-node-rest-api-typescript-simple/README.md index 551dd4037..93c674604 100644 --- a/aws-node-rest-api-typescript-simple/README.md +++ b/aws-node-rest-api-typescript-simple/README.md @@ -7,7 +7,7 @@ platform: AWS language: nodeJS priority: 10 authorLink: 'https://github.com/serverless' -authorName: 'Serverless, inc.' +authorName: 'Serverless, Inc.' authorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4' --> diff --git a/aws-python-rest-api/README.md b/aws-python-rest-api/README.md index 8daef75b8..e396ce736 100644 --- a/aws-python-rest-api/README.md +++ b/aws-python-rest-api/README.md @@ -7,7 +7,7 @@ platform: AWS language: python priority: 2 authorLink: 'https://github.com/serverless' -authorName: 'Serverless, inc.' +authorName: 'Serverless, Inc.' authorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4' --> diff --git a/aws-python-sqs-worker/README.md b/aws-python-sqs-worker/README.md index 4956242ed..b3fa17188 100644 --- a/aws-python-sqs-worker/README.md +++ b/aws-python-sqs-worker/README.md @@ -7,7 +7,7 @@ platform: AWS language: Python priority: 2 authorLink: 'https://github.com/serverless' -authorName: 'Serverless, inc.' +authorName: 'Serverless, Inc.' authorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4' --> diff --git a/aws-ruby-sinatra-dynamodb-api/README.md b/aws-ruby-sinatra-dynamodb-api/README.md index b3b09ca47..b48a8aaf7 100644 --- a/aws-ruby-sinatra-dynamodb-api/README.md +++ b/aws-ruby-sinatra-dynamodb-api/README.md @@ -7,7 +7,7 @@ platform: AWS language: Ruby priority: 5 authorLink: 'https://github.com/serverless' -authorName: 'Serverless, inc.' +authorName: 'Serverless, Inc.' authorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4' --> diff --git a/examples.json b/examples.json index 2e9bb402a..9de5ead26 100644 --- a/examples.json +++ b/examples.json @@ -179,6 +179,18 @@ "authorName": "Kai Hendry", "authorAvatar": "https://avatars3.githubusercontent.com/u/765871?v=4&s=140" }, + { + "title": "AWS Node.js ES Module Bundles with esbuild", + "name": "aws-node-esm-esbuild", + "description": "This example demonstrates how to bundle TypeScript handlers as ES modules (.mjs) with the built-in esbuild support, without adding a package.json to the deployment artifact.", + "githubUrl": "https://github.com/serverless/examples/tree/v4/aws-node-esm-esbuild", + "framework": "v4", + "language": "nodeJS", + "platform": "aws", + "authorLink": "https://github.com/serverless", + "authorName": "Serverless, Inc.", + "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" + }, { "title": "AWS Storing Encrypted Secrets example in NodeJS", "name": "aws-node-env-variables-encrypted-in-a-file", @@ -212,7 +224,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 2 }, @@ -225,7 +237,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 3 }, @@ -358,7 +370,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -406,7 +418,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -418,7 +430,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 1 }, @@ -467,7 +479,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -636,7 +648,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -780,7 +792,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 5 }, @@ -817,7 +829,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 7 }, @@ -830,7 +842,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 8 }, @@ -903,7 +915,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -915,7 +927,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 6 }, @@ -977,7 +989,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1001,7 +1013,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4", "priority": 10 }, @@ -1038,7 +1050,7 @@ "language": "ruby", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1122,7 +1134,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1134,7 +1146,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1146,7 +1158,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1158,7 +1170,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1170,7 +1182,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1182,7 +1194,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1194,7 +1206,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1206,7 +1218,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1218,7 +1230,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1230,7 +1242,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1242,7 +1254,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1254,7 +1266,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1266,7 +1278,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1278,7 +1290,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1290,7 +1302,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1302,7 +1314,7 @@ "language": "node", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1314,7 +1326,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1326,7 +1338,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1338,7 +1350,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1350,7 +1362,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1362,7 +1374,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1374,7 +1386,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1386,7 +1398,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1398,7 +1410,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1410,7 +1422,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, { @@ -1422,7 +1434,7 @@ "language": "python", "platform": "aws", "authorLink": "https://github.com/serverless", - "authorName": "Serverless, inc.", + "authorName": "Serverless, Inc.", "authorAvatar": "https://avatars1.githubusercontent.com/u/13742415?s=200&v=4" }, {