Skip to content

Commit

Permalink
feat(lambda-nodejs): source map mode (#15621)
Browse files Browse the repository at this point in the history
Addresses #14857 by adding source map configuration options. Current implementation preferred preserving backwards compatibility with `sourceMap` boolean flag. See issue discussion for an alternative.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
haimlit committed Jul 20, 2021
1 parent f7c6289 commit b934976
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 31 deletions.
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ new lambda.NodejsFunction(this, 'my-handler', {
bundling: {
minify: true, // minify code, defaults to false
sourceMap: true, // include source map, defaults to false
sourceMapMode: SourceMapMode.INLINE, // defaults to SourceMapMode.DEFAULT
target: 'es2020', // target environment for the generated JavaScript code
loader: { // Use the 'dataurl' loader for '.png' files
'.png': 'dataurl',
Expand Down
12 changes: 10 additions & 2 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda';
import * as cdk from '@aws-cdk/core';
import { EsbuildInstallation } from './esbuild-installation';
import { PackageManager } from './package-manager';
import { BundlingOptions } from './types';
import { BundlingOptions, SourceMapMode } from './types';
import { exec, extractDependencies, findUp } from './util';

const ESBUILD_MAJOR_VERSION = '0';
Expand Down Expand Up @@ -126,14 +126,22 @@ export class Bundling implements cdk.BundlingOptions {
const loaders = Object.entries(this.props.loader ?? {});
const defines = Object.entries(this.props.define ?? {});

if (this.props.sourceMap === false && this.props.sourceMapMode) {
throw new Error('sourceMapMode cannot be used when sourceMap is false');
}
// eslint-disable-next-line no-console
const sourceMapEnabled = this.props.sourceMapMode ?? this.props.sourceMap;
const sourceMapMode = this.props.sourceMapMode ?? SourceMapMode.DEFAULT;
const sourceMapValue = sourceMapMode === SourceMapMode.DEFAULT ? '' : `=${this.props.sourceMapMode}`;

const esbuildCommand: string[] = [
options.esbuildRunner,
'--bundle', `"${pathJoin(options.inputDir, this.relativeEntryPath)}"`,
`--target=${this.props.target ?? toTarget(this.props.runtime)}`,
'--platform=node',
`--outfile="${pathJoin(options.outputDir, 'index.js')}"`,
...this.props.minify ? ['--minify'] : [],
...this.props.sourceMap ? ['--sourcemap'] : [],
...sourceMapEnabled ? [`--sourcemap${sourceMapValue}`] : [],
...this.externals.map(external => `--external:${external}`),
...loaders.map(([ext, name]) => `--loader:${ext}=${name}`),
...defines.map(([key, value]) => `--define:${key}=${JSON.stringify(value)}`),
Expand Down
34 changes: 34 additions & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export interface BundlingOptions {
*/
readonly sourceMap?: boolean;

/**
* Source map mode to be used when bundling.
* @see https://esbuild.github.io/api/#sourcemap
*
* @default SourceMapMode.DEFAULT
*/
readonly sourceMapMode?: SourceMapMode;

/**
* Target environment for the generated JavaScript code.
*
Expand Down Expand Up @@ -266,3 +274,29 @@ export enum LogLevel {
/** Show nothing */
SILENT = 'silent',
}


/**
* SourceMap mode for esbuild
* @see https://esbuild.github.io/api/#sourcemap
*/
export enum SourceMapMode {
/**
* Default sourceMap mode - will generate a .js.map file alongside any generated .js file and add a special //# sourceMappingURL=
* comment to the bottom of the .js file pointing to the .js.map file
*/
DEFAULT = 'default',
/**
* External sourceMap mode - If you want to omit the special //# sourceMappingURL= comment from the generated .js file but you still
* want to generate the .js.map files
*/
EXTERNAL = 'external',
/**
* Inline sourceMap mode - If you want to insert the entire source map into the .js file instead of generating a separate .js.map file
*/
INLINE = 'inline',
/**
* Both sourceMap mode - If you want to have the effect of both inline and external simultaneously
*/
BOTH = 'both'
}
89 changes: 88 additions & 1 deletion packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AssetHashType, DockerImage } from '@aws-cdk/core';
import { version as delayVersion } from 'delay/package.json';
import { Bundling } from '../lib/bundling';
import { EsbuildInstallation } from '../lib/esbuild-installation';
import { LogLevel } from '../lib/types';
import { LogLevel, SourceMapMode } from '../lib/types';
import * as util from '../lib/util';

jest.mock('@aws-cdk/aws-lambda');
Expand Down Expand Up @@ -218,6 +218,93 @@ test('esbuild bundling with esbuild options', () => {
expect(bundleProcess.stdout.toString()).toMatchSnapshot();
});

test('esbuild bundling source map default', () => {
Bundling.bundle({
entry,
projectRoot,
depsLockFilePath,
runtime: Runtime.NODEJS_14_X,
sourceMap: true,
sourceMapMode: SourceMapMode.DEFAULT,
});

// Correctly bundles with esbuild
expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(depsLockFilePath), {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
command: [
'bash', '-c',
[
'esbuild --bundle "/asset-input/lib/handler.ts" --target=node14 --platform=node --outfile="/asset-output/index.js"',
'--sourcemap --external:aws-sdk',
].join(' '),
],
}),
});
});

test('esbuild bundling source map inline', () => {
Bundling.bundle({
entry,
projectRoot,
depsLockFilePath,
runtime: Runtime.NODEJS_14_X,
sourceMap: true,
sourceMapMode: SourceMapMode.INLINE,
});

// Correctly bundles with esbuild
expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(depsLockFilePath), {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
command: [
'bash', '-c',
[
'esbuild --bundle "/asset-input/lib/handler.ts" --target=node14 --platform=node --outfile="/asset-output/index.js"',
'--sourcemap=inline --external:aws-sdk',
].join(' '),
],
}),
});
});

