cdk-booster 1.1.0-alpha.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,17 +58,112 @@ const functionTestJsEsModule = new lambda_nodejs.NodejsFunction(
58
58
  );
59
59
  ```
60
60
 
61
- ### Verbose Logging
61
+ ### Command Line Parameters
62
+
63
+ CDK Booster supports several command-line parameters to customize its behavior:
64
+
65
+ #### Verbose Logging
62
66
 
63
67
  To enable verbose logging for debugging purposes, add the `-v` parameter:
64
68
 
65
69
  ```json
66
70
  {
67
- "app": "npx cdk-booster bin/your_app.ts -v".
71
+ "app": "npx cdk-booster bin/your_app.ts -v",
72
+ ...
73
+ }
74
+ ```
75
+
76
+ #### Batch Size (`-b`, `--batch`)
77
+
78
+ Controls the number of Lambda functions bundled together in a single ESBuild batch. This is particularly useful for large projects with many Lambda functions (100+).
79
+
80
+ **Default:** No limit (all Lambdas with identical build settings are bundled together)
81
+
82
+ **When to use:**
83
+
84
+ - For projects with 100+ Lambda functions
85
+ - To reduce memory usage during builds
86
+
87
+ **Example:**
88
+
89
+ ```json
90
+ {
91
+ "app": "npx cdk-booster bin/your_app.ts -b 20",
92
+ ...
93
+ }
94
+ ```
95
+
96
+ Setting `-b 20` limits each ESBuild batch to 20 Lambda functions. If ESBuild crashes, only that batch of 20 functions is affected rather than all functions. Functions in the failed batch will still be bundled by CDK's standard process.
97
+
98
+ #### Parallel Builds (`-p`, `--parallel`)
99
+
100
+ Controls the maximum number of parallel ESBuild processes running simultaneously.
101
+
102
+ **Default:** Unlimited (all batches run in parallel)
103
+
104
+ **When to use:**
105
+
106
+ - To limit resource usage (CPU/memory) on constrained environments
107
+ - For CI/CD pipelines with limited resources
108
+ - When experiencing ESBuild crashes due to too many concurrent processes
109
+
110
+ **Example:**
111
+
112
+ ```json
113
+ {
114
+ "app": "npx cdk-booster bin/your_app.ts -p 1",
68
115
  ...
69
116
  }
