Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lambda-nodejs): command hooks #11583

Merged
merged 7 commits into from
Nov 29, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
23 changes: 23 additions & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,26 @@ $ yarn add --dev esbuild@0
To force bundling in a Docker container, set the `forceDockerBundling` prop to `true`. This
is useful if your function relies on node modules that should be installed (`nodeModules` prop, see [above](#install-modules)) in a Lambda compatible environment. This is usually the
case with modules using native dependencies.

### Command hooks
It is possible to run additional commands by specifying the `commandHooks` prop:
eladb marked this conversation as resolved.
Show resolved Hide resolved

```ts
new lambda.NodejsFunction(this, 'my-handler-with-commands', {
commandHooks: {
// Copy a file so that it will be included in the bundled asset
afterBundling(inputDir: string, outputDir: string): string {
jogold marked this conversation as resolved.
Show resolved Hide resolved
return `cp ${inputDir}/important-file.node ${outputDir}`
}
}
});
```

The following hooks are available:
- `beforeBundling`: runs before all bundling commands
- `afterInstall`: runs before node modules installation
jogold marked this conversation as resolved.
Show resolved Hide resolved
- `afterBundling`: runs after all bundling commands

They all receive the directory containing the lock file (`inputDir`) and the
directory where the bundled asset will be output (`outputDir`). They must return
the command to run as a `string`.
8 changes: 7 additions & 1 deletion packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,13 @@ export class Bundling implements cdk.BundlingOptions {
]);
}

return chain([esbuildCommand, depsCommand]);
return chain([
this.props.commandHooks?.beforeBundling?.(inputDir, outputDir) ?? '',
esbuildCommand,
(this.props.nodeModules && this.props.commandHooks?.beforeInstall?.(inputDir, outputDir)) ?? '',
depsCommand,
this.props.commandHooks?.afterBundling?.(inputDir, outputDir) ?? '',
]);
}
}

Expand Down
29 changes: 29 additions & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,33 @@ export interface BundlingOptions {
* @default - use the Docker image provided by @aws-cdk/aws-lambda-nodejs
*/
readonly bundlingDockerImage?: BundlingDockerImage;

/**
* Command hooks
*
* @default - do not run additional commands
*/
readonly commandHooks?: ICommandHooks;
}

/**
* Command hooks
eladb marked this conversation as resolved.
Show resolved Hide resolved
*/
export interface ICommandHooks {
/**
* Returns a command to run before bundling
*/
beforeBundling?(inputDir: string, outputDir: string): string;

/**
* Returns a command to run before installing node modules.
*
* This hook only runs when node modules are installed
*/
beforeInstall?(inputDir: string, outputDir: string): string;

/**
* Returns a command to run after bundling
*/
afterBundling?(inputDir: string, outputDir: string): string;
}
27 changes: 27 additions & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,30 @@ test('Custom bundling docker image', () => {
}),
});
});

test('with command hooks', () => {
Bundling.bundle({
entry,
depsLockFilePath,
runtime: Runtime.NODEJS_12_X,
commandHooks: {
beforeBundling(inputDir: string, outputDir: string): string {
return `cp ${inputDir}/a.txt ${outputDir}`;
},
afterBundling(inputDir: string, outputDir: string): string {
return `cp ${inputDir}/b.txt ${outputDir}/txt`;
},
},
forceDockerBundling: true,
});

expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(depsLockFilePath), {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
command: [
'bash', '-c',
expect.stringMatching(/^cp \/asset-input\/a.txt \/asset-output && .+ && cp \/asset-input\/b.txt \/asset-output\/txt$/),
],
}),
});
});