Skip to content

πŸ’¨ A Serverless framework plugin to bundle JavaScript and TypeScript with extremely fast esbuild

License

Notifications You must be signed in to change notification settings

floydspace/serverless-esbuild

Repository files navigation

πŸ’¨ serverless-esbuild

Serverless Framework plugin for zero-config JavaScript and TypeScript code bundling using promising fast & furious esbuild bundler and minifier

serverless npm version npm downloads build status semantic-release

Features

  • Zero-config: Works out of the box without the need to install any additional plugins
  • Works with Typescript and Javascript projects
  • Guaranteed to work in Node.js v18 and higher environments
  • Supports sls package, sls deploy, sls deploy function
  • Integrates with Serverless Invoke Local & serverless-offline

Table of Contents

Install

# install `serverless-esbuild` and `esbuild`
yarn add --dev serverless-esbuild esbuild
# or
npm install -D serverless-esbuild esbuild
# or
pnpm install -D serverless-esbuild esbuild

Add the following plugin to your serverless.yml:

plugins:
  - serverless-esbuild

Configuration

By default, no configuration is required, but you can override the default behavior via the custom.esbuild section in the serverless.yml file.

custom:
  esbuild:
    bundle: true
    minify: false

Examples

See example folder for some example configurations.

Options

Option Description Default
Esbuild Options This plugin can take almost any Esbuild Javascript Build Option. Default Esbuild Options
concurrency The number of concurrent bundle operations to run at once. eg. 8. NOTE: This can be memory intensive and could produce slower builds. Infinity
zipConcurrency The number of concurrent zip operations to run at once. eg. 8. NOTE: This can be memory intensive and could produce slower builds. Infinity
exclude An array of dependencies to exclude from the Lambda. This is passed to the esbuild external option. Set to * to disable packaging node_modules ['aws-sdk']
installExtraArgs Optional arguments passed to npm or yarn for external dependency resolution. eg. ['--legacy-peer-deps'] for npm v7+ to use legacy peerDependency resolution behavior []
keepOutputDirectory Keeps the .esbuild output folder. Useful for debugging. false
nativeZip Uses the system's zip executable to create archives. NOTE: This will produce non-deterministic archives which causes a Serverless deployment update on every deploy. false
outputBuildFolder The output folder for Esbuild builds within the work folder. You will also need to manually override the watch ignore config if used. '.build'
outputWorkFolder The output folder for this plugin where all the bundle preparation is done. You will also need to manually override the watch ignore config if used. '.esbuild'
outputFileExtension The file extension used for the bundled output file. This will override the esbuild outExtension option '.js'
packagePath Path to the package.json file for external dependency resolution. './package.json'
packager Packager to use for external dependency resolution. Values: npm, yarn, pnpm 'npm'
packagerOptions Extra options for packagers for external dependency resolution. Packager Options
watch Watch options for serverless-offline. Watch Options
skipBuild Avoid rebuilding lambda artifacts in favor of reusing previous build artifacts. false
skipRebuild A boolean defining whether rebuild is avoided. Generally rebuild produces faster builds but in some context scenarios with many lambdas or low memory computer (like Github Actions) it can cause memory leaks. false
skipBuildExcludeFns An array of lambda names that will always be rebuilt if skipBuild is set to true and bundling individually. This is helpful for dynamically generated functions like serverless-plugin-warmup. []
stripEntryResolveExtensions A boolean that determines if entrypoints using custom file extensions provided in the resolveExtensions ESbuild setting should be stripped of their custom extension upon packing the final bundle for that file. Example: myLambda.custom.ts would result in myLambda.js instead of myLambda.custom.js.
disposeContext An option to disable the disposal of the context.(Functions can override the global disposeContext configuration by specifying their own disposeContext option in their individual configurations.) true

Default Esbuild Options

The following esbuild options are automatically set.

Option Default Notes
bundle true Esbuild requires this for use with external
entryPoints N/A Cannot be overridden
outDir N/A Cannot be overridden
platform 'node' Set format to esm to enable ESM support
target 'node18' We dynamically set this. See Supported Runtimes
watch N/A Cannot be overridden