70
117
  ```
71
118
 
119
+ Setting `-p 1` ensures only one ESBuild process runs at a time, which can help prevent crashes on resource-constrained systems.
120
+
121
+ #### Combining Parameters
122
+
123
+ You can combine multiple parameters for fine-tuned control:
124
+
125
+ ```json
126
+ {
127
+ "app": "npx cdk-booster bin/your_app.ts -b 20 -p 2 -v",
128
+ ...
129
+ }
130
+ ```
131
+
132
+ ### Skipping Specific Lambda Functions
133
+
134
+ You can exclude individual Lambda functions from CDK Booster processing by setting the `SKIP_CDK_BOOSTER` environment variable in the `bundling` property. This is useful when:
135
+
136
+ - A specific Lambda consistently causes bundling errors
137
+ - You want to use custom bundling settings for particular functions
138
+ - You need to debug issues with specific Lambda functions
139
+
140
+ **Important:** This is a bundling-time environment variable (set in `bundling.environment`), not a runtime environment variable for your Lambda function.
141
+
142
+ **Example:**
143
+
144
+ ```typescript
145
+ import * as lambda_nodejs from 'aws-cdk-lib/aws-lambda-nodejs';
146
+
147
+ // This Lambda will be skipped by CDK Booster
148
+ new lambda_nodejs.NodejsFunction(this, 'ProblematicFunction', {
149
+ entry: 'services/problematic/handler.ts',
150
+ environment: {
151
+ // Runtime environment variables for your Lambda
152
+ API_ENDPOINT: 'https://api.example.com',
153
+ },
154
+ bundling: {
155
+ environment: {
156
+ // Bundling-time environment variable - tells CDK Booster to skip this function
157
+ SKIP_CDK_BOOSTER: 'true',
158
+ },
159
+ minify: false,
160
+ sourceMap: true,
161
+ },
162
+ });
163
+ ```
164
+
165
+ When a Lambda is skipped, CDK Booster ignores it during the pre-bundling phase, and AWS CDK will bundle it using its standard (slower) sequential process. The function will still work normally - it just won't benefit from CDK Booster's speed improvements.
166
+
72
167
  ## How It Works
73
168
 
74
169
  CDK Booster operates through a multi-phase process:
@@ -98,6 +193,15 @@ If CDK needs to run synthesis again due to unresolved resources requiring lookup
98
193
  - AWS CDK v2.x with TypeScript
99
194
  - TypeScript or JavaScript Lambda handlers using `NodejsFunction` construct
100
195
 
196
+ ## Troubleshooting
197
+
198
+ For large projects, if you encounter ESBuild crashes:
199
+
200
+ - **Upgrade ESBuild:** Try upgrading ESBuild to the latest version.
201
+ - **Start with:** `-b 5 -p 1` (batch size 5, sequential processing)
202
+ - **Then adjust:** Increase batch size or parallelism based on your system resources
203
+ - **Skip specific functions:** Add `SKIP_CDK_BOOSTER: 'true'` to `bundling.environment` for problematic Lambdas
204
+
101
205
  ## Authors
102
206
 
103
207
  - [Marko (ServerlessLife)](https://www.serverlesslife.com/)
@@ -53,7 +53,9 @@ async function run() {
53
53
  compileCodeFile,
54
54
  });
55
55
  Logger.verbose(`Found ${lambdas.length} Lambda functions in the CDK code:`, JSON.stringify(lambdas, null, 2));
56
- const lambdasEsBuildCommands = lambdas;
56
+ let lambdasEsBuildCommands = lambdas;
57
+ // skip all lambdas that have SKIP_CDK_BOOSTER env var set to true in their bundling environment
58
+ lambdasEsBuildCommands = lambdasEsBuildCommands.filter((lambda) => lambda.environment?.SKIP_CDK_BOOSTER !== 'true');
57
59
  // Prepare bundling temp folders for each Lambda function
58
60
  await recreateBundlingTempFolders(lambdasEsBuildCommands);
59
61
  // Execute pre-bundling commands
@@ -97,9 +99,9 @@ async function bundle(lambdasEsBuildCommands) {
97
99
  for (const buildBatch of buildBatches) {
98
100
  const build = async () => {
99
101
  parallelCount++;
102
+ const buildOptions = buildBatch.buildOptions;
103
+ const entryPoints = buildBatch.entryPoints;
100
104
  try {
101
- const buildOptions = buildBatch.buildOptions;
102
- const entryPoints = buildBatch.entryPoints;
103
105
  const normalizedEsbuildArgs = normalizeEsbuildArgs(buildOptions.esbuildArgs);
104
106
  const esBuildOpt = {
105
107
  entryPoints,
@@ -142,6 +144,9 @@ async function bundle(lambdasEsBuildCommands) {
142
144
  ...buildingResults.metafile?.outputs,
143
145
  };
144
146
  }
147
+ catch (error) {
148
+ Logger.error(`The following functions failed to bundle:\n - ${entryPoints.join('\n - ')}. Set batch parameter (-b) to a smaller number, like 5, to lower the chance of this error, and in case of error, a smaller batch would be affected.`, error);
149
+ }
145
150
  finally {
146
151
  parallelCount--;
147
152
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chalk",
3
- "version": "5.6.0",
3
+ "version": "5.6.2",
4
4
  "description": "Terminal string styling done right",
5
5
  "license": "MIT",
6
6
  "repository": "chalk/chalk",
@@ -943,7 +943,7 @@ You can configure the help by modifying data properties and methods using `.conf
943
943
 
944
944
  Simple properties include `sortSubcommands`, `sortOptions`, and `showGlobalOptions`. You can add color using the style methods like `styleTitle()`.
945
945
 
946
- For more detail and examples of changing the displayed text, color, and layout see (./docs/help-in-depth.md).
946
+ For more detail and examples of changing the displayed text, color, and layout see [help in depth](./docs/help-in-depth.md).
947
947
 
948
948
  ## Custom event listeners
949
949
 
