Add Cdk.NodejsFunction#2458
Open
zbrydon wants to merge 29 commits into
Open
Conversation
🦋 Changeset detectedLatest commit: 19cf4a8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
zbrydon
commented
Jun 15, 2026
| "noUnusedLocals": false, | ||
| "noUnusedParameters": false, | ||
| "resolveJsonModule": true, | ||
| "skipLibCheck": true, |
Contributor
Author
There was a problem hiding this comment.
This is a result of trying to work around the optional peer deps added in this PR.
I am not sure about which approach we want to go with 🤷 :
- make the deps non-optional (I've make rolldown a dep but the other two aren't feasible and could result in version conflicts 🤔 )
- lazy load and skip type checking (current PR)
- create a dedicated subpath export via skuba (Seeing what that would look like here See what a sub path import looks like #2474)
- just import from the skuba-api (Means we have to make all the consumers of this have another dep 🫠 )
zbrydon
commented
Jun 17, 2026
Contributor
Author
There was a problem hiding this comment.
Draft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The main driver is making the CDK
NodejsFunctionconstruct work with the strict pnpm settings we want to enforce, and those enforced by default in pnpm 11. The upstream construct doesn't play nicely with these, and thought we can use rolldown instead of esbuild while we're at it.Related upstream issues:
Overview
A
NodejsFunctionCDK construct under@skuba-lib/api/cdk, a drop-in alternative toaws-cdk-lib/aws-lambda-nodejs.NodejsFunction, built around rolldown and pnpm . At synth time it bundles a TS/JS entry into a single ESMindex.mjshandler, optionally installs a subset of realnode_modules, and packages the result as a Lambda asset.Flow:
Cdk.NodejsFunction→function.ts(validation) →bundling.ts(tryBundle) → spawns the rolldown bridge → optionalpnpm install→outputDirbecomes the asset.Bits worth noting
cdk/index.tsis a lazyrequire()getter, not a normal export.aws-cdk-libandconstructsare optional peers; the getter defers loading them so consumers who never use the construct don't need them installed. See discussion on potential optionsBundlingimplements CDK'sBundlingOptionsbut theimageis a dummy andtryBundlealways returnstrue. Synth therefore requiresnode,pnpm, and rolldown in the environment.bridges/rolldown.mts) resolved from the package root. This isolates the bundler's native bits and module resolution from the CDK app process. The bridge also enforces the single-handler contract: it rejectsinput,output.preserveModules,output.entryFileNames, multi-entryoutput, and non-ESMformatrather than overriding them.package-manager.tsthrows if a non-pnpm package manager is declared.nodeModulesinstall path has real subtlety: pins exact versions viafindPackageJSON, filterspatchedDependenciesdown to the requested modules, copies patch files with path-traversal/symlink guards, and cleans staged files in afinally.lib/cdk/bridges/rolldown.mjscouples source layout to build output@skuba-lib/apibecause it seems odd to have half esm only 🤷Tests