test('esbuild bundling source map enabled when only source map mode exists', () => {
Bundling.bundle({
entry,
projectRoot,
depsLockFilePath,
runtime: Runtime.NODEJS_14_X,
sourceMapMode: SourceMapMode.INLINE,
});

// Correctly bundles with esbuild
expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(depsLockFilePath), {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
command: [
'bash', '-c',
[
'esbuild --bundle "/asset-input/lib/handler.ts" --target=node14 --platform=node --outfile="/asset-output/index.js"',
'--sourcemap=inline --external:aws-sdk',
].join(' '),
],
}),
});
});

test('esbuild bundling throws when sourceMapMode used with false sourceMap', () => {
expect(() => {
Bundling.bundle({
entry,
projectRoot,
depsLockFilePath,
runtime: Runtime.NODEJS_14_X,
sourceMap: false,
sourceMapMode: SourceMapMode.INLINE,
});
}).toThrow('sourceMapMode cannot be used when sourceMap is false');
});

test('Detects yarn.lock', () => {
const yarnLock = path.join(__dirname, '..', 'yarn.lock');
Bundling.bundle({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3Bucket29060E55"
"Ref": "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3Bucket1B1D9794"
},
"S3Key": {
"Fn::Join": [
Expand All @@ -49,7 +49,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3VersionKeyE68A6B82"
"Ref": "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3VersionKey720EECDB"
}
]
}
Expand All @@ -62,7 +62,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3VersionKeyE68A6B82"
"Ref": "AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3VersionKey720EECDB"
}
]
}
Expand Down Expand Up @@ -126,7 +126,7 @@
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3Bucket4A9B4410"
"Ref": "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3Bucket95EC2A4C"
},
"S3Key": {
"Fn::Join": [
Expand All @@ -139,7 +139,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3VersionKeyA27DDFEA"
"Ref": "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3VersionKey0EEB0B14"
}
]
}
Expand All @@ -152,7 +152,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3VersionKeyA27DDFEA"
"Ref": "AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3VersionKey0EEB0B14"
}
]
}
Expand Down Expand Up @@ -758,7 +758,7 @@
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3BucketA6D7D091"
"Ref": "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3Bucket6796DF76"
},
"S3Key": {
"Fn::Join": [
Expand All @@ -771,7 +771,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3VersionKeyD716694C"
"Ref": "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3VersionKeyE83502D3"
}
]
}
Expand All @@ -784,7 +784,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3VersionKeyD716694C"
"Ref": "AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3VersionKeyE83502D3"
}
]
}
Expand Down Expand Up @@ -835,41 +835,41 @@
}
},
"Parameters": {
"AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3Bucket29060E55": {
"AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3Bucket1B1D9794": {
"Type": "String",
"Description": "S3 bucket for asset \"e693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031\""
"Description": "S3 bucket for asset \"790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1\""
},
"AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031S3VersionKeyE68A6B82": {
"AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1S3VersionKey720EECDB": {
"Type": "String",
"Description": "S3 key for asset version \"e693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031\""
"Description": "S3 key for asset version \"790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1\""
},
"AssetParameterse693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031ArtifactHash0218547C": {
"AssetParameters790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1ArtifactHashA9293830": {
"Type": "String",
"Description": "Artifact hash for asset \"e693e416c0e5591cb0eaa424f7526a449f788de8aa8a89f06f27671feaba8031\""
"Description": "Artifact hash for asset \"790877879aeb907c349904efa092342fdc774820821fe50f7b6bf9201c2cfdf1\""
},
"AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3Bucket4A9B4410": {
"AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3Bucket95EC2A4C": {
"Type": "String",
"Description": "S3 bucket for asset \"8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39\""
"Description": "S3 bucket for asset \"55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6\""
},
"AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39S3VersionKeyA27DDFEA": {
"AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6S3VersionKey0EEB0B14": {
"Type": "String",
"Description": "S3 key for asset version \"8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39\""
"Description": "S3 key for asset version \"55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6\""
},
"AssetParameters8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39ArtifactHash13E6F6BF": {
"AssetParameters55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6ArtifactHashE6098BA4": {
"Type": "String",
"Description": "Artifact hash for asset \"8bda5a67feb4905ef8b67b45ee665d3e466be7357e6c361ad2aa773e5867db39\""
"Description": "Artifact hash for asset \"55ec667368ab6d681cbdada49e45f9f8a8dd2d610a1e6c9d6b4f342adb77f3d6\""
},
"AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3BucketA6D7D091": {
"AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3Bucket6796DF76": {
"Type": "String",
"Description": "S3 bucket for asset \"9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736c\""
"Description": "S3 bucket for asset \"39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfe\""
},
"AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cS3VersionKeyD716694C": {
"AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeS3VersionKeyE83502D3": {
"Type": "String",
"Description": "S3 key for asset version \"9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736c\""
"Description": "S3 key for asset version \"39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfe\""
},
"AssetParameters9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736cArtifactHashF03B1BE8": {
"AssetParameters39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfeArtifactHashB3080084": {
"Type": "String",
"Description": "Artifact hash for asset \"9aa4dd3191867438d7cf78d5509ee4ffc26b9f3954f6d9a2977c478b7728736c\""
"Description": "Artifact hash for asset \"39132cdcc42d93606e39f295123475dee67fc9051b50231400eff004dac11dfe\""
}
}
}
6 changes: 5 additions & 1 deletion packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ class TestStack extends Stack {
new lambda.NodejsFunction(this, 'ts-handler', {
entry: path.join(__dirname, 'integ-handlers/ts-handler.ts'),
runtime: Runtime.NODEJS_12_X,
bundling: { minify: true },
bundling: {
minify: true,
sourceMap: true,
sourceMapMode: lambda.SourceMapMode.BOTH,
},
});

new lambda.NodejsFunction(this, 'js-handler', {
Expand Down

0 comments on commit b934976

Please sign in to comment.