Packager Options

Option Description Default
scripts A string or array of scripts to be executed, currently only supports 'scripts' for npm, pnpm and yarn undefined
noInstall [Yarn only] A boolean that deactivates the install step false
ignoreLockfile [Yarn only] A boolean to bypass lockfile validation, typically paired with external dependencies because we generate a new package.json with only the externalized dependencies. false

Watch Options

Option Description Default
pattern An anymatch-compatible definition for the watcher to respond to ./**/*.(js|ts) (watches all .js and .ts files)
ignore An anymatch-compatible definition for the watcher to ignore ['.esbuild', 'dist', 'node_modules', '.build']
chokidar Any Chokidar option { ignoreInitial: true }

Function Options

Option Description Default
skipEsbuild Set this property to true on a function definition to skip esbuild undefined

Supported Runtimes

This plugin will automatically set the esbuild target for the following supported Serverless runtimes:

AWS

Runtime Target
nodejs20.x node20
nodejs18.x node18
nodejs16.x node16
nodejs14.x node14
nodejs12.x node12

Google

This plugin is compatible with the serverless-google-cloudfunctions plugin, and will set the runtimes accordingly.

Runtime Target
nodejs20 node20
nodejs18 node18
nodejs16 node16
nodejs14 node14
nodejs12 node12

Azure

This plugin is compatible with the serverless-azure-functions plugin, and will set the runtimes accordingly.

Runtime Target
nodejs18 node18
nodejs16 node16
nodejs14 node14
nodejs12 node12

Please Note When using this package in conjunction with the serverless-azure-functions plugin, the following additional configuration is required to ensure function apps are built correctly:

package:
	patterns: ["host.json", "**/function.json"],

Non-Node functions

If you wish to use this plugin alongside non Node functions like Python or functions with images, this plugin will automatically ignore any function which does not contain a handler or use a supported Node.js runtime.

Note: If you are using Python functions with Serverless Offline you will need to change the outputWorkFolder and outputBuildFolder to folder names without fullstops.

Advanced Configuration

Config file

Esbuild configuration can be defined by a config file.

custom:
  esbuild:
    config: './esbuild.config.js'
// esbuild.config.js
module.exports = (serverless) => ({
  external: ['lodash'],
  plugins: [],
});

Including Extra Files

Serverless Package Configuration will behave in the same way as native packaging. You can use patterns, include and exclude to include extra files into your bundles.

External Dependencies

Packages that are marked as external and exist in the package.json's dependencies will be installed and included with your build under node_modules. You can customize this with a number of options.

custom:
  esbuild:
    external:
      - lodash
    packager: yarn
    packagePath: absolute/path/to/package.json
    packagerOptions:
      scripts:
        - echo 'Hello World!'
        - rm -rf node_modules
    installExtraArgs:
      - '--legacy-peer-deps'

To easily mark all the dependencies in package.json as external, you can utilize esbuild-node-externals plugin.

To mark one or more individual packages as external, use the following configuration:

custom:
  esbuild:
    external:
      - 'my-package-name'
      - 'another-package-name'

Esbuild Plugins

Note: The Esbuild plugins API is still experimental

You can configure esbuild plugins by passing a plugins' configuration file:

custom:
  esbuild:
    plugins: plugins.js

The plugins' configuration file must be a javascript file exporting an array of plugins (see examples/individually/plugins.js for a dummy plugin example):

let myPlugin = {
  name: 'my-plugin',
  setup(build) {
    // plugin implementation
  },
};

// default export should be an array of plugins
module.exports = [myPlugin];

