Skip to content

Commit

Permalink
feat(lambda-nodejs): pnpm support
Browse files Browse the repository at this point in the history
Closes aws#14757
  • Loading branch information
jogold committed May 19, 2021
1 parent 5c84696 commit f1e644c
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 27 deletions.
14 changes: 7 additions & 7 deletions packages/@aws-cdk/aws-lambda-nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ when working with the AWS SDK for JavaScript. Set the `awsSdkConnectionReuse` pr

## Lock file

The `NodejsFunction` requires a dependencies lock file (`yarn.lock` 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.
The `NodejsFunction` requires a dependencies lock file (`yarn.lock`, `package-lock.json` or
`pnpm-lock.yml`). 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.

By default, the construct will try to automatically determine your project lock file.
Alternatively, you can specify the `depsLockFilePath` prop manually. In this
Expand Down Expand Up @@ -114,8 +113,9 @@ new lambda.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` or
`package-lock.json`) will be used along with the right installer (`yarn` or `npm`).
installed. The same version will be used for installation. The lock file (`yarn.lock`,
`pnpm-lock.yml` or `package-lock.json`) will be used along with the right installer (`yarn`,
`pnpm` 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 @@ -219,7 +219,7 @@ new lambda.NodejsFunction(this, 'my-handler', {
```

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

Use the [default image provided by `@aws-cdk/aws-lambda-nodejs`](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-lambda-nodejs/lib/Dockerfile)
as a source of inspiration.
5 changes: 4 additions & 1 deletion packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# The correct AWS SAM build image based on the runtime of the function will be
# passed as build arg. The default allows to do `docker build .` when testing.
ARG IMAGE=public.ecr.aws/sam/build-nodejs12.x
ARG IMAGE=public.ecr.aws/sam/build-nodejs14.x
FROM $IMAGE

# Install yarn
RUN npm install --global yarn@1.22.5

# Install pnpm
RUN npm install --global pnpm

# Install esbuild
# (unsafe-perm because esbuild has a postinstall script)
ARG ESBUILD_VERSION=0
Expand Down
46 changes: 28 additions & 18 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,28 +84,11 @@ export class NodejsFunction extends lambda.Function {
throw new Error('Only `NODEJS` runtimes are supported.');
}

// Find lock file
let depsLockFilePath: string;
if (props.depsLockFilePath) {
if (!fs.existsSync(props.depsLockFilePath)) {
throw new Error(`Lock file at ${props.depsLockFilePath} doesn't exist`);
}
if (!fs.statSync(props.depsLockFilePath).isFile()) {
throw new Error('`depsLockFilePath` should point to a file');
}
depsLockFilePath = path.resolve(props.depsLockFilePath);
} else {
const lockFile = findUp(PackageManager.YARN.lockFile) ?? findUp(PackageManager.NPM.lockFile);
if (!lockFile) {
throw new Error('Cannot find a package lock file (`yarn.lock` or `package-lock.json`). Please specify it with `depsFileLockPath`.');
}
depsLockFilePath = lockFile;
}

// Entry and defaults
const entry = path.resolve(findEntry(id, props.entry));
const handler = props.handler ?? 'handler';
const runtime = props.runtime ?? lambda.Runtime.NODEJS_14_X;
const depsLockFilePath = findLockFile(props.depsLockFilePath);

super(scope, id, {
...props,
Expand All @@ -126,6 +109,33 @@ export class NodejsFunction extends lambda.Function {
}
}

/**
* Checks given lock file or searches for a lock file
*/
function findLockFile(depsLockFilePath?: string): string {
if (depsLockFilePath) {
if (!fs.existsSync(depsLockFilePath)) {
throw new Error(`Lock file at ${depsLockFilePath} doesn't exist`);
}

if (!fs.statSync(depsLockFilePath).isFile()) {
throw new Error('`depsLockFilePath` should point to a file');
}

return path.resolve(depsLockFilePath);
}

const lockFile = findUp(PackageManager.PNPM.lockFile)
?? findUp(PackageManager.YARN.lockFile)
?? findUp(PackageManager.NPM.lockFile);

if (!lockFile) {
throw new Error('Cannot find a package lock file (`pnpm-lock.yaml`, `yarn.lock` or `package-lock.json`). Please specify it with `depsFileLockPath`.');
}

return lockFile;
}

/**
* Searches for an entry file. Preference order is the following:
* 1. Given entry file
Expand Down
8 changes: 8 additions & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export class PackageManager {
runCommand: ['yarn', 'run'],
});

public static PNPM = new PackageManager({
lockFile: 'pnpm-lock.yaml',
installCommand: ['pnpm', 'install'],
runCommand: ['pnpm', 'run'],
});

public static fromLockFile(lockFilePath: string): PackageManager {
const lockFile = path.basename(lockFilePath);

Expand All @@ -31,6 +37,8 @@ export class PackageManager {
return PackageManager.NPM;
case PackageManager.YARN.lockFile:
return PackageManager.YARN;
case PackageManager.PNPM.lockFile:
return PackageManager.PNPM;
default:
return PackageManager.NPM;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ test('from a yarn.lock', () => {
expect(packageManager.runBinCommand('my-bin')).toBe('yarn run my-bin');
});

test('defaults to NPM', () => {
test('from a pnpm-lock.yml', () => {
const packageManager = PackageManager.fromLockFile('/path/to/pnpm-lock.yaml');
expect(packageManager).toEqual(PackageManager.PNPM);

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

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

Expand Down

0 comments on commit f1e644c

Please sign in to comment.