diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 094b206eba5d4..48cfc6407e7a4 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -104,21 +104,21 @@ same version will be used for installation. If a lock file is detected (`package `yarn.lock`) it will be used along with the right installer (`npm` or `yarn`). ### Local bundling -If Parcel v2 is available it will be used to bundle your code in your environment. Otherwise, +If Parcel v2.0.0-beta.1 is available it will be used to bundle your code in your environment. Otherwise, bundling will happen in a [Lambda compatible Docker container](https://hub.docker.com/r/amazon/aws-sam-cli-build-image-nodejs12.x). For macOS the recommendend approach is to install Parcel as Docker volume performance is really poor. -Parcel v2 can be installed with: +Parcel v2.0.0-beta.1 can be installed with: ```bash -$ npm install --save-dev parcel@next +$ npm install --save-dev --save-exact parcel@2.0.0-beta.1 ``` OR ```bash -$ yarn add --dev @parcel@next +$ yarn add --dev --exact parcel@2.0.0-beta.1 ``` To force bundling in a Docker container, set the `forceDockerBundling` prop to `true`. This diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts index 60ea23305f527..51319927f70be 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundlers.ts @@ -5,6 +5,8 @@ import { Runtime } from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { exec } from './util'; +const PARCEL_VERSION = '2.0.0-beta.1'; + interface BundlerProps { relativeEntryPath: string; cacheDir?: string; @@ -31,14 +33,18 @@ export class LocalBundler implements cdk.ILocalBundling { } try { const parcel = spawnSync(require.resolve('parcel'), ['--version']); - LocalBundler._runsLocally = /^2/.test(parcel.stdout.toString().trim()); // Cache result to avoid unnecessary spawns + const version = parcel.stdout.toString().trim(); + LocalBundler._runsLocally = new RegExp(`^${PARCEL_VERSION}`).test(version); // Cache result to avoid unnecessary spawns + if (!LocalBundler._runsLocally) { + process.stderr.write(`Incorrect parcel version detected: ${version} <> ${PARCEL_VERSION}. Switching to Docker bundling.\n`); + } return LocalBundler._runsLocally; } catch { return false; } } - private static _runsLocally?: boolean; + public static _runsLocally?: boolean; // public for testing purposes constructor(private readonly props: LocalBundlerProps) {} @@ -89,7 +95,7 @@ export class DockerBundler { buildArgs: { ...props.buildArgs ?? {}, IMAGE: props.runtime.bundlingDockerImage.image, - PARCEL_VERSION: props.parcelVersion ?? '2.0.0-beta.1', + PARCEL_VERSION: props.parcelVersion ?? PARCEL_VERSION, }, }) : cdk.BundlingDockerImage.fromRegistry('dummy'); // Do not build if we don't need to 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 0d7755fbed9e9..064834e6204a0 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -248,3 +248,36 @@ test('Local bundling', () => { // Docker image is not built expect(fromAssetMock).not.toHaveBeenCalled(); }); + +test('LocalBundler.runsLocally checks parcel version and caches results', () => { + LocalBundler._runsLocally = undefined; + + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('2.0.0-beta.1'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(LocalBundler.runsLocally).toBe(true); + expect(LocalBundler.runsLocally).toBe(true); + expect(spawnSyncMock).toHaveBeenCalledTimes(1); + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringContaining('parcel'), ['--version']); +}); + +test('LocalBundler.runsLocally with incorrect parcel version', () => { + LocalBundler._runsLocally = undefined; + + jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('3.5.1'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(LocalBundler.runsLocally).toBe(false); +});