or a function that accepts serverless instance and returns an array of plugins (see issue #168 for an example):

module.exports = (serverless) => {
  const myPlugin = {
    name: 'my-plugin',
    setup(build) {
      // plugin implementation with `serverless` instance access
      console.log('sls custom options', serverless.service.custom);
    },
  };

  // an array of plugins must be returned
  return [myPlugin];
};

Usage

Automatic compilation

As long as the plugin is properly installed, all regular Serverless operations sls package, sls deploy, sls deploy function, sls invoke local, sls offline will automatically compile using serverless-esbuild.

Specify a custom entrypoint for a function

You can specify a custom entrypoint for ESBuild by specifying the esbuildEntrypoint field in your function definition.

export const myLambdaFunction = {
  handler: '/opt/nodejs/node_modules/my_custom_extension/handler.handler',
  esbuildEntrypoint: './handler.main',
};

Serverless Offline

The plugin integrates very well with serverless-offline to simulate AWS Lambda and AWS API Gateway locally.

Add the plugins to your serverless.yml file and make sure that serverless-esbuild precedes serverless-offline as the order is important:

plugins: ...
  - serverless-esbuild
  ...
  - serverless-offline
  ...

Run serverless offline or serverless offline start to start the Lambda/API simulation.

In comparison to serverless offline, the start command will fire an init and a end lifecycle hook which is needed for serverless-offline and e.g. serverless-dynamodb-local to switch off resources (see below)

Automatic compilation is available while using the plugin with serverless-offline.

custom:
  esbuild:
    watch:
      pattern: ['src/**/*.ts'] # match only typescript files in src directory
      ignore: ['temp/**/*']

Note: When overriding the ignore pattern, remember to ignore .build directory to avoid endless compilation.

Serverless Dynamodb Local

Configure your service the same as mentioned above, but additionally add the serverless-dynamodb-local plugin as follows:

plugins:
  - serverless-esbuild
  - serverless-dynamodb-local
  - serverless-offline

Run serverless offline start.

Invoke Local

This plugin supports the Serverless Invoke Local functionality and will automatically compile the selected function.

External Tools

Contributors

Victor Korzunin
Victor Korzunin

πŸ’¬ πŸ’» πŸ“– πŸ’‘ πŸ€” πŸš‡ 🚧 πŸ”Œ πŸ“† πŸ‘€ ⚠️ πŸ”§
Loup Topalian
Loup Topalian

πŸ’¬ πŸ’» πŸ“– πŸš‡ 🚧 πŸ”Œ
Sam Chung
Sam Chung

πŸ’¬ πŸ’» πŸ“– πŸ’‘ πŸš‡ 🚧 πŸ”Œ πŸ‘€ πŸ”§
Vamsi Dharmavarapu
Vamsi Dharmavarapu

πŸ’» πŸ“– πŸ’‘ πŸš‡ 🚧
Eric
Eric

πŸ’» πŸ€” 🚧 πŸš‡ πŸ‘€
Chris
Chris

πŸ’» πŸ€”
MartΓ­n Acosta
MartΓ­n Acosta

πŸ’»
Tony Tyrrell
Tony Tyrrell

πŸ’»
Matt Jennings
Matt Jennings

πŸ’»
Misha Bruml
Misha Bruml

πŸ’»
François Farge
François Farge

πŸ’»
Sam Hulick
Sam Hulick

πŸ“–
Troy Ready
Troy Ready

πŸ’»
subash adhikari
subash adhikari

πŸ’»
Dan Ionescu
Dan Ionescu

πŸ’»
gurushida
gurushida

πŸ’»
nickygb
nickygb

πŸ’»
Jiri Spac
Jiri Spac

πŸ’»
gavynriebau
gavynriebau

πŸ“–
Adrien Cacciaguerra
Adrien Cacciaguerra

πŸ“–
lulzneko
lulzneko

πŸ’»
AOKI Yuuto
AOKI Yuuto

πŸ’»
Thomas Aribart
Thomas Aribart

πŸ€”
Kory Hutchison
Kory Hutchison

πŸ’» πŸ€”
Chris Hutchinson
Chris Hutchinson

πŸ’»
Fredrik MΓΆllerstrand
Fredrik MΓΆllerstrand

πŸ’»
Sander Kooger
Sander Kooger

πŸ’»
Adam Swift
Adam Swift

πŸ’»
Florian Mayer
Florian Mayer

πŸ’»
Zach Levi
Zach Levi

πŸ’»

Inspired by serverless-plugin-typescript and serverless-webpack