_CDK constructs for esbuild, an extremely fast JavaScript bundler_
Getting started | Documentation | API Reference | Python, .NET, & Go | FAQ
Why?
_esbuild_ is an extremely fast bundler and minifier for TypeScript and JavaScript. This package makes _esbuild_ available to deploy AWS Lambda Functions, static websites or publish assets for further usage.
AWS CDK supports _esbuild_ for AWS Lambda Functions, but the implementation cannot be used with other Constructs and doesn't expose all of _esbuild_'s API.
Getting started
Install cdk-esbuild for Node.js using your favorite package manager:
# npm
npm install @mrgrain/cdk-esbuild@5
Yarn
yarn add @mrgrain/cdk-esbuild@5
pnpm
pnpm add @mrgrain/cdk-esbuild@5
For Python, .NET or Go, use these commands:
# Python
pip install mrgrain.cdk-esbuild
.NET
dotnet add package Mrgrain.CdkEsbuild
Go
go get github.com/mrgrain/cdk-esbuild-go/cdkesbuild/v5
AWS Lambda: Serverless function
💡 See Lambda (TypeScript) and Lambda (Python) for working examples of a how to deploy an AWS Lambda Function.
Use TypeScriptCode as the code of a lambda function:
const bundledCode = new TypeScriptCode("src/handler.ts");
const fn = new lambda.Function(stack, "MyFunction", {
runtime: lambda.Runtime.NODEJS_18_X,
handler: "index.handler",
code: bundledCode,
});
AWS S3: Static Website
💡 See React App (TypeScript) for a working example of a how to deploy a React app to S3.
Use TypeScriptSource as one of the sources of a static website deployment:
const websiteBundle = new TypeScriptSource("src/index.tsx");
const websiteBucket = new s3.Bucket(stack, "WebsiteBucket", {
autoDeleteObjects: true,
publicReadAccess: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
websiteIndexDocument: "index.html",
});
new s3deploy.BucketDeployment(stack, "DeployWebsite", {
destinationBucket: websiteBucket,
sources: [websiteBundle],
});
Amazon CloudFront: Functions
💡 See CloudFront Function (TypeScript) for a working example of a CloudFront Distribution using CloudFront Functions.
Use CloudFrontTypeScriptCode as the code of a CloudFront Function:
``ts fixture=local
const functionCode = CloudFrontTypeScriptCode.fromFile("src/function.ts", {
runtime: cloudfront.FunctionRuntime.JS_2_0,
});
const cfFunction = new cloudfront.Function(stack, "MyFunction", { code: functionCode, runtime: cloudfront.FunctionRuntime.JS_2_0, });
ts const bundledCode = new TypeScriptCode("src/canary.ts", { buildOptions: { outdir: "nodejs/node_modules", // This is required by AWS Synthetics }, });### Amazon CloudWatch Synthetics: Canary monitoringTypeScriptCode> 💡 See Monitored Website (TypeScript) for a working example of a deployed and monitored website.
Synthetics runs a canary to produce traffic to an application for monitoring purposes. Use
as thecodeof a Canary test:
const canary = new synthetics.Canary(stack, "MyCanary", { runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_5_1, test: synthetics.Test.custom({ code: bundledCode, handler: "index.handler", }), });
ts // Use the standard Node.js algorithm to detect a locally installed package new EsbuildProvider({ esbuildModulePath: EsbuildSource.nodeJs(), });## Documentationlambda.CodeThe package exports constructs for use with AWS CDK features. The guiding design principal of this package is _"extend, don't replace"_. Expect constructs that you can provide as props, not complete replacements.
For use with Lambda Functions and Synthetic Canaries, implementing
(reference) andsynthetics.Code(reference):TypeScriptCodeInline code is only supported by Lambda:InlineTypeScriptCodeFor use with S3 bucket deployments, implementings3deploy.ISource(reference):TypeScriptSource> _CodeandSourceconstructs seamlessly plug-in to other high-level CDK constructs. They share the same set of parameters, props and build options._TypeScriptAssetThe following classes power the other features. You normally won't have to use them, but they are there if you need them:
implementss3.Asset(reference) \ creates an asset uploaded to S3 which can be referenced by other constructsEsbuildBundlerimplementscore.BundlingOptions(reference) \ provides an interface for a _esbuild_ bundler wherever neededEsbuildProviderimplementsIBuildProviderandITransformProvider\ provides the default _esbuild_ API implementation and can be replaced with a custom implementationcdk-esbuildAPI Reference
Auto-generated reference for Constructs, Classes and Structs. This information is also available as part of your IDE's code completion.
Python, .NET, Go
_Esbuild_ requires a platform and architecture specific binary and currently has to be installed with a Node.js package manager like npm.
When using
with Python, .NET or Go, the package will automatically detect local and global installations of the _esbuild_ npm package. If none can be found, it will fall back to dynamically installing a copy into a temporary location. The exact algorithm of this mechanism must be treated as an implementation detail and should not be relied on. It can however be configured to a certain extent. See the examples below for more details.package.jsonThis "best effort" approach makes it easy to get started. But is not always desirable, for example in environments with limited network access or when guaranteed repeatability of builds is a concern. You have several options to opt-out of this behavior.
Provide a controlled installation of _esbuild_
The first step is to install a version of _esbuild_ that is controlled by you.
I strongly recommend to install _esbuild_ as a local package. The easiest approach is to manage an additional Node.js project at the root of your AWS CDK project. _esbuild_ can then be added to the
file and it is your responsibility to ensure required setup steps are taken in all environments like development machines and CI/CD systems.npm install -g esbuildInstead of installing the _esbuild_ package in a local project, it can also be installed globally with
or a similar command. This approach might be preferred if a build container is prepared ahead of time, thus avoiding repeated package installation.cdk-esbuildChange the automatic package detection
The second step is to make
aware of your chosen install location. This step is optional, but it's a good idea to have the location or at least the method explicitly defined.esbuildModulePathTo do this, you can set the
prop on aEsbuildProvider. Either pass a known, absolute or relative path as value, or use theEsbuildSourcehelper to set the detection method. Please refer to theEsbuildSourcereference for a complete list of available methods.
// Provide an explicit path new EsbuildProvider({ esbuildModulePath: '/home/user/node_modules/esbuild/lib/main.js', });
ts const customModule = new EsbuildProvider({ esbuildModulePath: EsbuildSource.globalPaths(), }); EsbuildProvider.overrideDefaultProvider(customModule);As a no-code approach, theCDK_ESBUILD_MODULE_PATHenvironment variable can be set in the same way. An advantage of this is that the path can easily be changed for different systems. Setting the env variable can be used with any installation approach, but is typically paired with a global installation of the _esbuild_ package. Note thatesbuildModulePathtakes precedence.TypeScriptCodeOverride the default detection method
For an AWS CDK app with many instances of
etc. it would be annoying to change the above for every single one of them. Luckily, the default can be changed for all usages per app:
ts declare const myCustomBuildProvider: IBuildProvider;### Customizing the Esbuild APInpmThis package uses the _esbuild_ JavaScript API. In most situations the default API configuration will be suitable. But sometimes it is required to configure _esbuild_ differently or even provide a custom implementation. Common reasons for this are:
- Using a pre-installed version of _esbuild_ with Python, .NET or Go
- If features not supported by the synchronous API are required, e.g. support for plugins
- If the default version constraints for _esbuild_ are not suitable
- To use a version of esbuild that is installed by any other means than
, including Docker For these scenarios, this package offers customization options and an interface to provide a custom implementation:
new TypeScriptCode("src/handler.ts", { buildProvider: myCustomBuildProvider, });
declare const myCustomTransformProvider: ITransformProvider;
new InlineTypeScriptCode("let x: number = 1", { transformProvider: myCustomTransformProvider, });
ts const buildProvider = new EsbuildProvider({ esbuildBinaryPath: "path/to/esbuild/binary", });#### Esbuild binary pathEsbuildProviderIt is possible to override the binary used by _esbuild_ by setting a property on
. This is the same as setting theESBUILD_BINARY_PATHenvironment variable. Defining theesbuildBinaryPathprop takes precedence.
// This will use a different esbuild binary new TypeScriptCode("src/handler.ts", { buildProvider });
#### Esbuild module path
The Node.js module discovery algorithm will normally be used to find the _esbuild_ package.
It can be useful to use specify a different module path, for example if a globally installed package should be used instead of a local version.
ts
const buildProvider = new EsbuildProvider({
esbuildModulePath: "/home/user/node_modules/esbuild/lib/main.js",
});
// This will use a different esbuild module new TypeScriptCode("src/handler.ts", { buildProvider });
ts class CustomEsbuild implements IBuildProvider, ITransformProvider { buildSync(options: BuildOptions): void { // custom implementation goes here } transformSync(code: string, options?: TransformOptions): string { // custom implementation goes here, return transformed code return 'transformed code'; } }Alternatively supported by setting theCDK_ESBUILD_MODULE_PATHenvironment variable, which will apply to all uses. Defining theesbuildModulePathprop takes precedence.IBuildProviderIf you are a Python, .NET or Go user, refer to the language specific guide for a more detailed explanation of this feature.
Custom Build and Transform API implementations
> 💡 See esbuild plugins w/ TypeScript for a working example of a custom Build API implementation.
A custom implementation can be provided by implementing
orITransformProvider:
// These will use the custom implementation new TypeScriptCode("src/handler.ts", { buildProvider: new CustomEsbuild(), }); new InlineTypeScriptCode("let x: number = 1", { transformProvider: new CustomEsbuild(), });
ts const myCustomEsbuildProvider = new MyCustomEsbuildProvider();Instead of _esbuild_, the custom methods will be invoked with all computed options. Custom implementations can amend, change or discard any of the options.IBuildProviderThe
integration with CDK relies on theoutdir/outfilevalues and it's usually required to use them unchanged.ITransformProvidermust return the transformed code as a string.TypeScriptCodeFailures and warnings should be printed to stderr and thrown as the respective _esbuild_ error.
Overriding the default implementation providers
The default implementation can also be set for all usages of
etc. in an AWS CDK app. You can change the default for both APIs at once or set a different implementation for each of them.
EsbuildProvider.overrideDefaultProvider(myCustomEsbuildProvider); EsbuildProvider.overrideDefaultBuildProvider(myCustomEsbuildProvider); EsbuildProvider.overrideDefaultTransformationProvider(myCustomEsbuildProvider);
// This will use the custom provider without the need to define it as a prop new TypeScriptCode("src/handler.ts");
console npm install esbuild### Roadmap & Contributionscdk-esbuildThe project's roadmap is available on GitHub.
Please submit feature requests as issues to the repository. All contributions are welcome, no matter if they are for already planned or completely new features.
FAQ
Should I use this package in production?
This package is stable and ready to be used in production, as many do. However _esbuild_ has not yet released a version 1.0.0 and its API is still in active development. Please read the guide on esbuild's production readiness.
Note that _esbuild_ minor version upgrades are also introduced in minor versions of this package. Since _esbuild_ is pre v1, these versions typically introduce breaking changes and this package will inherit them. To avoid this behavior, add the desired _esbuild_ version as a dependency to your package.
How do I upgrade from
v4?Cannot find module 'esbuild'Please refer to the v5 release notes for a list of backwards incompatible changes and respective upgrade instructions.
[TS/JS] Why am I getting the error
?This package depends on _esbuild_ as an optional dependencies. If optional dependencies are not installed automatically on your system (e.g. when using npm v4-6), install _esbuild_ explicitly:
### [TS/JS] How can I use a different version of _esbuild_?
Use the override instructions for your package manager to force a specific version, for example:
json
{
"overrides": {
"esbuild": "0.14.7"
}
}
ts const bundledCode = new TypeScriptCode("src/handler.ts", { buildOptions: { unsupportedOption: "value" } as any, });Build and Transform interfaces are relatively stable across _esbuild_ versions. However if any incompatibilities occur,buildOptions/transformOptionscan be cast toany:
js // file: node_modules/construct-library/src/index.ts const props = { buildOptions: { absWorkingDir: path.resolve(__dirname, ".."), // now: /user/local-app/node_modules/construct-library }, }; `### [Python/.NET/Go] How can I use a different version of _esbuild_?buildOptionsInstall the desired version of _esbuild_ locally or globally as described in the documentation above.
Build and Transform interfaces are relatively stable across _esbuild_ versions. However if any incompatibilities occur, use the appropriate language features to cast any incompatible
/transformOptionsto the correct types.cdk-esbuildCan I use this package in my published AWS CDK Construct?
It is possible to use
in a published AWS CDK Construct library, but not recommended. Always prefer to ship a compiled.jsfile or even bundle a zip archive in your package. For AWS Lambda Functions, projen provides an excellent solution.cdk-esbuildIf you do end up consuming
, you will have to setbuildOptions.absWorkingDir. The easiest way to do this, is to resolve the path based on the directory name of the calling file:
This will dynamically resolve to the correct path, wherever the package is installed.
Please open an issue if you encounter any difficulties.
Can I use this package with AWS CDK v1?
Yes,
v2 of cdk-esbuild is compatible with AWS CDK v1.
You can find the documentation for it on the v2 branch.
Support for AWS CDK v1 and
cdk-esbuild` v2 has ended on June 1, 2023.
Both packages are not receiving any updates or bug fixes, including for security related issues.
You are strongly advised to upgrade to a supported version of these packages.