You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* upgrade integration tests to use nodejs14.x instead of obsolete 8.10; remove garbage lockfile left by npm 7
* esbuild bundling for javascript
* initial esbuild support
* aws-sam -> aws_sam, revert to node 10 for integration tests, document package.json options
* rename main -> entry_point, support multiple entrypoints
* Update Appveyor nodejs version
* Testing different node version
* Update npm to version that supports node14
* Cleanup garbage package lock in dependencies dir generated by npm 7
* PEP8 compliance and missing doc strings
* Add support for auto dep layer and incremental build with esbuild
* Fix documentation
* Revert accelerate feature changes
* Add experimental feature flag, route all requests to old workflow
* Add experimental feature flag, route all requests to old workflow
* Remove unused variable
* Black reformat
Co-authored-by: Gojko Adzic <[email protected]>
The general algorithm for preparing a node package for use on AWS Lambda
79
-
is as follows.
172
+
without a JavaScript bundler (`esbuild` or `webpack`) is as follows.
80
173
81
174
#### Step 1: Prepare a clean copy of the project source files
82
175
@@ -134,3 +227,157 @@ To fully support dependencies that download or compile binaries for a target pla
134
227
needs to be executed inside a Docker image compatible with AWS Lambda.
135
228
_(out of scope for the current version)_
136
229
230
+
### Implementation with a bundler
231
+
232
+
The general algorithm for preparing a node package for use on AWS Lambda
233
+
with a bundler (`esbuild` or `webpack`) is as follows.
234
+
235
+
#### Step 1: ensure production dependencies are installed
236
+
237
+
If the directory contains `package-lock.json` or `npm-shrinkwrap.json`,
238
+
execute [`npm ci`](https://docs.npmjs.com/cli/v7/commands/npm-ci). This
239
+
operation is designed to be faster than installing dependencies using `npm install`
240
+
in automated CI environments.
241
+
242
+
If the directory does not contain lockfiles, but contains `package.json`,
243
+
execute [`npm install --production`] to download production dependencies.
244
+
245
+
#### Step 2: bundle the main Lambda file
246
+
247
+
Execute `esbuild` to produce a single JavaScript file by recursively resolving
248
+
included dependencies, and optionally a source map.
249
+
250
+
Ensure that the target file name is the same as the entry point of the Lambda
251
+
function, so that there is no impact on the CloudFormation template.
252
+
253
+
254
+
### Activating the bundler workflow
255
+
256
+
Because there are advantages and disadvantages to both approaches (with and
257
+
without a bundler), the user should be able to choose between them. The default
258
+
is not to use a bundler (both because it's universally applicable and for
259
+
backwards compatibility). Node.js pakage manifests (`package.json`) allow for
260
+
custom properties, so a user can activate the bundler process by providing an
261
+
`aws_sam` configuration property in the package manifest. If this property is
262
+
present in the package manifest, and the sub-property `bundler` equals
263
+
`esbuild`, the Node.js NPM Lambda builder activates the bundler process.
264
+
265
+
Because the Lambda builder workflow is not aware of the main lambda function
266
+
definition, (the file containing the Lambda handler function) the user must
267
+
also specify the main entry point for bundling . This is a bit of an
268
+
unfortunate duplication with SAM Cloudformation template, but with the current
269
+
workflow design there is no way around it.
270
+
271
+
In addition, as a single JavaScript source package can contain multiple functions,
272
+
and can be included multiple times in a single CloudFormation template, it's possible
273
+
that there may be multiple entry points for bundling. SAM build executes the build
274
+
only once for the function in this case, so all entry points have to be bundled
275
+
at once.
276
+
277
+
The following example is a minimal `package.json` to activate the `esbuild` bundler
278
+
on a javascript file, starting from `lambda.js`. It will produce a bundled `lambda.js`
279
+
in the artifacts folder.
280
+
281
+
```json
282
+
{
283
+
"name": "nodeps-esbuild",
284
+
"version": "1.0.0",
285
+
"license": "APACHE2.0",
286
+
"aws_sam": {
287
+
"bundler": "esbuild",
288
+
"entry_points": ["lambda.js"]
289
+
}
290
+
}
291
+
```
292
+
293
+
#### Locating the esbuild binary
294
+
295
+
`esbuild` supports platform-independent binary distribution using NPM, by
296
+
including the `esbuild` package as a dependency. The Lambda builder should
297
+
first try to locate the binary in the Lambda code repository (allowing the
298
+
user to include a specific version). Failing that, the Lambda builder should
299
+
try to locate the `esbuild` binary in the `executable_search_paths` configured
300
+
for the workflow, then the operating system `PATH` environment variable.
301
+
302
+
The Lambda builder **should not** bring its own `esbuild` binary, but it should
303
+
clearly point to the error when one is not found, to allow users to configure the
304
+
build correctly.
305
+
306
+
In the previous example, the esbuild binary is not included in the package dependencies,
307
+
so the Lambda builder will use the system executable paths to search for it. In the
308
+
example below, `esbuild` is included in the package, so the Lambda builder should use it
309
+
directly.
310
+
311
+
```json
312
+
{
313
+
"name": "with-deps-esbuild",
314
+
"version": "1.0.0",
315
+
"license": "APACHE2.0",
316
+
"aws_sam": {
317
+
"bundler": "esbuild",
318
+
"entry_points": ["lambda.js"]
319
+
},
320
+
"devDependencies": {
321
+
"esbuild": "^0.11.23"
322
+
}
323
+
}
324
+
```
325
+
326
+
For a full example, see the [`with-deps-esbuild`](../../../tests/integration/workflows/nodejs_npm/testdata/with-deps-esbuild/) test project.
327
+
328
+
#### Building typescript
329
+
330
+
`esbuild` supports bundling typescript out of the box and transpiling it to plain
331
+
javascript. The user just needs to point to a typescript file as the main entry point,
332
+
as in the example below. There is no transpiling process needed upfront.
333
+
334
+
335
+
```js
336
+
{
337
+
"name":"with-deps-esbuild-typescript",
338
+
"version":"1.0.0",
339
+
"license":"APACHE2.0",
340
+
"aws_sam": {
341
+
"bundler":"esbuild",
342
+
"entry_points": ["included.ts"]
343
+
},
344
+
"dependencies": {
345
+
"@types/aws-lambda":"^8.10.76"
346
+
},
347
+
"devDependencies": {
348
+
"esbuild":"^0.11.23"
349
+
}
350
+
}
351
+
```
352
+
353
+
For a full example, see the [`with-deps-esbuild-typescript`](../../../tests/integration/workflows/nodejs_npm/testdata/with-deps-esbuild-typescript/) test project.
354
+
355
+
**important note:** esbuild does not perform type checking, so users wanting to ensure type-checks need to run the `tsc` process as part of their
356
+
testing flow before invoking `sam build`. For additional typescript caveats with esbuild, check out <https://esbuild.github.io/content-types/#typescript>.
357
+
358
+
#### Configuring the bundler
359
+
360
+
The Lambda builder invokes `esbuild` with sensible defaults that will work for the majority of cases. Importantly, the following three parameters are set by default
361
+
362
+
*`--minify`, as it [produces a smaller runtime package](https://esbuild.github.io/api/#minify)
363
+
*`--sourcemap`, as it generates a [source map that allows for correct stack trace reporting](https://esbuild.github.io/api/#sourcemap) in case of errors (see the [Error reporting](#error-reporting) section above)
364
+
*`--target es2020`, as it allows for javascript features present in Node 14
365
+
366
+
Users might want to tweak some of these runtime arguments for a specific project, for example not including the source map to further reduce the package size, or restricting javascript features to an older version. The Lambda builder allows this with optional sub-properties of the `aws_sam` configuration property.
367
+
368
+
*`target`: string, corresponding to a supported [esbuild target](https://esbuild.github.io/api/#target) property
369
+
*`minify`: boolean, defaulting to `true`
370
+
*`sourcemap`: boolean, defaulting to `true`
371
+
372
+
Here is an example that deactivates minification and source maps, and supports JavaScript features compatible with Node.js version 10.
0 commit comments