@@ -1063,7 +1063,7 @@ customise the new subcommand (example file [custom-command-class.js](./examples/
1063
1063
  You can enable `--harmony` option in two ways:
1064
1064
 
1065
1065
  - Use `#! /usr/bin/env node --harmony` in the subcommands scripts. (Note Windows does not support this pattern.)
1066
- - Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning subcommand process.
1066
+ - Use the `--harmony` option when calling the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning subcommand processes.
1067
1067
 
1068
1068
  ### Debugging stand-alone executable subcommands
1069
1069
 
@@ -33,7 +33,7 @@ class Argument {
33
33
  break;
34
34
  }
35
35
 
36
- if (this._name.length > 3 && this._name.slice(-3) === '...') {
36
+ if (this._name.endsWith('...')) {
37
37
  this.variadic = true;
38
38
  this._name = this._name.slice(0, -3);
39
39
  }
@@ -53,12 +53,13 @@ class Argument {
53
53
  * @package
54
54
  */
55
55
 
56
- _concatValue(value, previous) {
56
+ _collectValue(value, previous) {
57
57
  if (previous === this.defaultValue || !Array.isArray(previous)) {
58
58
  return [value];
59
59
  }
60
60
 
61
- return previous.concat(value);
61
+ previous.push(value);
62
+ return previous;
62
63
  }
63
64
 
64
65
  /**
@@ -103,7 +104,7 @@ class Argument {
103
104
  );
104
105
  }
105
106
  if (this.variadic) {
106
- return this._concatValue(arg, previous);
107
+ return this._collectValue(arg, previous);
107
108
  }
108
109
  return arg;
109
110
  };
@@ -245,11 +245,10 @@ class Command extends EventEmitter {
245
245
  configureOutput(configuration) {
246
246
  if (configuration === undefined) return this._outputConfiguration;
247
247
 
248
- this._outputConfiguration = Object.assign(
249
- {},
250
- this._outputConfiguration,
251
- configuration,
252
- );
248
+ this._outputConfiguration = {
249
+ ...this._outputConfiguration,
250
+ ...configuration,
251
+ };
253
252
  return this;
254
253
  }
255
254
 
@@ -375,7 +374,7 @@ class Command extends EventEmitter {
375
374
  */
376
375
  addArgument(argument) {
377
376
  const previousArgument = this.registeredArguments.slice(-1)[0];
378
- if (previousArgument && previousArgument.variadic) {
377
+ if (previousArgument?.variadic) {
379
378
  throw new Error(
380
379
  `only the last argument can be variadic '${previousArgument.name()}'`,
381
380
  );
@@ -702,7 +701,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
702
701
  if (val !== null && option.parseArg) {
703
702
  val = this._callParseArg(option, val, oldValue, invalidValueMessage);
704
703
  } else if (val !== null && option.variadic) {
705
- val = option._concatValue(val, oldValue);
704
+ val = option._collectValue(val, oldValue);
706
705
  }
707
706
 
708
707
  // Fill-in appropriate missing values. Long winded but easy to follow.
@@ -1481,7 +1480,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1481
1480
 
1482
1481
  _chainOrCall(promise, fn) {
1483
1482
  // thenable
1484
- if (promise && promise.then && typeof promise.then === 'function') {
1483
+ if (promise?.then && typeof promise.then === 'function') {
1485
1484
  // already have a promise, chain callback
1486
1485
  return promise.then(() => fn());
1487
1486
  }
@@ -1612,7 +1611,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1612
1611
  promiseChain = this._chainOrCallHooks(promiseChain, 'postAction');
1613
1612
  return promiseChain;
1614
1613
  }
1615
- if (this.parent && this.parent.listenerCount(commandEvent)) {
1614
+ if (this.parent?.listenerCount(commandEvent)) {
1616
1615
  checkForUnknownOptions();
1617
1616
  this._processArguments();
1618
1617
  this.parent.emit(commandEvent, operands, unknown); // legacy
@@ -1742,15 +1741,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
1742
1741
  * sub --unknown uuu op => [sub], [--unknown uuu op]
1743
1742
  * sub -- --unknown uuu op => [sub --unknown uuu op], []
1744
1743
  *
1745
- * @param {string[]} argv
1744
+ * @param {string[]} args
1746
1745
  * @return {{operands: string[], unknown: string[]}}
1747
1746
  */
1748
1747
 
1749
- parseOptions(argv) {
1748
+ parseOptions(args) {
1750
1749
  const operands = []; // operands, not options or values
1751
1750
  const unknown = []; // first unknown option and remaining unknown args
1752
1751
  let dest = operands;
1753
- const args = argv.slice();
1754
1752
 
1755
1753
  function maybeOption(arg) {
1756
1754
  return arg.length > 1 && arg[0] === '-';
@@ -1769,13 +1767,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
1769
1767
 
1770
1768
  // parse options
1771
1769
  let activeVariadicOption = null;
1772
- while (args.length) {
1773
- const arg = args.shift();
1770
+ let activeGroup = null; // working through group of short options, like -abc
1771
+ let i = 0;
1772
+ while (i < args.length || activeGroup) {
1773
+ const arg = activeGroup ?? args[i++];
1774
+ activeGroup = null;
1774
1775
 
1775
1776
  // literal
1776
1777
  if (arg === '--') {
1777
1778
  if (dest === unknown) dest.push(arg);
1778
- dest.push(...args);
1779
+ dest.push(...args.slice(i));
1779
1780
  break;
1780
1781
  }
1781
1782
 
@@ -1793,17 +1794,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
1793
1794
  // recognised option, call listener to assign value with possible custom processing
1794
1795
  if (option) {
1795
1796
  if (option.required) {
1796
- const value = args.shift();
1797
+ const value = args[i++];
1797
1798
  if (value === undefined) this.optionMissingArgument(option);
1798
1799
  this.emit(`option:${option.name()}`, value);
1799
1800
  } else if (option.optional) {
1800
1801
  let value = null;
1801
1802
  // historical behaviour is optional value is following arg unless an option
1802
1803
  if (
1803
- args.length > 0 &&
1804
- (!maybeOption(args[0]) || negativeNumberArg(args[0]))
1804
+ i < args.length &&
1805
+ (!maybeOption(args[i]) || negativeNumberArg(args[i]))
1805
1806
  ) {
1806
- value = args.shift();
1807
+ value = args[i++];
1807
1808
  }
1808
1809
  this.emit(`option:${option.name()}`, value);
1809
1810
  } else {
@@ -1826,9 +1827,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1826
1827
  // option with value following in same argument
1827
1828
  this.emit(`option:${option.name()}`, arg.slice(2));
1828
1829
  } else {
1829
- // boolean option, emit and put back remainder of arg for further processing
1830
+ // boolean option
1830
1831
  this.emit(`option:${option.name()}`);
1831
- args.unshift(`-${arg.slice(2)}`);
1832
+ // remove the processed option and keep processing group
1833
+ activeGroup = `-${arg.slice(2)}`;
1832
1834
  }
1833
1835
  continue;
1834
1836
  }
@@ -1865,26 +1867,23 @@ Expecting one of '${allowedValues.join("', '")}'`);
1865
1867
  ) {
1866
1868
  if (this._findCommand(arg)) {
1867
1869
  operands.push(arg);
1868
- if (args.length > 0) unknown.push(...args);
1870
+ unknown.push(...args.slice(i));
1869
1871
  break;
1870
1872
  } else if (
1871
1873
  this._getHelpCommand() &&
1872
1874
  arg === this._getHelpCommand().name()
1873
1875
  ) {
1874
- operands.push(arg);
1875
- if (args.length > 0) operands.push(...args);
1876
+ operands.push(arg, ...args.slice(i));
1876
1877
  break;
1877
1878
  } else if (this._defaultCommandName) {
1878
- unknown.push(arg);
1879
- if (args.length > 0) unknown.push(...args);
1879
+ unknown.push(arg, ...args.slice(i));
1880
1880
  break;
1881
1881
  }
1882
1882
  }
1883
1883
 
1884
1884
  // If using passThroughOptions, stop processing options at first command-argument.
1885
1885
  if (this._passThroughOptions) {
1886
- dest.push(arg);
1887
- if (args.length > 0) dest.push(...args);
1886
+ dest.push(arg, ...args.slice(i));
1888
1887
  break;
1889
1888
  }
1890
1889
 
@@ -162,12 +162,13 @@ class Option {
162
162
  * @package
163
163
  */
164
164
 
165
- _concatValue(value, previous) {
165
+ _collectValue(value, previous) {
166
166
  if (previous === this.defaultValue || !Array.isArray(previous)) {
167
167
  return [value];
168
168
  }
169
169
 
170
- return previous.concat(value);
170
+ previous.push(value);
171
+ return previous;
171
172
  }
172
173
 
173
174
  /**
@@ -186,7 +187,7 @@ class Option {
186
187
  );
187
188
  }
188
189
  if (this.variadic) {
189
- return this._concatValue(arg, previous);
190
+ return this._collectValue(arg, previous);
190
191
  }
191
192
  return arg;
192
193
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commander",
3
- "version": "14.0.0",
3
+ "version": "14.0.1",
4
4
  "description": "the complete solution for node.js command-line programs",
5
5
  "keywords": [
6
6
  "commander",
@@ -61,16 +61,16 @@
61
61
  },
62
62
  "devDependencies": {
63
63
  "@eslint/js": "^9.4.0",
64
- "@types/jest": "^29.2.4",
64
+ "@types/jest": "^30.0.0",
65
65
  "@types/node": "^22.7.4",
66
66
  "eslint": "^9.17.0",
67
67
  "eslint-config-prettier": "^10.0.1",
68
- "eslint-plugin-jest": "^28.3.0",
68
+ "eslint-plugin-jest": "^29.0.1",
69
69
  "globals": "^16.0.0",
70
- "jest": "^29.3.1",
70
+ "jest": "^30.0.3",
71
71
  "prettier": "^3.2.5",
72
72
  "ts-jest": "^29.0.3",
73
- "tsd": "^0.31.0",
73
+ "tsd": "^0.33.0",
74
74
  "typescript": "^5.0.4",
75
75
  "typescript-eslint": "^8.12.2"
76
76
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdk-booster",
3
- "version": "1.1.0-alpha.2",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "Speed up AWS CDK's bundling of TypeScript/JavaScript Lambda handlers",
6
6
  "homepage": "https://www.cdkbooster.com",
@@ -60,30 +60,30 @@
60
60
  "docs:preview": "vitepress preview"
61
61
  },
62
62
  "devDependencies": {
63
- "@eslint/js": "^9.34.0",
63
+ "@eslint/js": "^9.37.0",
64
64
  "@tsconfig/node22": "^22.0.2",
65
65
  "@types/eslint-config-prettier": "^6.11.3",
66
- "@types/node": "^24.3.0",
67
- "aws-cdk": "2.1027.0",
68
- "aws-cdk-lib": "2.213.0",
66
+ "@types/node": "^24.7.2",
67
+ "aws-cdk": "2.1030.0",
68
+ "aws-cdk-lib": "2.219.0",
69
69
  "constructs": "^10.4.2",
70
- "eslint": "^9.34.0",
70
+ "eslint": "^9.37.0",
71
71
  "eslint-config-prettier": "^10.1.8",
72
- "globals": "^16.3.0",
72
+ "globals": "^16.4.0",
73
73
  "husky": "^9.1.7",
74
74
  "prettier": "^3.6.2",
75
- "semantic-release": "^24.2.7",
76
- "tsx": "^4.20.5",
77
- "typescript-eslint": "^8.41.0",
75
+ "semantic-release": "^24.2.9",
76
+ "tsx": "^4.20.6",
77
+ "typescript-eslint": "^8.46.1",
78
78
  "vitepress": "^1.6.4",
79
- "@aws-sdk/client-lambda": "^3.879.0",
79
+ "@aws-sdk/client-lambda": "^3.908.0",
80
80
  "adm-zip": "^0.5.16",
81
81
  "@types/adm-zip": "^0.5.7"
82
82
  },
83
83
  "dependencies": {
84
- "chalk": "^5.6.0",
85
- "commander": "^14.0.0",
86
- "typescript": "~5.9.2"
84
+ "chalk": "^5.6.2",
85
+ "commander": "^14.0.1",
86
+ "typescript": "~5.9.3"
87
87
  },
88
88
  "peerDependencies": {
89
89
  "esbuild": "^0"