Skip to content

Commit

Permalink
feat(lambda-nodejs): add bun support
Browse files Browse the repository at this point in the history
  • Loading branch information
blimmer committed Oct 15, 2024
1 parent 7d6bf77 commit 8308ec9
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 9 deletions.
8 changes: 4 additions & 4 deletions packages/aws-cdk-lib/aws-lambda-nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ With the `@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion` disabled, the runt

## Lock file

The `NodejsFunction` requires a dependencies lock file (`yarn.lock`, `pnpm-lock.yaml` or
The `NodejsFunction` requires a dependencies lock file (`yarn.lock`, `pnpm-lock.yaml`, `bun.lockb` or
`package-lock.json`). When bundling in a Docker container, the path containing this lock file is
used as the source (`/asset-input`) for the volume mounted in the container.

Expand Down Expand Up @@ -203,8 +203,8 @@ new nodejs.NodejsFunction(this, 'my-handler', {

The modules listed in `nodeModules` must be present in the `package.json`'s dependencies or
installed. The same version will be used for installation. The lock file (`yarn.lock`,
`pnpm-lock.yaml` or `package-lock.json`) will be used along with the right installer (`yarn`,
`pnpm` or `npm`).
`pnpm-lock.yaml`, `bun.lockb` or `package-lock.json`) will be used along with the right installer (`yarn`,
`pnpm`, `bun` or `npm`).

When working with `nodeModules` using native dependencies, you might want to force bundling in a
Docker container even if `esbuild` is available in your environment. This can be done by setting
Expand Down Expand Up @@ -344,7 +344,7 @@ new nodejs.NodejsFunction(this, 'my-handler', {
```

This image should have `esbuild` installed **globally**. If you plan to use `nodeModules` it
should also have `npm`, `yarn` or `pnpm` depending on the lock file you're using.
should also have `npm`, `yarn`, `bun` or `pnpm` depending on the lock file you're using.

Use the [default image provided by `aws-cdk-lib/aws-lambda-nodejs`](https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-lambda-nodejs/lib/Dockerfile)
as a source of inspiration.
Expand Down
8 changes: 8 additions & 0 deletions packages/aws-cdk-lib/aws-lambda-nodejs/lib/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ RUN npm install --global [email protected]
# Install pnpm
RUN npm install --global [email protected]

# Install bun
RUN npm install --global [email protected]

# Install typescript
RUN npm install --global typescript

Expand Down Expand Up @@ -39,4 +42,9 @@ RUN npm config --global set update-notifier false
# create non root user and change allow execute command for non root user
RUN /sbin/useradd -u 1000 user && chmod 711 /

# Ensure all users can write to bun cache
RUN mkdir /tmp/bun-cache && \
chmod -R 777 /tmp/bun-cache && \
echo -e "[install.cache]\ndir = \"/tmp/bun-cache\"" >> /home/user/.bunfig.toml

CMD [ "esbuild" ]
9 changes: 5 additions & 4 deletions packages/aws-cdk-lib/aws-lambda-nodejs/lib/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ export interface NodejsFunctionProps extends lambda.FunctionOptions {
readonly awsSdkConnectionReuse?: boolean;

/**
* The path to the dependencies lock file (`yarn.lock`, `pnpm-lock.yaml` or `package-lock.json`).
* The path to the dependencies lock file (`yarn.lock`, `pnpm-lock.yaml`, `bun.lockb` or `package-lock.json`).
*
* This will be used as the source for the volume mounted in the Docker
* container.
*
* Modules specified in `nodeModules` will be installed using the right
* installer (`yarn`, `pnpm` or `npm`) along with this lock file.
* installer (`yarn`, `pnpm`, `bun` or `npm`) along with this lock file.
*
* @default - the path is found by walking up parent directories searching for
* a `yarn.lock`, `pnpm-lock.yaml` or `package-lock.json` file
* a `yarn.lock`, `pnpm-lock.yaml`, `bun.lockb` or `package-lock.json` file
*/
readonly depsLockFilePath?: string;

Expand Down Expand Up @@ -200,11 +200,12 @@ function findLockFile(depsLockFilePath?: string): string {
const lockFiles = findUpMultiple([
LockFile.PNPM,
LockFile.YARN,
LockFile.BUN,
LockFile.NPM,
]);

if (lockFiles.length === 0) {
throw new Error('Cannot find a package lock file (`pnpm-lock.yaml`, `yarn.lock` or `package-lock.json`). Please specify it with `depsLockFilePath`.');
throw new Error('Cannot find a package lock file (`pnpm-lock.yaml`, `yarn.lock`, `bun.lockb` or `package-lock.json`). Please specify it with `depsLockFilePath`.');
}
if (lockFiles.length > 1) {
throw new Error(`Multiple package lock files found: ${lockFiles.join(', ')}. Please specify the desired one with \`depsLockFilePath\`.`);
Expand Down
7 changes: 7 additions & 0 deletions packages/aws-cdk-lib/aws-lambda-nodejs/lib/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface PackageManagerProps {
export enum LockFile {
NPM = 'package-lock.json',
YARN = 'yarn.lock',
BUN = 'bun.lockb',
PNPM = 'pnpm-lock.yaml',
}

Expand Down Expand Up @@ -46,6 +47,12 @@ export class PackageManager {
runCommand: ['pnpm', 'exec'],
argsSeparator: '--',
});
case LockFile.BUN:
return new PackageManager({
lockFile: LockFile.BUN,
installCommand: logLevel && logLevel !== LogLevel.INFO ? ['bun', 'install', '--frozen-lockfile', '--silent'] : ['bun', 'install', '--frozen-lockfile'],
runCommand: ['bun', 'run'],
});
default:
return new PackageManager({
lockFile: LockFile.NPM,
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-cdk-lib/aws-lambda-nodejs/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export interface BundlingOptions extends DockerRunOptions {
* A custom bundling Docker image.
*
* This image should have esbuild installed globally. If you plan to use `nodeModules`
* it should also have `npm`, `yarn` or `pnpm` depending on the lock file you're using.
* it should also have `npm`, `yarn`, `bun` or `pnpm` depending on the lock file you're using.
*
* See https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-lambda-nodejs/lib/Dockerfile
* for the default image provided by aws-cdk-lib/aws-lambda-nodejs.
Expand Down
23 changes: 23 additions & 0 deletions packages/aws-cdk-lib/aws-lambda-nodejs/test/bundling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,29 @@ test('Detects pnpm-lock.yaml', () => {
});
});

test('Detects bun.lockb', () => {
const bunLock = path.join(__dirname, '..', 'bun.lockb');
Bundling.bundle(stack, {
entry: __filename,
projectRoot: path.dirname(bunLock),
depsLockFilePath: bunLock,
runtime: STANDARD_RUNTIME,
architecture: Architecture.X86_64,
nodeModules: ['delay'],
forceDockerBundling: true,
});

// Correctly bundles with esbuild
expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(bunLock), {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
command: expect.arrayContaining([
expect.stringMatching(/bun\.lockb.+bun install --frozen-lockfile/),
]),
}),
});
});

test('with Docker build args', () => {
Bundling.bundle(stack, {
entry,
Expand Down
13 changes: 13 additions & 0 deletions packages/aws-cdk-lib/aws-lambda-nodejs/test/docker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ test('can pnpm install with non root user', () => {
expect(proc.status).toEqual(0);
});

test('can bun install with non root user', () => {
const proc = spawnSync(docker, [
'run', '-u', '500:500',
'esbuild',
'bash', '-c', [
'mkdir /tmp/test',
'cd /tmp/test',
'bun add constructs',
].join(' && '),
]);
expect(proc.status).toEqual(0);
});

test('cache folders have the right permissions', () => {
const proc = spawnSync(docker, [
'run', 'esbuild',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ test('from a pnpm-lock.yaml with LogLevel.ERROR', () => {
expect(packageManager.installCommand).toEqual(['pnpm', 'install', '--reporter', 'silent', '--config.node-linker=hoisted', '--config.package-import-method=clone-or-copy', '--no-prefer-frozen-lockfile']);
});

test('from a bun.lockb', () => {
const packageManager = PackageManager.fromLockFile('/path/to/bun.lockb');
expect(packageManager.lockFile).toEqual(LockFile.BUN);
expect(packageManager.argsSeparator).toBeUndefined();
expect(packageManager.installCommand).toEqual(['bun', 'install', '--frozen-lockfile']);
expect(packageManager.runCommand).toEqual(['bun', 'run']);

expect(packageManager.runBinCommand('my-bin')).toBe('bun run my-bin');
});

test('from a bun.lockb with LogLevel.ERROR', () => {
const packageManager = PackageManager.fromLockFile('/path/to/bun.lockb', LogLevel.ERROR);
expect(packageManager.installCommand).toEqual(['bun', 'install', '--frozen-lockfile', '--silent']);
});

test('defaults to NPM', () => {
const packageManager = PackageManager.fromLockFile('/path/to/other.lock');
expect(packageManager.lockFile).toEqual(LockFile.NPM);
Expand Down

0 comments on commit 8308ec9

Please sign in to comment.