diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 25a27d85042f9..49381a8588523 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -32,6 +32,7 @@ This file is used as "entry" for [Parcel](https://parceljs.org/). This means tha automatically transpiled and bundled whether it's written in JavaScript or TypeScript. Alternatively, an entry file and handler can be specified: + ```ts new lambda.NodejsFunction(this, 'MyFunction', { entry: '/path/to/my/file.ts', // accepts .js, .jsx, .ts and .tsx files @@ -56,6 +57,7 @@ new lambda.NodejsFunction(this, 'my-handler', { ``` Use the `buildArgs` prop to pass build arguments when building the bundling image: + ```ts new lambda.NodejsFunction(this, 'my-handler', { buildArgs: { @@ -64,6 +66,20 @@ new lambda.NodejsFunction(this, 'my-handler', { }); ``` +Use the `bundlingDockerImage` prop to use a custom bundling image: + +```ts +new lambda.NodejsFunction(this, 'my-handler', { + bundlingDockerImage: dk.BundlingDockerImage.fromAsset('/path/to/Dockerfile'), +}); +``` + +This image should have Parcel installed at `/`. If you plan to use `nodeModules` it +should also have `npm` or `yarn` 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/parcel/Dockerfile) +as a source of inspiration. + ### Project root The `NodejsFunction` tries to automatically determine your project root, that is the root of your node project. This is usually where the top level `node_modules` diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts index 51e51ab584043..fd0d69d960b92 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts @@ -77,6 +77,7 @@ export class LocalBundler implements cdk.ILocalBundling { } interface DockerBundlerProps extends BundlerProps { + bundlingDockerImage?: cdk.BundlingDockerImage; buildImage?: boolean; buildArgs?: { [key: string]: string }; runtime: Runtime; @@ -91,7 +92,7 @@ export class DockerBundler { constructor(props: DockerBundlerProps) { const image = props.buildImage - ? cdk.BundlingDockerImage.fromAsset(path.join(__dirname, '../parcel'), { + ? props.bundlingDockerImage ?? cdk.BundlingDockerImage.fromAsset(path.join(__dirname, '../parcel'), { buildArgs: { ...props.buildArgs ?? {}, IMAGE: props.runtime.bundlingDockerImage.image, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index d6a0368ad450b..9c946d4879e37 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -89,6 +89,19 @@ export interface ParcelBaseOptions { * @default false */ readonly forceDockerBundling?: boolean; + + /** + * A custom bundling Docker image. + * + * This image should have Parcel installed at `/`. If you plan to use `nodeModules` + * it should also have `npm` or `yarn` depending on the lock file you're using. + * + * See https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-lambda-nodejs/parcel/Dockerfile + * for the default image provided by @aws-cdk/aws-lambda-nodejs. + * + * @default - use the Docker image provided by @aws-cdk/aws-lambda-nodejs + */ + readonly bundlingDockerImage?: cdk.BundlingDockerImage; } /** @@ -189,6 +202,7 @@ export class Bundling { relativeEntryPath, cacheDir: options.cacheDir, environment: options.parcelEnvironment, + bundlingDockerImage: options.bundlingDockerImage, buildImage: !LocalBundler.runsLocally || options.forceDockerBundling, buildArgs: options.buildArgs, parcelVersion: options.parcelVersion, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index 1ff71b6422ece..0caa440ec1b8a 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -13,16 +13,17 @@ const writeFileSyncMock = jest.spyOn(fs, 'writeFileSync').mockReturnValue(); const existsSyncOriginal = fs.existsSync; const existsSyncMock = jest.spyOn(fs, 'existsSync'); const originalFindUp = util.findUp; -const findUpMock = jest.spyOn(util, 'findUp').mockImplementation((name: string, directory) => { - if (name === 'package.json') { - return path.join(__dirname, '..'); - } - return originalFindUp(name, directory); -}); const fromAssetMock = jest.spyOn(BundlingDockerImage, 'fromAsset'); +let findUpMock: jest.SpyInstance; beforeEach(() => { jest.clearAllMocks(); + findUpMock = jest.spyOn(util, 'findUp').mockImplementation((name: string, directory) => { + if (name === 'package.json') { + return path.join(__dirname, '..'); + } + return originalFindUp(name, directory); + }); }); test('Parcel bundling', () => { @@ -317,3 +318,19 @@ test('Project root detection', () => { expect(findUpMock).toHaveBeenNthCalledWith(3, LockFile.NPM); expect(findUpMock).toHaveBeenNthCalledWith(4, 'package.json'); }); + +test('Custom bundling docker image', () => { + Bundling.parcel({ + entry: '/project/folder/entry.ts', + projectRoot: '/project', + runtime: Runtime.NODEJS_12_X, + bundlingDockerImage: BundlingDockerImage.fromRegistry('my-custom-image'), + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.BUNDLE, + bundling: expect.objectContaining({ + image: { image: 'my-custom-image' }, + }), + }); +});